Thứ Ba, 20 tháng 9, 2016

[writeup][CSAW16][pwn200] Tutorial


Lần đầu làm giải CSAW này. Chỉ solve được vài bài, pwn thì chỉ làm đc warmup với tutorial. Bài warmup dễ nên nên lười viết. Bài này khó (so với noob như mình) nên viết, để năm sau có khá hơn đọc lại còn có cái mà tự cười vào mặt ...

File :https://drive.google.com/drive/folders/0B-QPcxnExPUcbmZ2cXBKcFVVQjQ?usp=sharing

Kiểm tra file









Hàm main thì chủ yếu là phần kết nối với socket này nọ, không liên quan đến ctrinh chính và được setup ở trên server sẵn nên mình không tập trung vào đây.
Sau khi kết nối xong này nọ, nó sẽ gọi hàm menu

















Hàm này sẽ cho ta truyền vào một số. Nếu số 1 thì gọi func1, số 2 gọi func2, số 3 thì exit. Trong đây không có lỗi gì nên sẽ xem tiếp func1...













Hàm func1 cũng không có lỗi gì. Tuy nhiên, ta có thể chú ý đến hàm dlsym. Sau khi lấy địa chỉ của hàm puts trong, nó sẽ trừ đi 1280 sau đó in ra. Qua cái này ta có thể leak được địa chỉ của puts. sau đó thông qua libc đề cho tính đc base libc.


Xem tiếp hàm func2...











Nhìn qua cũng thấy chỗ này là có lỗi rồi . Stack của hàm có 0x144=324bytes tuy nhiên hàm read lại cho phép đọc 460 bytes. Ngoài ra hàm write còn in ra 324 bytes từ s. Mà từ s đến v3 khoảng cách là 0x140-0x8 = 312. Vậy nó sẽ in ra cả v3, nhưng thiếu 2 bytes cuối. Sau quá trình debug thì ta thấy 2 bytes cuối là 0 nên ta sẽ thêm vào sau. Như vậy là ta sẽ leak đc v3 và bypass stack cookies.

Như vậy có thể hình dung được stack của func2 như sau :

rbp + 0x8:  ret (3)
...
rbp - 0x8: v3 (2)
...
...
rbp - 0x140: s (1)

Vậy cách làm là sẽ overflow buffer(s) sau đó ghi cookie (v3) vào đúng vị trí và ghi đè ret để chạy system("/bin/sh")
(1)  ---> (2) Ta overflow s
Tại (2) ta sẽ đè giá trị ban đầu của v3 mà đã leak đc
(3) ---> ghi đè system và /bin/sh.
Từ cái leak puts của func1. Ta tính toán các offset của system và /bin/sh trong libc đã cho :
base = puts - 0x06fd60 +1280
system=0x046590+base
binsh=0x17c8c3+base
Bên cạnh đúng cũng tìm ropgadget để có thể truyền arg cho system

$ ROPgadget --binary tutorial | grep "pop rdi"
0x00000000004012e3 : pop rdi ; ret

payload sẽ là

pl+='A'*312
pl+=p64(cookie)
pl+='\x90'*8
pl+=p64(pop_rdi)
pl+=p64(binsh)
pl+=p64(system)

Tuy nhiên cái này chạy trên server thì được, nhưng chạy trên client thì k đc. Thế nên mình dùng dup2 (Cái này nhờ anh phieulang mới biết). Ta sẽ dùng 2 hàm dup2(4,0) + dup2(4,1). Và cũng tính toán offset lấy hàm dup2 từ libc.
Tìm thêm 1 ropgadget nữa để truyền arg cho 2 hàm

$ ROPgadget --binary tutorial | grep "pop rsi"
0x00000000004012e1 : pop rsi ; pop r15 ; ret

code exploit : http://bugs.vn/4995

















Lần đầu thì bao giờ cũng sung sướng nhất :)). Cảm ơn anh phieulang và lacloi đã giúp em bài này :D.
GLHF!







Thứ Hai, 5 tháng 9, 2016

[writeup][TWCTF][pwn50] Judgement


Ban đầu sẽ kiểm tra file 


Bật IDA xem qua pseudo code xem sao :
printf(&format); Để ý dòng này thì chắc chắn đây là lỗi format string. 


NX được bật nên k thể chèn shellcode vào được.

Thử debug bằng peda thì thấy địa chỉ của Flag là ở 0x0804a0a0. Nhưng so với đầu stack thì khá xa nên không thể quét. Vậy còn cách Direct parameter access. 
Sau một hồi tính toán, thử nghiệm thì đã tìm đc thứ tự của flag là 45th. Rồi, h thì lấy flag rồi submit thôi.


[writeup][TWCTF][ppc50] Make a Palindrome!


Đề đại khái là nó cho 1 chuỗi gồm các str ngăn bởi space. Giờ phải sắp xếp sao cho  chuỗi đó thành chuỗi palindrome ( có nghĩa là xuôi ngược đều như nhau ) mà vẫn giữ nguyên dấu cách. 
Time limit 3m
Có 30 test cases. Flag sẽ nằm ở case 1 và case 30.
Hiểu đề rồi thì code thôi.
Đề file 7z của nó gồm có 2 cái example của python và perl. Mình code python nên sẽ up python 
# -*- coding:utf-8 -*-
# Server connection example file for Python 2
import socket
import sys

host = 'ppc1.chal.ctf.westerns.tokyo'
if len(sys.argv) > 1:
    host = sys.argv[1]
port = 31111
if len(sys.argv) > 2:
    host = int(sys.argv[2])

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

client_file = client.makefile('b')

while client_file.readline().strip() != "Let's play!":
    pass

client_file.readline()
for case in range(0, 30):
    client_file.readline()
    words = client_file.readline().split()[2:]
    # words: input
    # answer: answer
    ##  Please write some code here
    answer = words
    #
    client_file.write(' '.join(answer) + "\n")
    client_file.flush()
    ret = client_file.readline()[8:-1]
    print(ret)
    if 'Wrong Answer' in ret:
        print(client_file.readline())
        sys.exit(1)



Thuật toán của mình cũng khá đơn giản.  Mình sẽ dùng permutations để tạo ra các hoán vị từ dữ liệu đã cho. Sau đó kiểm tra bằng hàm ispalindrome. Hàm này chỉ đảo ngược chuỗi lại và so sánh với chuỗi ban đầu . Code :

# -*- coding:utf-8 -*-
# Server connection example file for Python 2
import socket
import sys
import itertools
def ispalindrome(word):
    return word == word[::-1]
def palindrome(w):
    for x in list(itertools.permutations(w,len(w))):
        t=''.join(x)
        if ispalindrome(t):
            return x 
host = 'ppc1.chal.ctf.westerns.tokyo'
if len(sys.argv) > 1:
    host = sys.argv[1]
port = 31111
if len(sys.argv) > 2:
    host = int(sys.argv[2])

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

client_file = client.makefile('b')

while client_file.readline().strip() != "Let's play!":
    pass

client_file.readline()
for case in range(0, 30):
    client_file.readline()
    words = client_file.readline().split()[2:]
    # words: input
    # answer: answer
    ##  Please write some code here
    answer = palindrome(words)
    #
    client_file.write(' '.join(answer) + "\n")
    client_file.flush()
    ret = client_file.readline()[8:-1]
    print(ret)
    if 'Wrong Answer' in ret:
        print(client_file.readline())
        sys.exit(1)
Run : 

Thứ Sáu, 2 tháng 9, 2016

[write-up][ADCTF2014] crypto day 8 ROTATE

file http://adctf2014.katsudon.org/dat/bvvpSQFmYqKQLhEp/rotate.zip
extract thì có 2 file. 1 file là encypt hình và một file là flag.jpg.enc

import sys
import math
import struct

p = lambda x: struct.pack('f', x)
u = lambda x: struct.unpack('b', x)[0]

if len(sys.argv) != 3:
    sys.exit(1)

filename = sys.argv[1]
key = math.radians(int(sys.argv[2]))

bs = open(filename, 'rb').read()
enc = open(filename + '.enc', 'wb')

for i in range(0, len(bs), 2):
    x, y = u(bs[i]), u(bs[i+1])
    enc.write(p(x * math.cos(key) - y * math.sin(key)) + p(x * math.sin(key) + y * math.cos(key)))



Program này hoạt động như sau :
 - Ta truyền vào 2 argv ban đầu là tên file cần encrypt, thứ 2 là key. Key ở đây là một số. Do có đoạn 
"key = math.radians(int(sys.argv[2]))"
nên key chỉ nằm ở khoảng 0 - 360 . Sau đó sẽ đọc từng char xong file hình là encrypt theo công thức.
Sau khi hiểu cách hoạt động của program, mình bắt đầu vào viết code. Vì là code decrypt nên sẽ tiếp cận theo cách bottom-up.
Sau khi thử encrypt một file bình thường thì mình thấy sau khi encrypt thì từ 1 char ban đầu sẽ tăng lên 4 char, thì thế mình sẽ tách một đoạn 8 kí tự ra làm 2 phần. Sau đó giải pt tìm x và y. Rồi tiếp tục pack char đó lại về thành bs[i] và bs[i+1]. Sau khi decrypt, ta cần phải kiểm tra xem phải file hình không. Ban đầu mình kiểm tra header là ffd8ffe000 tuy nhiên k có file nào hợp lệ. Vì vậy đã giảm xuống ffd8ff. Tuy vậy nhưng vẫn decrypt được file như bình thường. 
Đây là code decrypt :
import sys
import math
import struct

z = lambda x: struct.unpack('f', x)[0]
t = lambda x: struct.pack('b', int(round(x)))


def cp(x): #check if x can pack with func t()
    if int(round(x))>127:
        return 0 
    elif int(round(x))<-128:
        return 0
    else:
        return 1


def decode(filee,key):
    de=''
    key=math.radians(int(key))
    sx=math.sin(key)
    cx=math.cos(key)
    for i in range(0,len(filee),8):
        a=z(filee[i:i+4]) 
        b=z(filee[i+4:i+8])
        y=((b*cx-a*sx)) 
        x=(a+y*sx)/cx
        if cp(x)==0 or cp(y)==0 :
            return 0
        xx=t(x)
        yy=t(y)
        de+=xx+yy
    if de.encode('hex')[:6]=='ffd8ff':
        return de
    else:
        return 0
def solve(filename):
    filee=open(filename,'rb').read()
    dc=open(filename + '.jpg','wb')
    for i in range(360): 
        if i!=0 and i!=90 and i!=270:
            if decode(filee,i)!=0 :
                print i
                dc.write(decode(filee,i))
solve(sys.argv[1])