CTF-RE baleful (pin打桩+虚拟机+upx脱壳)

本文部分借鉴文章: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

你可能感兴趣的:(CTF-RE)