本文部分借鉴文章:https://firmianay.gitbooks.io/ctf-all-in-one/src/writeup/6.2.5_re_picoctf2014_baleful#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99
首先查看文件信息
supergate@ubuntu:~/Desktop/task1$ file baleful
baleful: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, stripped
直接在ida中打开,发现内容非常杂乱,猜测有壳,查看一下:
supergate@ubuntu:~/Desktop/task1$ strings baleful | grep -i upx
@UPX!
$Info: This file is packed with the UPX executable packer http://upx.sf.net $
$Id: UPX 3.91 Copyright (C) 1996-2013 the UPX Team. All Rights Reserved. $
UPX!u
UPX!
UPX!
有upx壳,直接解压即可:
supergate@ubuntu:~/Desktop/task1$ upx -d baleful
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2018
UPX 3.95 Markus Oberhumer, Laszlo Molnar & John Reiser Aug 26th 2018
File size Ratio Format Name
-------------------- ------ ----------- -----------
144956 <- 6752 4.66% linux/i386 baleful
Unpacked 1 file.
将所得的文件ida打开,发现重要的函数有如下特点:
分支较多,经分析知道是一个虚拟机。
在看一下虚拟机的内容,发现非常复杂,所以用pin尝试一下
使用32位编译一下pintool
[ManualExamples]$ make obj-ia32/inscount0.so TARGET=ia32
由于我们不知道密码有多少位,因此尝试着看密码长度和比较次数有没有什么关系
$ pin_path=/home/supergate/Desktop/Pin/pin/pin
$ baleful_path=/home/supergate/Desktop/task1/baleful
$ echo "a" |$pin_path -t obj-ia32/inscount0.so -o inscount.out -- $baleful_path
Please enter your password: Sorry, wrong password!
$ cat inscount.outCount
409812
$ echo "aa" |$pin_path -t obj-ia32/inscount0.so -o inscount.out -- $baleful_path
Please enter your password: Sorry, wrong password!
$ cat inscount.outCount
410654
$ echo "aaa" |$pin_path -t obj-ia32/inscount0.so -o inscount.out -- $baleful_path
Please enter your password: Sorry, wrong password!
$ cat inscount.outCount
411496
$ echo "aba" |$pin_path -t obj-ia32/inscount0.so -o inscount.out -- $baleful_path
Please enter your password: Sorry, wrong password!
$ cat inscount.outCount
411496
发现比较次数确实会随输入的长度有规律增长,并且其中改变字符也不会影响比较次数。
因此我们考虑写一个脚本爆破出最终的flag长度。原理就是一直增加flag的长度,直到发现比较次数不变,即该长度为正确flag的长度
import os
def getcnt(flag):
cmd="echo"+" \""+flag+"\" |"+" /home/supergate/Desktop/Pin/pin/pin -t obj-ia32/inscount0.so -o inscount.out -- /home/supergate/Desktop/task1/baleful"
os.system(cmd)
with open("inscount.out") as f:
cnt=int(f.read().split(" ")[1])
return cnt
flag="a"
Last=getcnt(flag)
flag="aa"
cnt=getcnt(flag)
cur=cnt-Last
Last=cnt
for i in range(50):
flag+='a'
cnt=getcnt(flag)
if cnt-Last!=cur:
break
Last=cnt
print len(flag)
运行后得到结果30,即正确flag的长度为30,因此可以继续用pin来暴力解出flag,脚本如下:
import os
def getcnt(flag):
cmd="echo"+" \""+flag+"\" |"+" /home/supergate/Desktop/Pin/pin/pin -t obj-ia32/inscount0.so -o inscount.out -- /home/supergate/Desktop/task1/baleful"
os.system(cmd)
with open("inscount.out") as f:
cnt=int(f.read().split(" ")[1])
return cnt
charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-+*'{}"
flag=list('A'*30)
Last=getcnt("".join(flag))
for i in range(30):
for c in charset:
flag[i]=c
print "".join(flag)
cnt=getcnt("".join(flag))
print cnt
if cnt!=Last:
break
Last=cnt
print "".join(flag)
最终结果:packers_and_vms_and_xors_oh_my