Fork me on GitHub

InForSec夏令营-2018-二进制训练营总结

这次训练营的内容主要是逆向的入门和pwn的shellcode的编写,个人感觉逆向没讲什么东西,pwn的话shellcode还是不会写hh,这里总结一下期间写的逆向的题目.

0x00 level0-明文比较

方法一:ida得到伪代码把flag直接拿出来

深度截图20180726205418

方法二:ltrace命令

1
ltrace ./level0

综上得到flag{welc0me_to_inforsec}

0x01 level1-类base64

题目流程大致就是输入一串字符,经过sub_400750函数后与字符串ZmxhZ3tiNHNlNjRXafNXczFtcGxlXQ==比较.对ctf打的比较多的人一看就猜是base64,但具体是不是呢,我把这串字符用原版的base64解码之后得到

flag{b4se64Wi\xf3Ws1mple]

其中有不可见字符,并且结尾也不对,于是看了看sub_400750函数,把模板提出来

ABCDEFGHIJKLMNOPQRSTUVWfYZabcdeXghijklmnopqrstuvwxyz0123456789+/

以此进行base64解码即可

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
28
__Auther__ = 'L1B0' 

from z3 import *
from libnum import s2n,n2s
from itertools import permutations
from ctypes import c_int32

table = '''ABCDEFGHIJKLMNOPQRSTUVWfYZabcdeXghijklmnopqrstuvwxyz0123456789+/\x00'''

def decodeBase64(src):
delPaddingTail = {0: 0, 2: 4, 1: 2}
value = ''
n = src.count('=')
sin = src[:len(src) - n]
for c in sin:
value += bin(table.find(c))[2:].zfill(6)
value = value[:len(value) - delPaddingTail[n]]
# print value
middle = []
for i in range(8, len(value) + 1, 8):
middle.append(int(value[i-8:i], 2))
output = middle
out = hex(s2n(''.join(map(chr, output))))[2: -1]
# print out
return out

crypto = 'ZmxhZ3tiNHNlNjRXafNXczFtcGxlXQ'
print n2s(0x666c61677b6234736536345f69735f73316d706c657d)

flag{b4se64_is_s1mple}

0x02 level2-2017国赛数独

待补充

0x03 level3-md5爆破

题目大致流程是输入一个长度为16的数字,并且均分成四段,每段的大小均比前一段大,且每一段都大于999.然后每一段会经过sub_40083C函数的处理得到其md5,最后要符合sub400bbe函数的验证.

题目的主要难度在于你在伪代码中看不出sub_40083C函数的作用(赛棍除外),我的解决方法是用gdb跟一下,将得到的结果和自己猜测的结果对比验证.

sub_40083C函数

一开始我并不知道sub_40083C函数是干什么的...当我点进去后看到下面这串数后感觉和md5算法的数很像,百度一发发现就是md5的数.

v6 = 1732584193;

v7 = -271733879;

v8 = -1732584194;

v9 = 271733878;

接着我用gdb验证了我的想法

1
2
3
gdb level3
b *0x400f4a
r 1234123512361237
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
*RAX  0x0
RBX 0x0
RCX 0x0
*RDX 0x55
*RDI 0x55d03e31
*RSI 0x7fffffffcb9c ◂— 0x155d03e31
*R8 0x603090 ◂— 0x0
*R9 0x0
*R10 0x8ba
*R11 0x7ffff7ab54e0 (free) ◂— mov rax, qword ptr [rip + 0x31da11]
R12 0x4006b0 ◂— xor ebp, ebp
R13 0x7fffffffccc0 ◂— 0x2
R14 0x0
R15 0x0
RBP 0x7fffffffcbe0 —▸ 0x401100 ◂— push r15
RSP 0x7fffffffcb40 —▸ 0x7fffffffccc8 —▸ 0x7fffffffcfbd ◂— 0x696c2f656d6f682f ('/home/li')
*RIP 0x400f5f ◂— lea rdx, [rbp - 0x40]
───────────────────────────────────────[ DISASM ]───────────────────────────────────────
0x400f4a lea rdx, [rbp - 0x50]
0x400f4e mov rax, qword ptr [rbp - 0x78]
0x400f52 mov esi, 4
0x400f57 mov rdi, rax
0x400f5a call 0x40083c

可以看到,字符串1234经过sub_40083C后,结果存在rdi上,rdi=0x55d03e31,而’1234’的md5值为81dc9bdb52d04dc20036dbd8313ed055,基本确定是md5算法.

sub400BBE函数

这个函数当时我主要疑惑的是a2和a2[1]取得到底是md5值的哪个位置,经过gdb跟一波可以很容易发现*a2和a2[1]取的是md5的前两个byte,比如说’1234’的md5是81dc9bdb52d04dc20036dbd8313ed055,那么*a2=0x81,a2[1]=0xdc.

那么接下来就可以根据sub_400bbe的条件限制爆破出符合的数.

exp如下

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/python
# -*- coding: utf-8 -*-
__Author__ = "L1B0@10.0.0.55"

import hashlib
from string import printable

def check(a,b):
s = [0,0,0,0]

x = int(b[:2],16)
y= int(b[2:4],16)
if a == '1234':
print x,y
v7 = [(x&0xf)+48,(x>>4) + 48,(y&0xf) + 48,(y>>4) + 48]#优先级问题
if a=='1234':
print v7
for i in range(4):
for j in range(4):
if( s[j]==0 and v7[j] == ord(a[i]) ):
s[j] = 1
break

for k in range(4):
if s[k] == 0:
return 0
return 1

my_flag = ''
for a in range(10):
for b in range(10):
for c in range(10):
for d in range(10):
#flag = a+b+c+d
flag = str(a)+str(b)+str(c)+str(d)
md5_flag = hashlib.md5()
md5_flag.update(flag.encode(encoding='utf-8'))
#if flag == '0640':
#print md5_flag.hexdigest()
if check(flag,md5_flag.hexdigest()) == 1:
print flag
my_flag += flag
print my_flag

正确输入:3179679093279624

CTF{Md5_i3_ea5y}

0x04 level4-gdb跟踪

题目用ida看了一下发现贼奇怪,call rax导致不能f5,经中矿的一位师傅提示用gdb跟踪.

gdb infosec_level4

b *(main+178)

r

s#单步步入

n

s

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
28
 RAX  0x7fffffffcb90 ◂— 0xc180c931485e2beb
RBX 0x0
*RCX 0x22
RDX 0x7fffffffcce8 —▸ 0x7fffffffd002 ◂— 0x5f52455454554c43 ('CLUTTER_')
RDI 0x1
RSI 0x7fffffffcbc2 ◂— 0x1e230f670d0b060c
R8 0x400620 (__libc_csu_fini) ◂— ret
R9 0x7ffff7de8cb0 (_dl_fini) ◂— push rbp
R10 0x848
R11 0x7ffff7a5a1c0 (__libc_start_main) ◂— push r14
R12 0x4003c0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffccd0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffcbf0 —▸ 0x400590 (__libc_csu_init) ◂— mov qword ptr [rsp - 0x28], rbp
RSP 0x7fffffffcb78 —▸ 0x400580 (main+180) ◂— mov eax, 0
*RIP 0x7fffffffcb99 ◂— 0xf8e2c6ff48133680
───────────────────────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────────────────────────
0x7fffffffcb92 pop rsi
0x7fffffffcb93 xor rcx, rcx
0x7fffffffcb96 add cl, 0x22
► 0x7fffffffcb99 xor byte ptr [rsi], 0x13
0x7fffffffcb9c inc rsi
0x7fffffffcb9f loop 0x7fffffffcb99

► 0x7fffffffcb99 xor byte ptr [rsi], 0x13
0x7fffffffcb9c inc rsi
0x7fffffffcb9f loop 0x7fffffffcb99

发现一直在进行异或操作,根据题目correct the byte提示,把异或的那串数据提出来进行爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/python
# -*- coding: utf-8 -*-
__Author__ = "L1B0@10.0.0.55"

flag_len = 0x22
flag = [0x0c,0x06,0x0b,0x0d,0x67,0x0f,0x23,0x1e,0x07,0x30,0x3f,0x20,0x05,0x3a,0x04,0x3d,0x13,0x09,0x2f,0x2f,0x38,0x3c,0x1b,0x07,0x0c,0x25,
0x2e,0x7a,0x22,0x27,0x10,0x02,0x09,0x0a]
print len(flag)==flag_len

for i in range(0,255):
b = [chr((i^j)&0xff) for j in flag]
b = ''.join(b)
print b
if 'ctf' in b:
print b

FLAG-EiTMzujOpNwYCeervQMFod0hmZHC@

交上去不对..发现长度为0x22包括了个\n,把@删了就对了.