423 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # PoliCTF 2017 Challenge
 | |
| 
 | |
| This is the description displayed on the challenge page:
 | |
| 
 | |
| > We found this executable and we think it must have something in common with the baddies' infrastructure.
 | |
| > We would be glad to understand what **`data`** they are hiding from us...
 | |
| 
 | |
| # How to deploy
 | |
| 
 | |
| The challenge can be deployed by running the `create_files.sh` helper script and by running the `server.elf` behind a proxy (xinetd). The server needs to access the files in the `res/` directory.
 | |
| 
 | |
| # Write-up
 | |
| 
 | |
| The client provided to the partecipants is just the VM running the code `encrypt.pstc` in the `asms/` directory:
 | |
| 
 | |
| ```asm
 | |
| def datastrlen:
 | |
| ###############
 | |
| # r0 = offset of str in data
 | |
| # retval (r0) = strlen
 | |
| ###############
 | |
| push r1
 | |
| push r2
 | |
| push r3
 | |
| movr s2, r0
 | |
| movi s1, 0
 | |
| lodr s0, s2
 | |
| cmpb s0, 0
 | |
| jpei exit
 | |
| loop:
 | |
| movi s2, 0
 | |
| addi s1, 1
 | |
| addr s2, s1
 | |
| lodr s0, s2
 | |
| cmpb s0, 0
 | |
| jpni loop
 | |
| exit:
 | |
| movr r0, s1
 | |
| poop r3
 | |
| poop r2
 | |
| poop r1
 | |
| retn
 | |
| 
 | |
| def round: # round(uint16_t text[2])
 | |
| #################
 | |
| # r0 = offset of text[0] in data
 | |
| # r1 = offset of text[1] in data
 | |
| # r2 = text[0]
 | |
| # r3 = text[1]
 | |
| # retval = void
 | |
| ################
 | |
| push r1
 | |
| push r2
 | |
| push r3
 | |
| lodr r2, r0 # text[0]
 | |
| lodr r3, r1 # text[1]
 | |
| movi s0, 0 # i
 | |
| movi s1, 0 # sum
 | |
| loop:
 | |
| push s0 # saving i
 | |
| addi s1, 0x626f # sum += delta
 | |
| push s1 # saving sum
 | |
| # s0 and s1 will be used as tmps
 | |
| #########
 | |
| # calc v0
 | |
| #########
 | |
| movr s0, r3
 | |
| shli s0, 4
 | |
| addi s0, 0x7065 # s0 = (text[1] << 4) + k0
 | |
| movr s1, r3
 | |
| poop s3 # restoring sum in s3
 | |
| #addr s1, s3 # s1 = text[1] + sum
 | |
| push s3 # saving sum again
 | |
| xorr s0, s1 # s0 = ((text[1] << 4) + k0) ^ (text[1] + sum)
 | |
| push s0
 | |
| movr s0, r3
 | |
| shri s0, 5
 | |
| addi s0, 0x7065 # s0 = (text[1] >> 5) + k1
 | |
| poop s1
 | |
| xorr s0, s1 # s0 = ((text[1] << 4) + k0) ^ (text[1] + sum) ^ ((text[1] >> 5) + k1)
 | |
| addr r2, s0 # r2 += s0
 | |
| #########
 | |
| # calc v1
 | |
| #########
 | |
| movr s0, r2
 | |
| shli s0, 4
 | |
| addi s0, 0x7275 # s0 = (text[0] << 4) + k2
 | |
| movr s1, r2
 | |
| poop s3 # restoring sum in s3
 | |
| #addr s1, s3 # s1 = text[0] + sum
 | |
| push s3 # saving sum again
 | |
| xorr s0, s1 # s0 = ((text[0] << 4) + k2) ^ (text[0] + sum)
 | |
| push s0
 | |
| movr s0, r2
 | |
| shri s0, 5
 | |
| addi s0, 0x6e73 # s0 = (text[0] >> 5) + k3
 | |
| poop s1
 | |
| xorr s0, s1 # s0 = ((text[0] << 4) + k2) ^ (text[0] + sum) ^ ((text[0] >> 5) + k3)
 | |
| addr r3, s0 # r3 += s0
 | |
| ######
 | |
| # end loop
 | |
| #####
 | |
| poop s1 # restoring sum
 | |
| poop s0 # restoring i
 | |
| addi s0, 1
 | |
| cmpb s0, 127 # while (i < 128)
 | |
| jpbi loop
 | |
| # saving the values
 | |
| strr r0, r2
 | |
| strr r1, r3
 | |
| poop r3
 | |
| poop r2
 | |
| poop r1
 | |
| retn
 | |
| 
 | |
| def main:
 | |
| grmn
 | |
| movi r0, 0xadde
 | |
| movi r1, 0x0bb0
 | |
| stri 0, r0
 | |
| stri 2, r1
 | |
| movi r0, 0x0bb0
 | |
| movi r1, 0xcefa
 | |
| stri 0x4, r0
 | |
| stri 0x6, r1
 | |
| movi r0, 0
 | |
| call datastrlen
 | |
| movr r2, r0
 | |
| movi s0, 0
 | |
| encrypt:
 | |
| push s0
 | |
| movi r0, 0
 | |
| movi r1, 2
 | |
| addr r0, s0
 | |
| addr r1, s0
 | |
| call round
 | |
| poop s0
 | |
| addi s0, 4
 | |
| cmpr s0, r2
 | |
| jpbi encrypt
 | |
| lodi r0, 0
 | |
| lodi r1, 2
 | |
| lodi r2, 4
 | |
| lodi r3, 6
 | |
| shit
 | |
| ```
 | |
| 
 | |
| Once the VM bytecode has been reversed, the partecipant had to write a custom assembler to **decrypt the server's VM data section** using the same algorithm shown above. 
 | |
| 
 | |
| An example of a working decryption algorithm is `decrypt.pstc` in the `asms/` directory:
 | |
| 
 | |
| ```asm
 | |
| def datastrlen:
 | |
| ###############
 | |
| # r0 = offset of str in data
 | |
| # retval (r0) = strlen
 | |
| ###############
 | |
| push r1
 | |
| push r2
 | |
| push r3
 | |
| movr s2, r0
 | |
| movi s1, 0
 | |
| lodr s0, s2
 | |
| cmpb s0, 0
 | |
| jpei exit
 | |
| loop:
 | |
| movi s2, 0
 | |
| addi s1, 1
 | |
| addr s2, s1
 | |
| lodr s0, s2
 | |
| cmpb s0, 0
 | |
| jpni loop
 | |
| exit:
 | |
| movr r0, s1
 | |
| poop r3
 | |
| poop r2
 | |
| poop r1
 | |
| retn
 | |
| 
 | |
| def round: # round(uint16_t text[2])
 | |
| #################
 | |
| # r0 = offset of text[0] in data
 | |
| # r1 = offset of text[1] in data
 | |
| # r2 = text[0]
 | |
| # r3 = text[1]
 | |
| # retval = void
 | |
| ################
 | |
| push r1
 | |
| push r2
 | |
| push r3
 | |
| lodr r2, r0 # text[0]
 | |
| lodr r3, r1 # text[1]
 | |
| movi s0, 0 # i
 | |
| movi s1, 0 # sum
 | |
| loop:
 | |
| push s0 # saving i
 | |
| # s0 and s1 will be used as tmps
 | |
| #########
 | |
| # calc v1
 | |
| #########
 | |
| movr s0, r2
 | |
| shli s0, 4
 | |
| addi s0, 0x7275 # s0 = (text[0] << 4) + k2
 | |
| movr s1, r2
 | |
| xorr s0, s1 # s0 = ((text[0] << 4) + k2) ^ text[0]
 | |
| push s0
 | |
| movr s0, r2
 | |
| shri s0, 5
 | |
| addi s0, 0x6e73 # s0 = (text[0] >> 5) + k3
 | |
| poop s1
 | |
| xorr s0, s1 # s0 = ((text[0] << 4) + k2) ^ text[0] ^ ((text[0] >> 5) + k3)
 | |
| subr r3, s0 # r3 -= s0
 | |
| #########
 | |
| # calc v0
 | |
| #########
 | |
| movr s0, r3
 | |
| shli s0, 4
 | |
| addi s0, 0x7065 # s0 = (text[1] << 4) + k0
 | |
| movr s1, r3
 | |
| xorr s0, s1 # s0 = ((text[1] << 4) + k0) ^ text[1]
 | |
| push s0
 | |
| movr s0, r3
 | |
| shri s0, 5
 | |
| addi s0, 0x7065 # s0 = (text[1] >> 5) + k1
 | |
| poop s1
 | |
| xorr s0, s1 # s0 = ((text[1] << 4) + k0) ^ text[1] ^ ((text[1] >> 5) + k1)
 | |
| subr r2, s0 # r2 -= s0
 | |
| ######
 | |
| # end loop
 | |
| #####
 | |
| poop s0 # restoring i
 | |
| addi s0, 1
 | |
| cmpb s0, 127 # while (i < 128)
 | |
| jpbi loop
 | |
| # saving the values
 | |
| strr r0, r2
 | |
| strr r1, r3
 | |
| poop r3
 | |
| poop r2
 | |
| poop r1
 | |
| retn
 | |
| 
 | |
| def main:
 | |
| movi r0, 0
 | |
| call datastrlen
 | |
| movr r2, r0
 | |
| movi s0, 0
 | |
| decrypt:
 | |
| push s0
 | |
| movi r0, 0
 | |
| movi r1, 2
 | |
| addr r0, s0
 | |
| addr r1, s0
 | |
| call round
 | |
| poop s0
 | |
| addi s0, 4
 | |
| cmpr s0, r2
 | |
| jpbi decrypt
 | |
| shit
 | |
| ```
 | |
| 
 | |
| The python wrapper used to solve the challenge, `exploit-test.py`, can be found in the `server/` directory.
 | |
| 
 | |
| ```python
 | |
| from pwn import *
 | |
| import subprocess
 | |
| 
 | |
| key_re = re.compile(".*\"(.*)\".*")
 | |
| r = remote("pasticciotto.chall.polictf.it", 31337)
 | |
| 
 | |
| first = r.recv()
 | |
| key = key_re.match(first).group(1)
 | |
| print("Using key: {}".format(key))
 | |
| subprocess.check_call(["python3", "../../assembler/assembler.py", "{}".format(key), "../asms/decrypt.pstc", "./out.pasticciotto"])
 | |
| with open("./out.pasticciotto") as f:
 | |
|     data = f.read()
 | |
| r.send("{}\n".format(len(data)))
 | |
| print(r.recv())
 | |
| r.send("{}\n".format(data))
 | |
| print(r.recv(100000))
 | |
| ```
 | |
| 
 | |
| ## Challenge output
 | |
| 
 | |
| ```
 | |
| $ python ./exploit-test.py
 | |
| [+] Opening connection to pasticciotto.chall.polictf.it on port 31337: Done
 | |
| Using key: 9XM6SvFPvN8qiLi
 | |
| movi : 0x0->0x39
 | |
| movr : 0x1->0x20
 | |
| lodi : 0x2->0x9a
 | |
| lodr : 0x3->0x1d
 | |
| stri : 0x4->0xa9
 | |
| strr : 0x5->0xd2
 | |
| addi : 0x6->0x38
 | |
| addr : 0x7->0x8f
 | |
| subi : 0x8->0xd
 | |
| subr : 0x9->0x64
 | |
| andb : 0xa->0xa6
 | |
| andw : 0xb->0x22
 | |
| andr : 0xc->0x97
 | |
| yorb : 0xd->0xda
 | |
| yorw : 0xe->0x51
 | |
| yorr : 0xf->0x48
 | |
| xorb : 0x10->0x12
 | |
| xorw : 0x11->0x70
 | |
| xorr : 0x12->0xb6
 | |
| notr : 0x13->0x37
 | |
| muli : 0x14->0xa5
 | |
| mulr : 0x15->0xc
 | |
| divi : 0x16->0xd5
 | |
| divr : 0x17->0xf4
 | |
| shli : 0x18->0xdc
 | |
| shlr : 0x19->0xc3
 | |
| shri : 0x1a->0x6e
 | |
| shrr : 0x1b->0xb5
 | |
| push : 0x1c->0xe1
 | |
| poop : 0x1d->0x88
 | |
| cmpb : 0x1e->0x2c
 | |
| cmpw : 0x1f->0x3a
 | |
| cmpr : 0x20->0x35
 | |
| jmpi : 0x21->0xbb
 | |
| jmpr : 0x22->0x52
 | |
| jpai : 0x23->0x4f
 | |
| jpar : 0x24->0x90
 | |
| jpbi : 0x25->0xd4
 | |
| jpbr : 0x26->0x11
 | |
| jpei : 0x27->0xe5
 | |
| jper : 0x28->0x45
 | |
| jpni : 0x29->0xbc
 | |
| jpnr : 0x2a->0xbe
 | |
| call : 0x2b->0x32
 | |
| retn : 0x2c->0x7e
 | |
| shit : 0x2d->0x6d
 | |
| nope : 0x2e->0x6a
 | |
| grmn : 0x2f->0xe6
 | |
| FUNCTION main
 | |
| 0x0:	movi r0, 0
 | |
| 0x4:	call datastrlen
 | |
| 0x7:	movr r2, r0
 | |
| 0x9:	movi s0, 0
 | |
| 0xd:	push s0
 | |
| 0xf:	movi r0, 0
 | |
| 0x13:	movi r1, 2
 | |
| 0x17:	addr r0, s0
 | |
| 0x19:	addr r1, s0
 | |
| 0x1b:	call round
 | |
| 0x1e:	poop s0
 | |
| 0x20:	addi s0, 4
 | |
| 0x24:	cmpr s0, r2
 | |
| 0x26:	jpbi decrypt
 | |
| 0x29:	shit 
 | |
| FUNCTION round
 | |
| 0x2a:	push r1
 | |
| 0x2c:	push r2
 | |
| 0x2e:	push r3
 | |
| 0x30:	lodr r2, r0
 | |
| 0x32:	lodr r3, r1
 | |
| 0x34:	movi s0, 0
 | |
| 0x38:	movi s1, 0
 | |
| 0x3c:	push s0
 | |
| 0x3e:	movr s0, r2
 | |
| 0x40:	shli s0, 4
 | |
| 0x44:	addi s0, 0x7275
 | |
| 0x48:	movr s1, r2
 | |
| 0x4a:	xorr s0, s1
 | |
| 0x4c:	push s0
 | |
| 0x4e:	movr s0, r2
 | |
| 0x50:	shri s0, 5
 | |
| 0x54:	addi s0, 0x6e73
 | |
| 0x58:	poop s1
 | |
| 0x5a:	xorr s0, s1
 | |
| 0x5c:	subr r3, s0
 | |
| 0x5e:	movr s0, r3
 | |
| 0x60:	shli s0, 4
 | |
| 0x64:	addi s0, 0x7065
 | |
| 0x68:	movr s1, r3
 | |
| 0x6a:	xorr s0, s1
 | |
| 0x6c:	push s0
 | |
| 0x6e:	movr s0, r3
 | |
| 0x70:	shri s0, 5
 | |
| 0x74:	addi s0, 0x7065
 | |
| 0x78:	poop s1
 | |
| 0x7a:	xorr s0, s1
 | |
| 0x7c:	subr r2, s0
 | |
| 0x7e:	poop s0
 | |
| 0x80:	addi s0, 1
 | |
| 0x84:	cmpb s0, 127
 | |
| 0x87:	jpbi loop
 | |
| 0x8a:	strr r0, r2
 | |
| 0x8c:	strr r1, r3
 | |
| 0x8e:	poop r3
 | |
| 0x90:	poop r2
 | |
| 0x92:	poop r1
 | |
| 0x94:	retn 
 | |
| FUNCTION datastrlen
 | |
| 0x95:	push r1
 | |
| 0x97:	push r2
 | |
| 0x99:	push r3
 | |
| 0x9b:	movr s2, r0
 | |
| 0x9d:	movi s1, 0
 | |
| 0xa1:	lodr s0, s2
 | |
| 0xa3:	cmpb s0, 0
 | |
| 0xa6:	jpei exit
 | |
| 0xa9:	movi s2, 0
 | |
| 0xad:	addi s1, 1
 | |
| 0xb1:	addr s2, s1
 | |
| 0xb3:	lodr s0, s2
 | |
| 0xb5:	cmpb s0, 0
 | |
| 0xb8:	jpni loop
 | |
| 0xbb:	movr r0, s1
 | |
| 0xbd:	poop r3
 | |
| 0xbf:	poop r2
 | |
| 0xc1:	poop r1
 | |
| 0xc3:	retn 
 | |
| [main: size 0x2a, offset 0x0, round: size 0x6b, offset 0x2a, datastrlen: size 0x2f, offset 0x95]
 | |
| Go ahead then!
 | |
| 
 | |
| Congratulations!
 | |
| The flag is: flag{m4nc14t1b1_stu_bellu_p4sticci0tt0}
 | |
| 
 | |
| [*] Closed connection to pasticciotto.chall.polictf.it port 31337
 | |
| ``` |