Background

现在是2023年10月17上午 我在等外卖 很饿有点学不下去,想着写一篇文章记录下我以前出题和经历过的有意思的非预期解,不知道能不能连载下去,随缘更一下

2021CISCN华南分赛区magicchar

先鞭尸我自己,我人生中第一道出给比较大比赛的题

<?php
error_reporting(0);
include'flag.php';
function Magic($str){
  for($i=0; $i<=strlen($str)-1; $i++) {
    if ((ord($str[$i])<32) or (ord($str[$i])>126)) {
      die('sorry');
      exit;
    }
  }
  $blklst = ['[A-VX-Za-z]',' ','\t','\r','\n','\'','""','`','\[','\]','\$','\\','\^','~'];
  foreach ($blklst as $blkitem) {
    if (preg_match('/' . $blkitem . '/m', $str)) {
      die('out');
      exit;
    }
  }
}
if(!isset($_GET['yell'])) {
  show_source(__FILE__);
} else {
  $str = $_GET['yell'];
  Magic($str);
  ob_start();
  $res = eval("echo " . $str . ";");
  $out = ob_get_contents();
  ob_end_clean();
  if ($out === "Wa4nn") {
      echo $flag;
  } else {
    echo htmlspecialchars($out, ENT_QUOTES);
  }
}
?>

可以看到思路是比较简单的 就是给定字符让你拼出一个字符串,那就是写个脚本要么异或要么与运算就可以,但是在某次我翻资料的时候突然发现个奇怪的事情,我的黑名单的正则是被当作字符串拼凑进去的,不清楚当时为什么这么写,再一看发现我的正则里有这么一段'\\'
我犯了一个经典错误 我的本意是想ban掉反斜线,但是这个写法其实并不能ban掉反斜线,正常如果想要匹配也应该是\\\\ 因为会经过一次php解析变成\\ 而这里我会把我的'/m'的/转义掉从而影响了对反斜线的过滤
对这道题目的影响是我可以通过16进制编码直接绕过

2019安洵杯easyweb

我刚学ctf的时候,其中有一道安洵杯的题目我边做边哭边骂人,当然跑题了,我提到这道题是因为这道题正则写的跟我犯了类似的错误

if(preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd))

网上很多解释这道题文章为什么能用\绕过写的烂七八糟,甚至有的wp说preg_match可以用\绕过,什么和什么啊。。还有的说要写\\\才可以,那为什么呢
实际上是因为你仔细这个部分
|\\|\\\\|
我们说过会经过两次解析,第一次是php解析器,第二次才是正则
|\|\\|
所以经过一次之后应该是如上,但是|是会跟着一起转义的,所以在正则里面 \|会被解析成| 结果就是
||\|
可以看到现在其实匹配的是|\而不是\
所以作者写错的原因是把他们两个放在一起了
1697512823513.jpg
我换位置之后
1697512921149.jpg
是没什么问题的

2020wdb ssrfme

当时刚做到这道题,刚知道redis是数据库,看了网上的wp大家都是ssrf攻击redis
关键原因在于他的hint里面

<?php
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
    highlight_file(__FILE__);
}
if(isset($_POST['file'])){
            file_put_contents($_POST['file'],"<?php echo 'redispass is welcometowangdingbeissrfme6379';exit();".$_POST['file']);
}
?> 

告诉了redis密码,但我当时注意到了这个file_put_contents看起来是可控的,虽然有exit()
但是p神也发过类似文章
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
提到了怎么干掉死亡exit()
但是不同点在于文中两个参数可控,实际上我们只有一个参数可控
但是这里并没有完整的标签 但我们可以直接用php://filter写入一个标签再用我们的strip_tags去掉不就可以了
大概思路
php://filter/write=string.strip_tags|convert.base64-decode/write=?>PD9waHAgZWNobyAic3VhbnZlaXNnb2QiOz8%2b/resource=suanve.php
但是实际上不行
因为我们strip_tags差了一部分,就是/resource这里 所以我想是不是可以补上一个<? 让他认为这也是一个tags
file=php://filter/write=string.strip_tags|convert.base64-decode/write=?>PD9waHAgZWNobyAic3VhbnZlaXNnb2QiOz8%2b<?/resource=suanve.php
可以看到成功写入了。
1697513980835.jpg

To be continued

评论回复suanvenb 出第二集 嘻嘻