PwnCollege - Fundamentals - ProgramMisuse
PwnCollege - Fundamentals -ProgramMisuse
Using The Dojo - the welcome module
访问靶机的三种方式:在Workspace的Vscode中打开终端、在Desktop中操作靶机桌面以及通过ssh连接至靶机。另外,靶机的/home/hacker目录是持久化的,也就是说每次开启新的挑战,/home/hacker目录不会被重置。
靶机分为两种模式:challenge和practice,在practice模式中有可调试的解决方案,但是flag是假flag。
ssh连接步骤:
1.运行ssh-keygen -f key -N ''
命令,这会在当前目录下生成key和key.pub文件,分别是公钥和私钥。
2.cat key.pub
打印key.pub文件内容。
3.将打印出的内容复制粘贴到Settings->SSH Key中。
4.ssh -i key hacker@dojo.pwn.college
连接至靶机
Desktop中的复制粘贴:
打开剪切板,在网页虚拟机中选中的文字会直接被写入剪切板中,可以从剪切板中复制文字到本机;同理,要把外部的内容复制到虚拟机中只需将要复制的文字从本机复制到剪切板中,再在网页虚拟机中粘贴。
Fundamentals - Program Misuse
程序交互:Linux 命令行
文件类型、文件查看、软连接和硬链接、inode
程序滥用:权限提升 - linux权限模型
(1)用户和组信息
用户和组分别用 UID
和 GID
表示,一个用户可以同时属于多个组,默认每个用户必属于一个与之 UID 同值同名的 GID。
通过id
命令可以查看用户的UID和GID。
系统保存用户信息的文件是 /etc/passwd
,保存组信息的文件是 /etc/group
,保存密码口令及其变动信息的文件是 /etc/shadow
。
(2)文件权限控制
文件的权限分为三组:U(所有者, Owner), G(用户组, Group), O(其他, Other),而每组又由三个权限位构成,分别为r(读权限), w(写权限), x(可执行权限)。
通过 ls -l
可以查看到其文件类型及权限,通过 chmod
修改权限,通过 chown
改变文件或目录的所属用户,通过 chgrp
改变文件或目录的所属组。
虽然显示linux权限位是9位,但事实上linux权限位有12位,除了上述的9位外还有SUID,SGID和sticky位,其位置如下:
S G T r w x r w x r w x
例如- rws r-x r--
对应的12位权限位的数值为100 111 101 100
SUID(set user id)和SGID(set group id):
可通过chmod u+s
和chmod g+s
设置,只有具有对应可执行权限的可执行程序能够设置SUID和SGID,设置后x变为s。当对一个不具备 x 权限的文件设置 s 权限时无效,权限变为大写 S,表明 s 权限未生效。该类文件被执行后进程的有效id为文件拥有者/组的id,而正常可执行文件执行后进程的有效id为执行者的用户/组id。
Strick(粘滞位):
一般对目录针对 others 设置,设置后在目录中只有属主和 root 有删除文件的权限,即用户只能删除自己为属主的文件(多用于共享目录中)。可通过chmod +t
和chmod -t
设置和删除,设置后others的x位显示为t,只有others有可执行权限的文件设置该位才有效(具有写和执行权限才能在目录下进行文件创建删除等操作),others没有可执行权限的文件设置后其others的x位显示为T。
(3)进程权限控制
进程的id称为进程凭证,包括了真实用户id(read user id,ruid)和真实组id(read group id,rgid),有效用户id(effective user id,euid)和有效组id(effective group id,egid),设置用户id(saved set user id)和设置组id(saved set group id),文件系统用户id(fsuid)和文件系统组id(fsgid),辅助组id(Supplementary Group ID)。
注意:saved set-user-id是进程id,而set-user-id(suid)是文件的特殊权限,group id同理
ruid
和rgid
标识了该进程属于哪一个用户(哪一个组)。子进程的真实id继承自创建它的父进程,shell进程的真实id会在用户登陆时被login进程使用setuid等函数设置为用户的uid和gid。euid
和egid
用于决定进程对系统资源的访问权限(除了文件访问),操作系统对访问权限的验证依据的是有效id而不是真实id(但进程间signal发送会检查真实id或有效id是否匹配)。有效id为0的特权进程拥有所有权限(root)。一般进程的euid和egid复制自ruid和rgid,由具有suid和sgid的可执行文件生成的进程的euid和egid复制自可执行文件的所属用户id和所属组id。saved set user id
和saved set group id
。在进程被创建时直接复制自euid和egid,其作用是:存在真实id为非root,原始有效id为root的情况,保存原始有效id以便进程可以通过setuid使得有效id在真实id和原始有效id(root)之间切换。可以看下图中的例子,来源。
fsuid
和fsgid
。这两个ID是linux特有的,传统unix并没有这些ID。对于传统的unix,访问文件、发送signal,打开IPC的object等等的权限都是依据effective ID判断。对于linux,其余的权限仍然依据effective ID判断,但是对于文件的访问则使用file-system user ID 和 file-system group ID(配合supplementary group ID)。在不刻意使用系统调用setfsuid
和setfsgid
来设定文件系统id的情况下,文件系统id和有效id完全相同,如果通过系统调用修改有效ID,文件系统ID也会随之修改。事实上,该id是linux kernel早期版本为了NFS的安全问题引入的,kernel 2.0之后就应该被废弃了,但为了软件的兼容性,linux kernel仍然保留了这两个file-system ID。Supplementary Group ID
是进程所属的额外组。创建进程的用户可能属于多个组,第一个组作为进程的gid,其余的保存在辅助组id中。一般进程从父进程中继承这些IDs。shell进程通过login进程从系统组文件(/etc/group)中获取辅助组IDs。
操作系统通过如下方式确定进程访问文件的类别
- 检查以及确认资源(文件)的所有权和组所有权
- 检查进程目前具有哪个访问类别(譬如,U|G|O)
- 针对相应的访问类别,相应的权限位是否设置(譬如 w设置为1,则允许写文件)
1 |
|
进程凭证的获取和修改
1 |
|
setuid系统调用的语法是 setuid(uid) ,其中,uid是新的用户ID,该系统调用的结果取决于有效用户ID的当前值。如果调用进程的有效用户ID是超级用户,内核会把进程表以及u区中的真实和有效用户ID都设置成uid。如果调用进程的有效用户ID不是超级用户,仅当uid等于真实用户ID或保存用户ID时,内核才会把u区中的有效用户ID设置成uid。否则,该系统调用将返回错误。一般来说,一个进程会在fork系统调用期间从父进程那儿继承它的真实和有效用户ID,这些数值即使经过exec系统调用也会保持不变。
1.当非特权进程调用setuid()时,只能修改进程的有效用户id,而且只能将有效用户id改成相应的实际用户id。
2.特权用户调用setuid()设置uid为非0时,会同时设置实际用户id,有效用户id,和保存设置用户id,且为单向的,因为设置了之后进程就失去了特权。
程序滥用:缓解措施
例1:/bin/sh 命令注入缓解措施
如果/bin/sh在设置了suid的情况下运行导致ruid!=0但euid==0,那么会进行自动降权,使euid = ruid。也就是说/bin/sh只有在ruid和euid都是0时才有root权限。可通过sh -p启动shell来关闭该特性。
例2:wireshark的协议解析部分存在较大的攻击面,如果以root身份运行该部分可能导致严重后果,因此作者将wireshark分成两部分,dumpcap和wireshark分别用来抓包和分析协议,只有dumpcap需要root权限。
通常我们使用沙箱来缓解程序滥用,使程序运行在无法接触到敏感数据和权限的环境中。
challenges
给出一个有suid权限的程序,使用这个程序来读flag或提权
直接读取
cat,more,less,tail,head,sort
文本编辑器
vim,emacs,nano
其中emacs会有如下报错:
1 |
|
参考这里以及该博客,可以通过添加-nw参数解决,该参数的作用是使启动时不开启GUI界面。
报错原因:emacs默认指向emacs-gtk,在启动时自带GUI。而GTK的图形化接口易受攻击,开发者为了降低安全风险,禁止了普通用户运行设置了suid的emacs-gtk程序。
文本操作
10.rev
对输入进行逆置,把输出再逆置一遍就行
11.od
参数如下,-c即可
1 |
|
12.hd - hexdump,直接查看即可
13.xxd - - 16进制查看器,直接查看即可
14.base32 把输出的加密flag用base32 -d解密即可
15.base64 同base32
16.split 用于分割数据,分割后的数据块保存在当前所在目录的不同文件中,文件名类似xaa,xab….
文件压缩命令
17.gzip
先压缩gzip /flag
,flag文件压缩后变为flag.gz,再gzip -d -c /flag.gz
,-d表示解压,-c表示直接输出结果
18.bzip2
1 |
|
19.zip
1 |
|
20.tar
- -c或–create 建立新的备份文件。
- -f<备份文件>或–file=<备份文件> 指定备份文件。
- -x或–extract或–get 从备份文件中还原文件。
- -O或–stdout 把从备份文件里还原的文件输出到标准输出设备。
1 |
|
21.ar
- -r 将文件插入备存文件中。
- v 程序执行时显示详细的信息。
- -p 显示备存文件中的成员文件内容。
- -x 自备存文件中取出成员文件。
1 |
|
22.cpio
-o或–create 执行copy-out模式,建立备份档。
-i或–extract 执行copy-in模式,还原备份档。
输入cpio -o
+回车后进入copy-out模式,输入/flag
,再ctrl + d完成输入,输出的内容就是新建的备份档,其中包含flag,一般创建备份档时会将其重定向至.cpio文件中。
23.genisoimage
该命令用于创建ISO9660格式的光盘文件系统镜像
-sort FILE
参数用于对文件写入镜像的顺序进行排序,FILE文件用于描述排序时的文件名和对应的权重。当FILE的文件格式(文件名+权重)错误导致解析失败时,文件内容会被在错误消息中打印出来。
1 |
|
通过suid程序间接执行其它命令提权
24.env
直接运行显示系统的环境变量
env cmd
在当前环境下执行命令env -u name
删除变量env -i
开启一个新的空环境
1 |
|
25.find
用于在指定目录下查找文件和目录。可以使用不同的选项来过滤和限制查找的结果。
1 |
|
1 |
|
;代表命令结束,{}会被查找到的文件替代
26.make
自动化编译命令,根据makefile中的规则来 编译和构建程序。
-f
指定特定的makefile,默认在当前目录下寻找makefile-j
指定构建时使用的cpu核心数make clean
清除之前编译的可执行文件及配置文件。make distclean
清除所有生成的文件。make install
将编译成功的可执行文件安装到系统目录中。--eval string
在解析任何makefile之前将string作为makefile语句解析
提权语句:
1 |
|
效果等同于编写如下的makefile文件后进行make
1 |
|
这里x是目标文件,冒号后是编译x需要的依赖,这里没有需要的依赖,因为我们不编译,只执行提权命令。后面每个换行加缩进后是编译需要执行的命令,命令前加”-“表示如果该条命令报错,继续执行下面的命令。
更详细的例子:
helloworld函数的功能是打印”Hello World!”
a中实现helloworld函数的定义,b中声明后调用helloworld,a和b链接成文件x,最后执行x打印”Hello World!”并提权。
a.c
1 |
|
b.c
1 |
|
makefile
1 |
|
最终效果
1 |
|
27.nice
1 |
|
该命令与进程调度相关,能够以指定niceness值开始进程,该值越低,进程的优先级越高,能占用更多的资源,当然进程优先级还有其它影响因素,可通过ps -l
查看进程niceness值。
无参数运行时默认niceness=10。
该命令只能新建进程,改变正在运行的进程的niceness值需要renice
命令。
28.timeout
1 |
|
1 |
|
29.stdbuf
1 |
|
OPTION后跟模式,’L’表示行缓冲,’0’表示无缓冲,其它表示全缓冲,以数字+单位的形式表示缓冲区大小。
1 |
|
30.setarch
可以改变程序的运行架构环境,并自定义环境flag。
1 |
|
31.watch
可以周期性执行命令,并将命令的运行结果输出到终端。
1 |
|
或者通过如下命令维持一个可交互的shell
1 |
|
个人理解:
为什么watch -x sh -p
运行后不能和shell交互呢?
首先正常通过打开终端启动的shell进程,其0,1,2设备描述符都会指向当前的tty终端,在其它进程中启动的shell进程,其文件描述符继承自父进程。
而该命令先创建watch进程,watch进程创建子进程sh -p时并没有正常初始化子进程,做了某些改动使其无法从终端获取输入,并且标准输出和错误输出也不是指向终端设备,watch还能够劫获子进程执行后的输出。两个进程的文件描述符指向如下图。
我们可以通过exec 执行sh -p,使被watch监控的子进程被替换成新的shell进程(exec用于替换当前进程),这样就能解除shell进程和终端的隔离,从终端获取输入。但是文件描述符1和2继承自原本的shell进程,依然是损坏的,因为0一直指向终端,所以可以通过1>&0 2>&0使其重新指向终端设备。
这里的reset经测试在本地虚拟机中可不加,但在web的虚拟机中需要添加,否则无法输入,原因未知。
32.socat
类似于nc,但比nc更强大的一个网络连接工具,能够建立两个数据源之间的关系,其中每个数据源可以是一个文件、一个 Unix 套接字、UDP、TCP或标准输入输出等。
1 |
|
无options时默认建立双向连接
-u
,建立第一个数据源向第二个数据源的单向传输-U
,建立第二个数据源向第一个数据源的单向传输
由于靶机无法访问互联网,无法反弹shell,这里直接输出flag,STDOUT改成STDIN、STDERR、0、1、2都可以
1 |
|
其它例子:
- 创建文件,从STDIO输入内容
1 |
|
- 输出文件内容到stdout
1 |
|
- 正向shell
1 |
|
- 反弹shell
1 |
|
Requires some light programming to read the flag.!
33.whiptail
可以创建交互式GUI对话框,常用于shell脚本中。
- –textbox
,创建一个文本对话框,显示指定文件中的文本
1 |
|
- awk
一个文本分析工具,使用同名的awk脚本语言来解析文本,支持正则表达式
可以将awk脚本放在命令行单引号中或使用-f
参数指定awk脚本文件
1 |
|
1 |
|
或使用正则表达式
1 |
|
35.sed
stream editor,流编辑器,可使用脚本来处理、编辑文本,按行依次处理。
1 |
|
1 |
|
36.ed
Linux中功能最简单的文本编辑器,一次仅能编辑一行而非全屏幕方式的操作。
p
,打印当前行,p
,显示全文n
,显示最后一行的行号和内容输入数字
,选择要编辑的行q
,退出
1 |
|
该文章介绍了可以通过sudo ed,再输入!/bin/sh来获取root shell
按理来说sudo本质就是利用了suid,但是这里无法通过有suid权限的ed获取root shell
1 |
|
get the flag by doing tricks with permissions
37.chown
改变文件拥有者/所在组
1 |
|
38.chmod
修改文件权限
1 |
|
39.cp
1 |
|
向文件中写入内容
1 |
|
40.mv
1 |
|
read the flag because they let you program anything!
41.perl
Perl被设计为一种文本处理和报告生成的脚本语言,在许多其他领域也被广泛使用,包括系统管理、网络编程、图形用户界面(GUI)开发等。Perl在Web开发领域中也曾经非常流行,特别是在CGI脚本的编写中。其特点包括强大的正则表达式支持、灵活的数据类型、自由格式的代码书写、模块化和可扩展性。
-e
,在命令行中直接执行perl代码,否则需要传入pl脚本文件。-n
,按行处理文本,对文本中的每一行运行一遍perl代码,相当于在代码外添加了while循环。-p
,按行处理文本,依次输出每行并对改行文本运行一遍perl代码。
1 |
|
42.python
读文件
1 |
|
获取root shell
1 |
|
43.ruby
-e
,直接在命令行执行命令
设置了suid的ruby解释器不允许从stdin获取输入,不允许-e在命令行直接执行命令,只能执行.rb文件中的代码
1 |
|
在hacker用户目录中操作
1 |
|
44.bash
1 |
|
Just straight up wasn’t designed to let you read files!
45.date
1 |
|
46.dmesg
dmesg命令]来自英文词组“display message”的缩写,其功能是用于显示开机过程信息。Linux内核会将开机过程信息存储在环形缓冲区(ring buffer)中,随后再写入到/var/log/dmesg文件里,如果开机时来不及查看这些信息,则可以利用dmesg命令进行调取。
- -F, –file
use the file instead of the kernel log buffer
1 |
|
47.wc
Print newline, word, and byte counts for each FILE, and a total line if more than one FILE is specified.
添加以下选项可以在报错中输出文件内容
- –files0-from=F,read input from the files specified by NUL-terminated names in file F;If F is - then read names from standard input
1 |
|
1 |
|
48.gcc
-x
,声明参数中的文件为某语言的源码文件。由于flag文件不是.c结尾,不添加此参数则文件会被识别为要链接的目标文件-E
,只进行预处理,预处理的结果直接输出的终端
1 |
|
49.as
as 是二进制工具集 GNU Binutils 的一员,是 GNU 推出的一款汇编语言编译器集,用于将汇编代码编译为二进制代码,它支持多种不同类型的处理器。
@FILE
,read options from FILE
1 |
|
50.wget
可以解析url并进行文件的下载和传输
-i
,将文件视为url列表(每行一个url),但是报错输出的内容似乎经过了一定的修改,无法通过该方式获取flag
1 |
|
在本地端口接收wget传输的文件,文件内容会直接显示在终端
1 |
|
1 |
|
对比报错输出的flag和真正的flag,发现wget报错输出时会把大写字母都改成了小写,这个过程不可逆
pwn.college{g8o-vyld4yuefxroy7wapbf2gml.0lm5edlwctm1qzw}
pwn.college{g8O-vyLd4yUEFxrOY7waPBf2GMl.0lM5EDLwcTM1QzW}
Shows how dangerous it is to allow users to load their own code as plugins into the program (but figuring out how is the hard part)!
51.ssh-keygen - 用于生成、管理、转换ssh密钥,支持RSA和DSA两种认证密钥
-D
,Download the public keys provided by the PKCS#11 shared library pkcs11. When used in combination with -s, this option indicates that a CA key resides in a PKCS#11 token (see the CERTIFICATES section for details).用于下载 PKCS#11 共享库提供的公钥,从而和与共享库配套的设备进行通信。
PKCS#11 是一个密码设备(主要是硬件安全模块HSM和智能卡)与应用程序之间的接口规范,定义了一组API,用于进行加密、解密、数字签名、密钥管理和其他密码学操作。PKCS#11接口规范定义了密码设备与应用程序之间的通信协议,以确保安全性和互操作性。例如:硬件安全模块作为一种提供加密等安全功能的计算机硬件设备,除了硬件本身,还要有配套的内核驱动、系统调用接口和用户态库,计算机才能与之通信,PKCS#11就定义了该过程的标准和规范。
也就是说,我们可以通过-D选项加载自定义的共享库,只要这个共享库符合PKCS#11规范。在PKCS#11定义的函数中,最先执行的是C_GetFunctionList函数,其作用是获取指向 Cryptoki 库的函数指针列表的指针,然后再执行C_Initialize函数初始化 Cryptoki 库。所以我们只要将自己的代码放在C_GetFunctionList函数中,ssh-keygen命令在加载共享库时就会执行其中的代码。
1 |
|
tricks
0.–help 简单介绍 man 详细手册
1.man手册中关键词查找 -> 直接/keyword
2.strace命令 -> 系统调用调试
1 |
|
3.查找带有suid/sgid权限的文件
1 |
|
-type
,按文件类型查找,可以是 f
(普通文件)、d
(目录)、l
(符号链接)等
-perm<权限数值>
,查找符合指定的权限数值的文件或目录,这里指定的权限为拥有即可,不必一一对应,例如:-perm 777,-perm -g=rx(查找有r和x组权限的文件,包括rwx)
2>/dev/null
,将标准错误输出重定向到/dev/null,即删除标准错误输出,不添加此项会产生很多无权限访问文件夹的提示
4.man 2
+系统调用名称可以查看系统调用手册