sweetchip's blog



이번에 데프콘 대회는 순천향대 Security First, Leaveret 그리고 저희 동아리인 SSG 연합으로 나가게 되었는데


이상하게도 작년보다 난이도가 더 어려운것 같네요.


문제들을 분석한것도 많고 취약점도 찾았지만 Exploit을 하지 못한 문제가 상당히 많았습니다 ㅠㅠ


이번 포스팅에는 그냥 문제중 한개인 코딩 챌린지를 풀이하도록 하겠습니다. (문제 이름이 기억이 안나서 그냥 코딩 챌린지로 했습니다,)


#!/usr/bin/env python


import subprocess, os, tempfile

from ctypes import *

import os

from socket import *

import time

import struct

# from pyasm import Program

# from pyasm.instructions import push, mov, ret, pop

# from pyasm.registers import eax, esp, ebp

from distorm3 import Decode, Decode16Bits, Decode32Bits, Decode64Bits


p= lambda x: struct.pack("


PAGE_SIZE = 4096


class AssemblerFunction(object):


def __init__(self, code, ret_type, *arg_types):

# Run Nasm

fd, source = tempfile.mkstemp(".S", "assembly", os.getcwd())

os.write(fd, code)

os.close(fd)

target = os.path.splitext(source)[0]

subprocess.check_call(["nasm",source])

os.unlink(source)

binary = file(target,"rb").read()

os.unlink(target)

bin_len = len(binary)


# align our code on page boundary.

self.code_buffer = create_string_buffer(PAGE_SIZE*2 bin_len)

addr = (addressof(self.code_buffer) PAGE_SIZE) & (~(PAGE_SIZE-1))

memmove(addr, binary, bin_len)


# Change memory protection

self.mprotect = cdll.LoadLibrary("libc.so.6").mprotect

mp_ret = self.mprotect(addr, bin_len, 4) # execute only.

if mp_ret: raise OSError("Unable to change memory protection")


self.func = CFUNCTYPE(ret_type, *arg_types)(addr)

self.addr = addr

self.bin_len = bin_len


def __call__(self, *args):

return self.func(*args)


def __del__(self):

# Revert memory protection

if hasattr(self,"mprotect"):

self.mprotect(self.addr, self.bin_len, 3)



def mov(data):

result = []

data = data.split("\n")

for i in data:

if "=" in i:

tmp = i.split('=')

result.append("mov " tmp[0] ", " tmp[1])

return "\n".join(result)


if __name__ == "__main__":

ip = "catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me"

port = 9999


s = socket(AF_INET, SOCK_STREAM)

s.connect((ip, port))


lst = []

inst = s.recv(1024)

# print inst

instructions = s.recv(1024).split("\n")[2]

print instructions

print instructions.encode("hex")


l = Decode(0, instructions, Decode64Bits)

t_ins = ""

for i in l:

t_ins = i[2] "\n"

movs = mov(inst)

# print movs

# print t_ins



result = "****Initial Register State****\n"

result = ""

registers = ["rax","rbx","rcx","rdx","rsi","rdi","r8","r9","r10","r11","r12","r13","r14","r15"]

for i in registers:

add_func = """BITS 64\n""" movs "\n" t_ins.replace("RET\n", "") """mov rax, """ i """

ret

"""

print add_func

Add = AssemblerFunction(add_func, c_uint64, c_uint64, c_uint64)

result = i "=" str(hex(Add(ord(os.urandom(1)), ord(os.urandom(1))))) "\n"


result = result.replace("L", "")

s.send(result)

print result

print s.recv(1024)


"""

rax=0x9c8982fc3b5cfae9

rbx=0x20223acc7e6949cb

rcx=0x3a46c99c

rdx=0xd5239501c5b48bd

rsi=0xbabfac6bbf67bbfd

rdi=0xe8fb6dcfe0000000

r8=0xcde6d06e980dd1ce

r9=0x339f0bb7dee53e3e

r10=0x23a769fd87124021

r11=0x2cb79cbedc86431f

r12=0x4d32ab24658d00be

r13=0x7dab448d20a82708

r14=0x3c8b784c

r15=0x43ccf3fcf39883c6


The flag is: Cats with frickin lazer beamz on top of their heads!

"""


문제는 간단하게 64비트 레지스터와 어셈블리 코드를 바이트코드화 해서 클라이언트에게 보내줍니다.


그러면 저희는 그 정보를 받아서 바이트 코드를 실행하고 레지스터 정보를 다시 되돌려 줘야 하는 문제인데요,


구글링해서 python에서 어셈블리 명령어를 실행하고 실행한 명령어의 결과값을 받아오는 스크립트가 있었습니다.


하지만 보내야 하는 것은 레지스터들 정보들이라서 결과값으로는 부족합니다.


그래서 쓴 간단한 꼼수가 함수의 결과값을 받아오는 스크립트이니 마지막에 mov rax, registers 를 붙여서 모든 레지스터의 값을 리턴하고 그 값을 받아오도록 코딩했습니다.


그래서 한번 실행하면 16개의 레지스터들을 모두 얻어오고 서버로 보내면 키값을 되돌려 줍니다.


그래서 저 스크립트를 실행시키면


The flag is: Cats with frickin lazer beamz on top of their heads!

신고

댓글 0