首页
社区
课程
招聘
[原创]2018看雪CTF第十五题WP
2018-7-15 13:23 3721

[原创]2018看雪CTF第十五题WP

2018-7-15 13:23
3721

试运行程序

解压题目附件压缩包。内有4个文件:
1、zImage(arm的linux内核)
2、vexpress-v2p-ca9.dtb(设备树)
3、ReadMe.txt(题目说明)
4、a9rootfs(根文件系统)
(实际上前3个文件只是提供运行环境,需要逆向的是a9rootfs)

 

ReadMe.txt中的内容:

操作系统:ubuntu 16.04 32位;
软件:qemu-system-arm 2.5.0/2.10.0版本均测试过(sudo apt-get install qemu-system-arm安装即可),pediy_ctf_2018.tar.gz压缩包内的三个文件;
Uboot的目标板:vexpress-a9;
Uboot的内存:128M、256M、512M均可;
将压缩包pediy_ctf_2018.tar.gz解压到目录下,在解压后的目录中执行uboot引导命令(二选一即可)
Qemu uboot引导命令1:qemu-system-arm -M vexpress-a9 -m 128M -dtb vexpress-v2p-ca9.dtb -kernel zImage -append "root=/dev/mmcblk0 rw" -sd a9rootfs (有图形化界面)
Qemu uboot引导命令2:qemu-system-arm -M vexpress-a9 -m 128M -dtb vexpress-v2p-ca9.dtb -kernel zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd a9rootfs (无图形化界面)

为了便于用IDA调试,我没有选择说明文件中建议的Ubuntu而是Windows。
命令行输入:

λ qemu-system-arm -M vexpress-a9 -m 128M -dtb vexpress-v2p-ca9.dtb -kernel zImage -append "root=/dev/mmcblk0 rw" -sd a9rootfs

弹出qemu界面:
设备要求输入key,输入错误则在此处一直循环

提取ELF

1、根据提示信息,用010Editor在3个binary中搜索字符串'please input your key'。对应的文件是a9rootfs。
2、尝试用IDA打开a9rootfs,IDA只能识别为2进制文件。
3、file命令识别文件格式,为ext3格式

abc@ubuntu64:~/Desktop$ file a9rootfs 
a9rootfs: Linux rev 1.0 ext3 filesystem data, UUID=d8a4bf4a-95c3-4cba-9893-827cd9e120fd (needs journal recovery) (large files)

4、用Explore2fs提取文件系统中的文件

 

5、在sh文件中搜索到了目的字符串'please input...',且sh为ELF格式。

逆向分析

sh文件运行时,系统还没初始化完成,故所使用的库均为静态链接的。(可能说的不对),没有导入表,没有符号,也没有got和plt。静态分析只能靠经验去'猜'。
比如start中:

EXPORT start
MOV     R11, #0
MOV     LR, #0
LDR     R1, [SP+arg_0],#4
MOV     R2, SP
STR     R2, [SP,#-4+arg_0]!
STR     R0, [SP,#var_4]!
LDR     R12, =sub_11F8C
STR     R12, [SP,#4+var_8]!
LDR     R0, =sub_11374
LDR     R3, =sub_11EF0
BL      sub_1179C
start

根据对ELF的经验猜测,sub_1179c为libc_start_main,而传递给该函数的第一个参数(LDR R0,sub_11374),就是main函数。

 

main函数中可以看到对printf("please input your key")的循环调用:

loc_113B0
LDR     R0, =aPleaseInputYou ; "please input your key:"
BL      printf

跳出循环的关键判断:

SUB     R3, R11, #-input
SUB     R3, R3, #4
SUB     R3, R3, #4
MOV     R1, R3
LDR     R0, =a100s      ; "%100s"
BL      scanf
SUB     R3, R11, #-input
SUB     R3, R3, #4
SUB     R3, R3, #4
MOV     R0, R3
BL      strlen__
MOV     R3, R0
STR     R3, [R11,#len]
SUB     R1, R11, #-out1
SUB     R3, R11, #-input
SUB     R3, R3, #4
SUB     R3, R3, #4
LDR     R2, [R11,#len]
MOV     R0, R3
BL      t1
SUB     R1, R11, #-out2
SUB     R1, R1, #4
SUB     R1, R1, #4
SUB     R3, R11, #-input
SUB     R3, R3, #4
SUB     R3, R3, #4
LDR     R2, [R11,#len]
MOV     R0, R3
BL      t2
SUB     R1, R11, #-out3
SUB     R3, R11, #-out2
SUB     R3, R3, #4
SUB     R3, R3, #4
LDR     R2, [R11,#len]
MOV     R0, R3
BL      t3
SUB     R3, R11, #-out3
LDR     R1, =aC1371da51a9030 ; "C1371DA51A9030079E21DCDC5B78E3856387213"...
MOV     R0, R3
BL      strcmp
MOV     R3, R0
CMP     R3, #0
BNE     loc_11648

输入的key经过t2和t3两次变换,和'C1371DA51A9030079E21DCDC5B78E38563872139C13F6F'比较,相等则成功。
t2变换中:

  memcpy(out, (int)in, v4, v4);
  a1((int)out_1, (int)temp, v4);
  b1((int)out_1, (int)temp, v4);
  c((int)out_1, v4);
  a2((int)out_1, (int)temp, v4);
  b2((int)out_1, (int)temp, v4);
  c((int)out_1, v4);
  a1((int)out_1, (int)temp, v4);
  b2((int)out_1, (int)temp, v4);
  c((int)out_1, v4);
  a2((int)out_1, (int)temp, v4);
  b1((int)out_1, (int)temp, v4);
  c((int)out_1, v4);

a1和a2算法一致(函数内部的字符串常量不同),b1、b2算法一致,且a和b互为逆运算。(很简单的字符串变换)
c将输入每字节异或并首尾互换。
abc函数均可求逆。
t3其实也是a函数。

求key代码

def r1(input,s):
    r = ''
    for i in range(len(input)//2):
        a = s.find(input[2*i])
        b = s.find(input[2*i+1])
        r += chr(a*16+b)
    return r

def r2(input,s):
    r = ''
    for i in range(len(input)):
        a = ord(input[i])//16
        b = ord(input[i])%16
        r += s[a] + s[b]
    return r

def r3(input):
    l = [ord(input[0])]*len(input)
    for i in range(1,len(input)):
        a = ord(input[i])
        for j in range(i):
            a = a^l[j]
        l[i] = a
    for i in range(len(input)//2):
        l[i], l[len(input)-i-1] = l[len(input)-i-1],l[i]

    r = ''
    for i in range(len(input)):
        r += chr(l[i])

    return r

s1 = 'FDB08642ECA97531'
s2 = '13579BDF02468ACE'
s3 = '0369CF258BE147AD'
s4 = 'FA50B61C72D83E94'
s5 = 'FDB08642ECA97531'
s6 = 'FA50B61C72D83E94'
s7 = '0369CF258BE147AD'
s8 = '13579BDF02468ACE'
expected = 'C1371DA51A9030079E21DCDC5B78E38563872139C13F6F'

a = r1(expected,'0123456789ABCDEF')
a = r3(a)
a = r2(a,s8)
a = r1(a,s7)
a = r3(a)
a = r2(a,s6)
a = r1(a,s5)
a = r3(a)
a = r2(a,s4)
a = r1(a,s3)
a = r3(a)
a = r2(a,s2)
a = r1(a,s1)

print(a)

得到Key是2018ctf0520pediy1314yyp

 

输进qemu,得到:

 

拿到flag之后还有一次exploit的机会?估计这题最初设计是个pwn吧。


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2018-7-15 14:28 被mratlatsn编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回