This commit is contained in:
firmianay 2018-06-08 20:46:05 +08:00
parent 77551e0470
commit a0ebe4a208
26 changed files with 961 additions and 119 deletions

View File

@ -76,6 +76,7 @@ GitHub 地址https://github.com/firmianay/CTF-All-In-One
* [3.1.11 Linux 内核漏洞利用](doc/3.1.11_linux_kernel_exploit.md)
* [3.1.12 Windows 内核漏洞利用](doc/3.1.12_windows_kernel_exploit.md)
* [3.1.13 竞争条件](doc/3.1.13_race_condition.md)
* [3.1.14 虚拟机逃逸](doc/3.1.14_vm_escape.md)
* Reverse
* [3.2.1 patch 二进制文件](doc/3.2.1_patch_binary.md)
* [3.2.2 脱壳技术PE](doc/3.2.2_pe_unpack.md)
@ -165,6 +166,8 @@ GitHub 地址https://github.com/firmianay/CTF-All-In-One
* [6.1.29 pwn Insomni'hack_teaserCTF2017 The_Great_Escape_part-3](doc/6.1.29_pwn_insomnictf2017_the_great_escape3.md)
* [6.1.30 pwn HITCONCTF2017 Ghost_in_the_heap](doc/6.1.30_pwn_hitconctf2017_ghost_in_the_heap.md)
* [6.1.31 pwn HITBCTF2018 mutepig](doc/6.1.31_pwn_hitbctf2018_mutepig.md)
* [6.1.32 pwn SECCONCTF2017 vm_no_fun](doc/6.1.32_pwn_secconctf2017_vm_no_fun.md)
* [6.1.33 pwn 34C3CTF2017 LFA](doc/6.1.33_pwn_34c3ctf2017_lfa.md)
* Reverse
* [6.2.1 re XHPCTF2017 dont_panic](doc/6.2.1_re_xhpctf2017_dont_panic.md)
* [6.2.2 re ECTF2016 tayy](doc/6.2.2_re_ectf2016_tayy.md)
@ -221,6 +224,7 @@ GitHub 地址https://github.com/firmianay/CTF-All-In-One
* [8.27 Firmalice - Automatic Detection of Authentication Bypass Vulnerabilities in Binary Firmware](doc/8.27_firmalice_bypass.md)
* [8.28 Cross-Architecture Bug Search in Binary Executables](doc/8.28_cross_arch_bug_search.md)
* [8.29 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data](doc/8.29_dynamic_hooks.md)
* [8.30 Preventing brute force attacks against stack canary protection on networking servers](doc/8.30_prevent_brute_force_canary.md)
* [九、附录](doc/9_appendix.md)
* [9.1 更多 Linux 工具](doc/9.1_Linuxtools.md)
* [9.2 更多 Windows 工具](doc/9.2_wintools.md)

View File

@ -12,7 +12,8 @@
- [核心转储](#核心转储)
- [调用约定](#调用约定)
- [环境变量](#环境变量)
- [/proc/[pid]](#procpid)
- [procfs](#procfs)
- [参考资料](#参考资料)
## 常用基础命令
@ -399,6 +400,8 @@ Cannot access memory at address 0x4141413d
## 环境变量
环境变量字符串都是 `name=value` 这样的形式。大多数 name 由大写字母加下画线组成,一般把 name 部分叫做环境变量名value 部分则是环境变量的值,而且 value 需要以 "/0" 结尾,环境变量定义了该进程的运行环境。
#### 分类
- 按照生命周期划分
- 永久环境变量:修改相关配置文件,永久生效。
@ -470,7 +473,6 @@ $ LD_PRELOAD=~/libc.so.6 ldd /bin/true
本地同版本编译后通常不会出现问题。如果有直接拷贝已编译版本的需要,可以对比 `interpreter` 确定是否符合要求,但是不保证不会失败。
上面的例子中两个 libc 是这样的:
```
$ file /lib/x86_64-linux-gnu/libc-2.23.so
/lib/x86_64-linux-gnu/libc-2.23.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=088a6e00a1814622219f346b41e775b8dd46c518, for GNU/Linux 2.6.32, stripped
@ -496,112 +498,304 @@ $ file ~/libc.so.6
```
一个在 `interpreter /usr/lib/ld-linux-x86-64.so.2`,而另一个在 `interpreter /lib64/ld-linux-x86-64.so.2`
#### environ
libc 中定义的全局变量 `environ` 指向环境变量表。而环境变量表存在于栈上,所以通过 `environ` 指针的值就可以泄露出栈地址。
```
gdb-peda$ vmmap libc
Start End Perm Name
0x00007ffff7a1c000 0x00007ffff7bcf000 r-xp /usr/lib/libc-2.27.so
0x00007ffff7bcf000 0x00007ffff7dce000 ---p /usr/lib/libc-2.27.so
0x00007ffff7dce000 0x00007ffff7dd2000 r--p /usr/lib/libc-2.27.so
0x00007ffff7dd2000 0x00007ffff7dd4000 rw-p /usr/lib/libc-2.27.so
gdb-peda$ vmmap stack
Start End Perm Name
0x00007ffffffde000 0x00007ffffffff000 rw-p [stack]
gdb-peda$ shell nm -D /usr/lib/libc-2.27.so | grep environ
00000000003b8ee0 V environ
00000000003b8ee0 V _environ
00000000003b8ee0 B __environ
gdb-peda$ x/gx 0x00007ffff7a1c000 + 0x00000000003b8ee0
0x7ffff7dd4ee0 <environ>: 0x00007fffffffde48
gdb-peda$ x/5gx 0x00007fffffffde48
0x7fffffffde48: 0x00007fffffffe1da 0x00007fffffffe1e9
0x7fffffffde58: 0x00007fffffffe1fd 0x00007fffffffe233
0x7fffffffde68: 0x00007fffffffe25f
gdb-peda$ x/5s 0x00007fffffffe1da
0x7fffffffe1da: "COLORFGBG=15;0"
0x7fffffffe1e9: "COLORTERM=truecolor"
0x7fffffffe1fd: "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
0x7fffffffe233: "DESKTOP_SESSION=/usr/share/xsessions/plasma"
0x7fffffffe25f: "DISPLAY=:0"
```
## /proc/[pid]
proc 文件系统是 Linux 内核提供的,为访问系统内核数据的操作提供接口。在该文件系统下,有一些以数字命名的目录,这些数字是进程的 PID 号,而这些目录是进程目录。
目录下的所有文件如下,然后会介绍几个比较重要的:
## procfs
procfs 文件系统是 Linux 内核提供的虚拟文件系统,为访问系统内核数据的操作提供接口。之所以说是虚拟文件系统,是因为它不占用存储空间,而只是占用了内存。用户可以通过 procfs 查看有关系统硬件及当前正在运行进程的信息,甚至可以通过修改其中的某些内容来改变内核的运行状态。
#### /proc/cmdline
在启动时传递给内核的相关参数信息,通常由 lilo 或 grub 等启动管理工具提供:
```
cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-4.14-x86_64 root=UUID=8e79a67d-af1b-4203-8c1c-3b670f0ec052 rw quiet resume=UUID=a220ecb1-7fde-4032-87bf-413057e9c06f
```
#### /proc/cpuinfo
记录 CPU 相关的信息:
```
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 60
model name : Intel(R) Core(TM) i5-4210H CPU @ 2.90GHz
stepping : 3
microcode : 0x24
cpu MHz : 1511.087
cache size : 3072 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt dtherm ida arat pln pts
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass
bogomips : 5788.66
clflush size : 64
cache_alignment : 64
address sizes : 39 bits physical, 48 bits virtual
power management:
...
```
#### /proc/crypto
已安装的内核所使用的密码算法及算法的详细信息:
```
$ cat /proc/crypto
name : ccm(aes)
driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni))
module : ccm
priority : 300
refcnt : 2
selftest : passed
internal : no
type : aead
async : no
blocksize : 1
ivsize : 16
maxauthsize : 16
geniv : <none>
...
```
#### /proc/devices
已加载的所有块设备和字符设备的信息,包含主设备号和设备组(与主设备号对应的设备类型)名:
```
$ cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
...
```
#### /proc/interrupts
X86/X86_64 系统上每个 IRQ 相关的中断号列表,多路处理器平台上每个 CPU 对于每个 I/O 设备均有自己的中断号:
```
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
0: 15 0 0 0 IR-IO-APIC 2-edge timer
1: 46235 1277 325 156 IR-IO-APIC 1-edge i8042
8: 0 1 0 0 IR-IO-APIC 8-edge rtc0
...
NMI: 0 0 0 0 Non-maskable interrupts
LOC: 7363806 5569019 6138317 5442200 Local timer interrupts
SPU: 0 0 0 0 Spurious interrupts
...
```
#### /proc/kcore
系统使用的物理内存,以 ELF 核心文件core file格式存储
```
$ sudo file /proc/kcore
/proc/kcore: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from 'BOOT_IMAGE=/boot/vmlinuz-4.14-x86_64 root=UUID=8e79a67d-af1b-4203-8c1c-3b670f0e'
```
#### /proc/meminfo
系统中关于当前内存的利用状况等的信息:
```
$ cat /proc/meminfo
MemTotal: 12226252 kB
MemFree: 4909444 kB
MemAvailable: 8776048 kB
Buffers: 288236 kB
Cached: 3953616 kB
...
```
#### /proc/mounts
每个进程自身挂载名称空间中的所有挂载点列表文件的符号链接:
```
$ cat /proc/mounts
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
dev /dev devtmpfs rw,nosuid,relatime,size=6106264k,nr_inodes=1526566,mode=755 0 0
...
```
#### /proc/modules
当前装入内核的所有模块名称列表,可以由 lsmod 命令使用。其中第一列表示模块名第二列表示此模块占用内存空间大小第三列表示此模块有多少实例被装入第四列表示此模块依赖于其它哪些模块第五列表示此模块的装载状态Live已经装入、Loading正在装入和 Unloading正在卸载第六列表示此模块在内核内存kernel memory中的偏移量
```
$ cat /proc/modules
fuse 118784 3 - Live 0xffffffffc0d9b000
ccm 20480 3 - Live 0xffffffffc0d95000
rfcomm 86016 4 - Live 0xffffffffc0d7f000
bnep 24576 2 - Live 0xffffffffc0d78000
...
```
#### /proc/slabinfo
保存着监视系统中所有活动的 slab 缓存的信息:
```
$ sudo cat /proc/slabinfo
slabinfo - version: 2.1
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
fuse_request 0 20 400 20 2 : tunables 0 0 0 : slabdata 1 1 0
fuse_inode 1 39 832 39 8 : tunables 0 0 0 : slabdata 1 1 0
drm_i915_gem_request 765 1036 576 28 4 : tunables 0 0 0 : slabdata 37 37 0
...
```
#### /proc/[pid]
在 /proc 文件系统下,还有一些以数字命名的目录,这些数字是进程的 PID 号,而这些目录是进程目录。目录下的所有文件如下,然后会介绍几个比较重要的:
```
$ cat - &
[1] 2865
$ ls /proc/2865/
attr cpuset limits ns root statm
autogroup cwd map_files numa_maps sched status
auxv environ maps oom_adj schedstat syscall
cgroup exe mem oom_score setgroups task
clear_refs fd mountinfo oom_score_adj smaps timers
cmdline fdinfo mounts pagemap smaps_rollup timerslack_ns
comm gid_map mountstats personality stack uid_map
coredump_filter io net projid_map stat wchan
[1]+ Stopped cat -
[1] 1060
$ ls /proc/1060/
attr comm fd maps ns personality smaps syscall
autogroup coredump_filter fdinfo mem numa_maps projid_map smaps_rollup task
auxv cpuset gid_map mountinfo oom_adj root stack timers
cgroup cwd io mounts oom_score sched stat timerslack_ns
clear_refs environ limits mountstats oom_score_adj schedstat statm uid_map
cmdline exe map_files net pagemap setgroups status wchan
```
#### /proc/[pid]/cmdline
启动当前进程的完整命令:
```
$ cat /proc/1060/cmdline
cat-
```
#### /proc/[pid]/exe
指向启动当前进程的可执行文件的符号链接:
```
$ file /proc/1060/exe
/proc/1060/exe: symbolic link to /usr/bin/cat
```
#### /proc/[pid]/root
当前进程运行根目录的符号链接:
```
$ file /proc/1060/root
/proc/1060/root: symbolic link to /
```
#### /proc/[pid]/mem
当前进程所占用的内存空间由open、read和lseek等系统调用使用不能被用户读取。但可通过下面的 /proc/[pid]/maps 查看。
#### /proc/[pid]/maps
这个文件大概是最常用的,用于显示进程的内存区域映射信息:
```
$ cat /proc/2865/maps
5580631c6000-5580631ce000 r-xp 00000000 08:01 4981196 /usr/bin/cat
5580633cd000-5580633ce000 r--p 00007000 08:01 4981196 /usr/bin/cat
5580633ce000-5580633cf000 rw-p 00008000 08:01 4981196 /usr/bin/cat
558063c7d000-558063c9e000 rw-p 00000000 00:00 0 [heap]
7f6301cd7000-7f6302027000 r--p 00000000 08:01 4993768 /usr/lib/locale/locale-archive
7f6302027000-7f63021d5000 r-xp 00000000 08:01 4982395 /usr/lib/libc-2.26.so
7f63021d5000-7f63023d5000 ---p 001ae000 08:01 4982395 /usr/lib/libc-2.26.so
7f63023d5000-7f63023d9000 r--p 001ae000 08:01 4982395 /usr/lib/libc-2.26.so
7f63023d9000-7f63023db000 rw-p 001b2000 08:01 4982395 /usr/lib/libc-2.26.so
7f63023db000-7f63023df000 rw-p 00000000 00:00 0
7f63023df000-7f6302404000 r-xp 00000000 08:01 4982398 /usr/lib/ld-2.26.so
7f63025c1000-7f63025c3000 rw-p 00000000 00:00 0
7f63025e1000-7f6302603000 rw-p 00000000 00:00 0
7f6302603000-7f6302604000 r--p 00024000 08:01 4982398 /usr/lib/ld-2.26.so
7f6302604000-7f6302605000 rw-p 00025000 08:01 4982398 /usr/lib/ld-2.26.so
7f6302605000-7f6302606000 rw-p 00000000 00:00 0
7fff2ab81000-7fff2aba2000 rw-p 00000000 00:00 0 [stack]
7fff2abef000-7fff2abf2000 r--p 00000000 00:00 0 [vvar]
7fff2abf2000-7fff2abf4000 r-xp 00000000 00:00 0 [vdso]
$ cat /proc/1060/maps
56271b3a5000-56271b3ad000 r-xp 00000000 08:01 24904069 /usr/bin/cat
56271b5ac000-56271b5ad000 r--p 00007000 08:01 24904069 /usr/bin/cat
56271b5ad000-56271b5ae000 rw-p 00008000 08:01 24904069 /usr/bin/cat
56271b864000-56271b885000 rw-p 00000000 00:00 0 [heap]
7fefb66cd000-7fefb6a1e000 r--p 00000000 08:01 24912207 /usr/lib/locale/locale-archive
7fefb6a1e000-7fefb6bd1000 r-xp 00000000 08:01 24905238 /usr/lib/libc-2.27.so
7fefb6bd1000-7fefb6dd0000 ---p 001b3000 08:01 24905238 /usr/lib/libc-2.27.so
7fefb6dd0000-7fefb6dd4000 r--p 001b2000 08:01 24905238 /usr/lib/libc-2.27.so
7fefb6dd4000-7fefb6dd6000 rw-p 001b6000 08:01 24905238 /usr/lib/libc-2.27.so
7fefb6dd6000-7fefb6dda000 rw-p 00000000 00:00 0
7fefb6dda000-7fefb6dff000 r-xp 00000000 08:01 24905239 /usr/lib/ld-2.27.so
7fefb6fbd000-7fefb6fbf000 rw-p 00000000 00:00 0
7fefb6fdc000-7fefb6ffe000 rw-p 00000000 00:00 0
7fefb6ffe000-7fefb6fff000 r--p 00024000 08:01 24905239 /usr/lib/ld-2.27.so
7fefb6fff000-7fefb7000000 rw-p 00025000 08:01 24905239 /usr/lib/ld-2.27.so
7fefb7000000-7fefb7001000 rw-p 00000000 00:00 0
7ffde5659000-7ffde567a000 rw-p 00000000 00:00 0 [stack]
7ffde5748000-7ffde574b000 r--p 00000000 00:00 0 [vvar]
7ffde574b000-7ffde574d000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
```
#### /proc/[pid]/stack
这个文件表示当前进程的内核调用栈信息:
这个文件表示当前进程的内核调用栈信息,只有在内核编译启用 `CONFIG_STACKTRACE` 选项,才会生成该文件
```
$ sudo cat /proc/2865/stack
[<ffffffffa008d05e>] do_signal_stop+0xae/0x1f0
[<ffffffffa008e50c>] get_signal+0x18c/0x5a0
[<ffffffffa002ac26>] do_signal+0x36/0x610
[<ffffffffa0003019>] exit_to_usermode_loop+0x69/0xa0
[<ffffffffa00038eb>] syscall_return_slowpath+0x9b/0xb0
[<ffffffffa06926e4>] entry_SYSCALL_64_fastpath+0x7b/0x7d
$ sudo cat /proc/1060/stack
[<ffffffff8e08fa2e>] do_signal_stop+0xae/0x1f0
[<ffffffff8e090ec1>] get_signal+0x191/0x580
[<ffffffff8e02ae56>] do_signal+0x36/0x610
[<ffffffff8e003669>] exit_to_usermode_loop+0x69/0xa0
[<ffffffff8e0039d1>] do_syscall_64+0xf1/0x100
[<ffffffff8e800081>] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
[<ffffffffffffffff>] 0xffffffffffffffff
```
#### /proc/[pid]/auxv
该文件包含了传递给进程的解释器信息,即 auxv(AUXiliary Vector),每一项都是由一个 unsigned long 长度的 ID 加上一个 unsigned long 长度的值构成:
```
$ xxd -e -g8 /proc/2865/auxv
00000000: 0000000000000021 00007fff2abf2000 !........ .*....
$ xxd -e -g8 /proc/1060/auxv
00000000: 0000000000000021 00007ffde574b000 !.........t.....
00000010: 0000000000000010 00000000bfebfbff ................
00000020: 0000000000000006 0000000000001000 ................
00000030: 0000000000000011 0000000000000064 ........d.......
00000040: 0000000000000003 00005580631c6040 ........@`.c.U..
00000040: 0000000000000003 000056271b3a5040 ........@P:.'V..
00000050: 0000000000000004 0000000000000038 ........8.......
00000060: 0000000000000005 0000000000000009 ................
00000070: 0000000000000007 00007f63023df000 ..........=.c...
00000070: 0000000000000007 00007fefb6dda000 ................
00000080: 0000000000000008 0000000000000000 ................
00000090: 0000000000000009 00005580631c8290 ...........c.U..
00000090: 0000000000000009 000056271b3a7260 ........`r:.'V..
000000a0: 000000000000000b 00000000000003e8 ................
000000b0: 000000000000000c 00000000000003e8 ................
000000c0: 000000000000000d 00000000000003e8 ................
000000d0: 000000000000000e 00000000000003e8 ................
000000e0: 0000000000000017 0000000000000000 ................
000000f0: 0000000000000019 00007fff2ab9ff39 ........9..*....
000000f0: 0000000000000019 00007ffde5678349 ........I.g.....
00000100: 000000000000001a 0000000000000000 ................
00000110: 000000000000001f 00007fff2aba1feb ...........*....
00000120: 000000000000000f 00007fff2ab9ff49 ........I..*....
00000110: 000000000000001f 00007ffde5679fef ..........g.....
00000120: 000000000000000f 00007ffde5678359 ........Y.g.....
00000130: 0000000000000000 0000000000000000 ................
```
每个值具体是做什么的,可以用下面的办法显示出来,对比看一看,更详细的可以查看 `/usr/include/elf.h``man ld.so`
```
$ LD_SHOW_AUXV=1 cat -
AT_SYSINFO_EHDR: 0x7fff6afb3000
AT_SYSINFO_EHDR: 0x7ffd16be5000
AT_HWCAP: bfebfbff
AT_PAGESZ: 4096
AT_CLKTCK: 100
AT_PHDR: 0x557b68217040
AT_PHDR: 0x55eb4c59a040
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7f41e5689000
AT_BASE: 0x7f61506e8000
AT_FLAGS: 0x0
AT_ENTRY: 0x557b68219290
AT_ENTRY: 0x55eb4c59c260
AT_UID: 1000
AT_EUID: 1000
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0
AT_RANDOM: 0x7fff6aedc0a9
AT_RANDOM: 0x7ffd16bd0ce9
AT_HWCAP2: 0x0
AT_EXECFN: /usr/bin/cat
AT_EXECFN: /bin/cat
AT_PLATFORM: x86_64
```
值得一提的是,`AT_SYSINFO_EHDR` 所对应的值是一个叫做的 VDSO(Virtual Dynamic Shared Object) 的地址。在 ret2vdso 漏洞利用方法中会用到参考章节6.1.6)。
@ -609,84 +803,66 @@ AT_PLATFORM: x86_64
#### /proc/[pid]/environ
该文件包含了进程的环境变量:
```
$ strings /proc/2865/environ
$ strings /proc/1060/environ
GS_LIB=/home/firmy/.fonts
KDE_FULL_SESSION=true
VIRTUALENVWRAPPER_WORKON_CD=1
VIRTUALENVWRAPPER_HOOK_DIR=/home/firmy/.virtualenvs
LANG=zh_CN.UTF-8
...
```
#### /proc/[pid]/fd
该文件包含了进程打开文件的情况:
```
$ ls -al /proc/2865/fd
$ ls -al /proc/1060/fd
total 0
dr-x------ 2 firmy firmy 0 12月 30 11:13 .
dr-xr-xr-x 9 firmy firmy 0 12月 30 11:13 ..
lrwx------ 1 firmy firmy 64 12月 30 12:31 0 -> /dev/pts/2
lrwx------ 1 firmy firmy 64 12月 30 12:31 1 -> /dev/pts/2
lrwx------ 1 firmy firmy 64 12月 30 12:31 2 -> /dev/pts/2
dr-x------ 2 firmy firmy 0 6月 7 23:37 .
dr-xr-xr-x 9 firmy firmy 0 6月 7 23:37 ..
lrwx------ 1 firmy firmy 64 6月 7 23:44 0 -> /dev/pts/3
lrwx------ 1 firmy firmy 64 6月 7 23:44 1 -> /dev/pts/3
lrwx------ 1 firmy firmy 64 6月 7 23:44 2 -> /dev/pts/3
```
#### /proc/[pid]/status
该文件包含了进程的状态信息:
```
$ cat /proc/2865/status
$ cat /proc/1060/status
Name: cat
Umask: 0022
State: T (stopped)
Tgid: 2865
Tgid: 1060
Ngid: 0
Pid: 2865
PPid: 2059
Pid: 1060
PPid: 1035
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 3 7 10 56 90 91 93 95 96 98 1000
NStgid: 2865
NSpid: 2865
NSpgid: 2865
NSsid: 2059
VmPeak: 7828 kB
VmSize: 7828 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 788 kB
VmRSS: 788 kB
RssAnon: 64 kB
RssFile: 724 kB
RssShmem: 0 kB
VmData: 312 kB
VmStk: 132 kB
VmExe: 32 kB
VmLib: 1876 kB
VmPTE: 40 kB
VmPMD: 12 kB
VmSwap: 0 kB
HugetlbPages: 0 kB
Threads: 1
SigQ: 2/47723
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Cpus_allowed: ff
Cpus_allowed_list: 0-7
Mems_allowed: 00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1
nonvoluntary_ctxt_switches: 0
...
```
#### /proc/[pid]/task
一个目录包含当前进程的每一个线程的相关信息每个线程的信息分别放在一个由线程号tid命名的目录中
```
$ ls /proc/1060/task/
1060
$ ls /proc/1060/task/1060/
attr clear_refs cwd fdinfo maps net oom_score projid_map setgroups stat uid_map
auxv cmdline environ gid_map mem ns oom_score_adj root smaps statm wchan
cgroup comm exe io mountinfo numa_maps pagemap sched smaps_rollup status
children cpuset fd limits mounts oom_adj personality schedstat stack syscall
```
#### /proc/[pid]/syscall
该文件包含了进程正在执行的系统调用:
```
$ sudo cat /proc/2865/syscall
0 0x0 0x7f63025e2000 0x20000 0x22 0xffffffffffffffff 0x0 0x7fff2ab9f958 0x7f630210ea11
$ sudo cat /proc/1060/syscall
0 0x0 0x7fefb6fdd000 0x20000 0x22 0xffffffff 0x0 0x7ffde5677d48 0x7fefb6b07901
```
第一个值是系统调用号,后面跟着是六个参数,最后两个值分别是堆栈指针和指令计数器的值。
## 参考资料
- [Linux Filesystem Hierarchy](http://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html)

View File

@ -66,6 +66,11 @@ $ ldd a.out
/usr/local/glibc-2.23/lib/ld-2.23.so => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f6abdb1c000)
```
然后如果希望在调试时指定 libc 的源文件,可以使用 gdb 命令 `directory`,但是这种方法的缺点是不能解析子目录,所以推荐使用下面的命令在启动时加载:
```
$ gdb `find ~/path/to/glibc/source -type d -printf '-d %p '` ./a.out
```
## malloc.c
下面我们先分析 glibc 2.23 版本的源码,它是 Ubuntu16.04 的默认版本,在 pwn 中也最常见。然后,我们再探讨新版本的 glibc 中所加入的漏洞缓解机制。

View File

@ -242,6 +242,11 @@ run `python2 -c 'print "A"*100'`
#### generate-core-file
将调试中的进程生成内核转储文件。
#### directory -- dir
设置查找源文件的路径。
或者使用 gdb 的 `-d` 参数,例如:`gdb a.out -d /search/code/`
## gdb-peda
当 gdb 启动时,它会在当前用户的主目录中寻找一个名为 `.gdbinit` 的文件;如果该文件存在,则 gdb 就执行该文件中的所有命令。通常,该文件用于简单的配置命令。但是 `.gdbinit` 的配置十分繁琐,因此对 gdb 的扩展通常用插件的方式来实现,通过 python 的脚本可以很方便的实现需要的功能。

1
doc/3.1.14_vm_escape.md Normal file
View File

@ -0,0 +1 @@
# 3.1.14 虚拟机逃逸

View File

@ -14,6 +14,7 @@
* [3.1.11 Linux 内核漏洞利用](3.1.11_linux_kernel_exploit.md)
* [3.1.12 Windows 内核漏洞利用](3.1.12_windows_kernel_exploit.md)
* [3.1.13 竞争条件](3.1.13_race_condition.md)
* [3.1.14 虚拟机逃逸](3.1.14_vm_escape.md)
* Reverse
* [3.2.1 patch 二进制文件](3.2.1_patch_binary.md)
* [3.2.2 脱壳技术PE](3.2.2_pe_unpack.md)

View File

@ -4,6 +4,7 @@
- [libc 2.23](#libc-2.23)
- [CTF 实例](#ctf-实例)
- [libc 2.25](#libc-2.25)
- [参考资料](#参考资料)
## 回顾 canary
@ -197,3 +198,7 @@ argv[0]: ./a.out
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
```
## 参考资料
- [Adventure with Stack Smashing Protector (SSP)](http://site.pi3.com.pl/papers/ASSP.pdf)

View File

@ -3,6 +3,7 @@
- [tcache](#tcache)
- [安全性分析](#安全性分析)
- [CTF 实例](#ctf-实例)
- [CVE-2017-17426](#cve-2017-17426)
- [参考资料](#参考资料)
@ -674,6 +675,71 @@ gdb-peda$ x/12gx 0x0000555555756000+0x10
在最近的 CTF 中,已经开始尝试使用 libc-2.26,比如章节 6.1.15、6.1.19 中的例子。
## CVE-2017-17426
libc-2.26 中的 tcache 机制被发现了安全漏洞,由于 `__libc_malloc()` 使用 `request2size()` 来将所请求的分配大小转换为计算块大小,该函数不会进行整数溢出检查。所以如果请求一个非常大的堆块(接近 `SIZE_MAX`),将会导致整数溢出,从而导致 malloc 错误地返回了 tcache bin 里的堆块。
一个例子:
```c
#include <stdio.h>
#include <stdlib.h>
int main() {
void *x = malloc(10);
printf("malloc(10): %p\n", x);
free(x);
void *y = malloc(((size_t)~0) - 2); // overflow allocation (size_t.max-2)
printf("malloc(((size_t)~0) - 2): %p\n", y);
}
```
```
$ gcc cve201717426.c
$ /usr/local/glibc-2.26/lib/ld-2.26.so ./a.out
malloc(10): 0x7f3f945ed260
malloc(((size_t)~0) - 2): 0x7f3f945ed260
$ /usr/local/glibc-2.27/lib/ld-2.27.so ./a.out
malloc(10): 0x7f399c69e260
malloc(((size_t)~0) - 2): (nil)
```
可以看到在使用 libc-2.26 时,第二次 malloc 返回了第一次 free 的堆块。而在使用 libc-2.27 时返回 NULL说明该问题已被修复。
#### patch
该漏洞在 libc-2.27 的这次 [commit](https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=34697694e8a93b325b18f25f7dcded55d6baeaf6) 中被修复。方法是用更安全的 `checked_request2size()` 替换 `request2size()`,以实现对整数溢出的检查:
```diff
$ git show 34697694e8a93b325b18f25f7dcded55d6baeaf6 malloc/malloc.c | cat
commit 34697694e8a93b325b18f25f7dcded55d6baeaf6
Author: Arjun Shankar <arjun@redhat.com>
Date: Thu Nov 30 13:31:45 2017 +0100
Fix integer overflow in malloc when tcache is enabled [BZ #22375]
When the per-thread cache is enabled, __libc_malloc uses request2size (which
does not perform an overflow check) to calculate the chunk size from the
requested allocation size. This leads to an integer overflow causing malloc
to incorrectly return the last successfully allocated block when called with
a very large size argument (close to SIZE_MAX).
This commit uses checked_request2size instead, removing the overflow.
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 79f0e9eac7..0c9e0748b4 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3031,7 +3031,8 @@ __libc_malloc (size_t bytes)
return (*hook)(bytes, RETURN_ADDRESS (0));
#if USE_TCACHE
/* int_free also calls request2size, be careful to not pad twice. */
- size_t tbytes = request2size (bytes);
+ size_t tbytes;
+ checked_request2size (bytes, tbytes);
size_t tc_idx = csize2tidx (tbytes);
MAYBE_INIT_TCACHE ();
```
## 参考资料
- [thread local caching in glibc malloc](http://tukan.farm/2017/07/08/tcache/)
- [MallocInternals](https://sourceware.org/glibc/wiki/MallocInternals)
- [CVE-2017-17426](https://sourceware.org/bugzilla/show_bug.cgi?id=22375)
- [CVE-2017-17426 Detail](https://nvd.nist.gov/vuln/detail/CVE-2017-17426)

View File

@ -173,7 +173,7 @@ $ wget -c http://busybox.net/downloads/busybox-1.28.3.tar.bz2
$ tar -xvjf busybox-1.28.3.tar.bz2
$ cd busybox-1.28.3/
```
生成默认配置文件并修改 `CONFIG_STATIC=y` 让它生成的是一个静态链接的 BusyBox
生成默认配置文件并修改 `CONFIG_STATIC=y` 让它生成的是一个静态链接的 BusyBox,这是因为 qemu 中没有动态链接库
```
$ make defconfig
$ cat .config | grep "CONFIG_STATIC"

View File

@ -10,7 +10,7 @@
Linux 中有各种各样的安全防护,其中 ASLR 是由内核直接提供的通过系统配置文件控制。NXCanaryPIERELRO 等需要在编译时根据各项参数开启或关闭。未指定参数时,使用默认设置。
#### CANARY
启用 CANARY 后,函数开始执行的时候会先往栈里插入 canary 信息,当函数返回时验证插入的 canary 是否被修改,如果是,停止运行。
启用 CANARY 后,函数开始执行的时候会先往栈里插入 canary 信息,当函数返回时验证插入的 canary 是否被修改,如果是,则说明发生了栈溢出,程序停止运行。
下面是一个例子:
```c
@ -150,7 +150,7 @@ No-eXecute表示不可执行其原理是将数据所在的内存页标识
但这种保护并不能阻止攻击者通过代码重用来进行攻击ret2libc
#### PIE
PIEPosition Independent Executable需要配合 ASLR 来使用以达到可执行文件的加载时地址随机化。简单来说PIE 是编译时随机化由编译器完成ASLR 是加载时随机化由操作系统完成。ASLR 将程序运行时的堆栈以及共享库的加载地址随机化,而 PIE 在编译时将程序编译为位置无关、即程序运行时各个段加载的虚拟地址在装载时确定。开启 PIE 时编译生成的是动态库文件Shared object文件而关闭 PIE 后生成可执行文件Executable
PIEPosition Independent Executable需要配合 ASLR 来使用以达到可执行文件的加载时地址随机化。简单来说PIE 是编译时随机化由编译器完成ASLR 是加载时随机化由操作系统完成。ASLR 将程序运行时的堆栈以及共享库的加载地址随机化,而 PIE 在编译时将程序编译为位置无关、即程序运行时各个段加载的虚拟地址在装载时确定。开启 PIE 时编译生成的是动态库文件Shared object文件而关闭 PIE 后生成可执行文件Executable
我们通过实际例子来探索一下 PIE 和 ASLR
```c

View File

@ -0,0 +1,30 @@
# 6.1.32 pwn SECCONCTF2017 vm_no_fun
- [题目复现](#题目复现)
- [题目解析](#题目解析)
- [漏洞利用](#漏洞利用)
- [参考资料](#参考资料)
[下载文件](../src/writeup/6.1.32_pwn_secconctf2017_vm_no_fun)
## 题目复现
```
$ file inception
inception: ELF 64-bit LSB pie executable x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c36d0c2ef8cae7c5166fa8e3cc30a229f97968c3, stripped
$ checksec -f inception
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable FILE
Partial RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH Yes 0 3 inception
$ strings libc-2.23.so | grep "GNU C"
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu9) stable release version 2.23, by Roland McGrath et al.
Compiled by GNU CC version 5.4.0 20160609.
```
64 位程序,开启了 canary、NX 和 PIE默认开启 ASLR。
## 题目解析
## 漏洞利用
## 参考资料
- https://github.com/SECCON/SECCON2017_online_CTF/tree/master/pwn/500_vm_no_fun

View File

@ -0,0 +1,19 @@
# 6.1.33 pwn 34C3CTF2017 LFA
- [题目复现](#题目复现)
- [题目解析](#题目解析)
- [漏洞利用](#漏洞利用)
- [参考资料](#参考资料)
[下载文件](../src/writeup/6.1.33_pwn_34c3ctf2017_lfa)
## 题目复现
## 题目解析
## 漏洞利用
## 参考资料
- https://ctftime.org/task/5167
- https://github.com/bkth/34c3ctf/tree/master/LFA

View File

@ -32,6 +32,8 @@
* [6.1.29 pwn Insomni'hack_teaserCTF2017 The_Great_Escape_part-3](6.1.29_pwn_insomnictf2017_the_great_escape3.md)
* [6.1.30 pwn HITCONCTF2017 Ghost_in_the_heap](6.1.30_pwn_hitconctf2017_ghost_in_the_heap.md)
* [6.1.31 pwn HITBCTF2018 mutepig](6.1.31_pwn_hitbctf2018_mutepig.md)
* [6.1.32 pwn SECCONCTF2017 vm_no_fun](6.1.32_pwn_secconctf2017_vm_no_fun.md)
* [6.1.33 pwn 34C3CTF2017 LFA](6.1.33_pwn_34c3ctf2017_lfa.md)
* Reverse
* [6.2.1 re XHPCTF2017 dont_panic](6.2.1_re_xhpctf2017_dont_panic.md)
* [6.2.2 re ECTF2016 tayy](6.2.2_re_ectf2016_tayy.md)

View File

@ -28,6 +28,7 @@ msf > search cve-2010-2883
exploit/windows/fileformat/adobe_cooltype_sing 2010-09-07 great Adobe CoolType SING Table "uniqueName" Stack Buffer Overflow
msf > use exploit/windows/fileformat/adobe_cooltype_sing
msf exploit(windows/fileformat/adobe_cooltype_sing) > show info
msf exploit(windows/fileformat/adobe_cooltype_sing) > set payload windows/exec
payload => windows/exec

View File

@ -20,7 +20,26 @@ cve-2010-3333 漏洞是一个栈溢出漏洞,该漏洞是由于 Microsoft Offi
| 反汇编器 | IDA Pro | 版本号7.0 |
| 漏洞软件 | MS Office | 版本号2003 SP3 |
我们利用 Metasploit 来生成攻击样本
我们利用 Metasploit 来生成拒绝服务攻击样本:
```
msf > search cve-2010-3333
Name Disclosure Date Rank Description
---- --------------- ---- -----------
exploit/windows/fileformat/ms10_087_rtf_pfragments_bof 2010-11-09 great MS10-087 Microsoft Word RTF pFragments Stack Buffer Overflow (File Format)
msf > use exploit/windows/fileformat/ms10_087_rtf_pfragments_bof
msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > show info
msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set target 6
target => 6
msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > set filename cve20103333.rtf
filename => cve20103333.rtf
msf exploit(windows/fileformat/ms10_087_rtf_pfragments_bof) > exploit
[*] Creating 'cve20103333.rtf' file ...
[+] cve20103333.rtf stored at /home/firmy/.msf4/local/cve20103333.rtf
```
## 漏洞分析

View File

@ -0,0 +1 @@
# 8.30 Preventing brute force attacks against stack canary protection on networking servers

View File

@ -32,3 +32,4 @@
* [8.27 Firmalice - Automatic Detection of Authentication Bypass Vulnerabilities in Binary Firmware](8.27_firmalice_bypass.md)
* [8.28 Cross-Architecture Bug Search in Binary Executables](8.28_cross_arch_bug_search.md)
* [8.29 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data](8.29_dynamic_hooks.md)
* [8.30 Preventing brute force attacks against stack canary protection on networking servers](8.30_prevent_brute_force_canary.md)

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
int main() {
void *x = malloc(10);
printf("malloc(10): %p\n", x);
free(x);
void *y = malloc(((size_t)~0) - 2); // overflow allocation (size_t.max-2)
printf("malloc(((size_t)~0) - 2): %p\n", y);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
The server runs on ubuntu/latest
to build the same version of ruby do the following steps:
git clone https://github.com/ruby/ruby.git
cd ruby
git checkout a5ec07c73fb667378ed617da6031381ee2d832b0
git apply ../sandbox_patch
autoconf
./configure
make install
mv LFA.so /usr/local/lib/ruby/site_ruby/2.4.0/x86_64-linux/LFA.so
then check that ruby 'sample.rb' runs properly (if you have ruby pre-installed on the machine check that you are running the right version of ruby)

Binary file not shown.

View File

@ -0,0 +1,9 @@
require 'LFA'
$arr = LFA.new
$arr[1] = 11
$arr[5] = 11
$arr[15000] = 11
puts $arr.sum

View File

@ -0,0 +1,433 @@
diff --git a/io.c b/io.c
index ee3ea3e68a..f53b4190cc 100644
--- a/io.c
+++ b/io.c
@@ -9388,6 +9388,419 @@ rb_io_fcntl(int argc, VALUE *argv, VALUE io)
#define rb_io_fcntl rb_f_notimplement
#endif
+
+/* ------------SECCOMP--------------- */
+
+
+#include <linux/seccomp.h>
+#include <linux/filter.h>
+#include <linux/unistd.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <err.h>
+
+
+
+#include <asm/bitsperlong.h> /* for __BITS_PER_LONG */
+#include <endian.h>
+#include <linux/filter.h>
+#include <linux/audit.h>
+#include <linux/seccomp.h> /* for seccomp_data */
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stddef.h>
+
+#define BPF_LABELS_MAX 256
+struct bpf_labels {
+ int count;
+ struct __bpf_label {
+ const char *label;
+ __u32 location;
+ } labels[BPF_LABELS_MAX];
+};
+
+
+#define JUMP_JT 0xff
+#define JUMP_JF 0xff
+#define LABEL_JT 0xfe
+#define LABEL_JF 0xfe
+
+#if defined(__i386__)
+# define REG_SYSCALL REG_EAX
+# define ARCH_NR AUDIT_ARCH_I386
+#elif defined(__x86_64__)
+# define REG_SYSCALL REG_RAX
+# define ARCH_NR AUDIT_ARCH_X86_64
+#else
+# warning "Platform does not support seccomp filter yet"
+# define REG_SYSCALL 0
+# define ARCH_NR 0
+#endif
+
+#define arch_nr (offsetof(struct seccomp_data, arch))
+
+#define VALIDATE_ARCHITECTURE \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
+
+
+#define ALLOW \
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+#define DENY \
+ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
+#define JUMP(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \
+ JUMP_JT, JUMP_JF)
+#define LABEL(labels, label) \
+ BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \
+ LABEL_JT, LABEL_JF)
+#define SECCOMP_SYSCALL(nr, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (nr), 0, 1), \
+ jt
+
+/* Lame, but just an example */
+#define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label)
+
+#define EXPAND(...) __VA_ARGS__
+
+/* Ensure that we load the logically correct offset. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#else
+#error "Unknown endianness"
+#endif
+
+/* Map all width-sensitive operations */
+#if __BITS_PER_LONG == 32
+
+#define JEQ(x, jt) JEQ32(x, EXPAND(jt))
+#define JNE(x, jt) JNE32(x, EXPAND(jt))
+#define JGT(x, jt) JGT32(x, EXPAND(jt))
+#define JLT(x, jt) JLT32(x, EXPAND(jt))
+#define JGE(x, jt) JGE32(x, EXPAND(jt))
+#define JLE(x, jt) JLE32(x, EXPAND(jt))
+#define JA(x, jt) JA32(x, EXPAND(jt))
+#define ARG(i) ARG_32(i)
+
+#elif __BITS_PER_LONG == 64
+
+/* Ensure that we load the logically correct offset. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ENDIAN(_lo, _hi) _lo, _hi
+#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define ENDIAN(_lo, _hi) _hi, _lo
+#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#endif
+
+union arg64 {
+ struct {
+ __u32 ENDIAN(lo32, hi32);
+ };
+ __u64 u64;
+};
+
+#define JEQ(x, jt) \
+ JEQ64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JGT(x, jt) \
+ JGT64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JGE(x, jt) \
+ JGE64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JNE(x, jt) \
+ JNE64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JLT(x, jt) \
+ JLT64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define JLE(x, jt) \
+ JLE64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+
+#define JA(x, jt) \
+ JA64(((union arg64){.u64 = (x)}).lo32, \
+ ((union arg64){.u64 = (x)}).hi32, \
+ EXPAND(jt))
+#define ARG(i) ARG_64(i)
+
+#else
+#error __BITS_PER_LONG value unusable.
+#endif
+
+/* Loads the arg into A */
+#define ARG_32(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx))
+
+/* Loads lo into M[0] and hi into M[1] and A */
+#define ARG_64(idx) \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \
+ BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, HI_ARG(idx)), \
+ BPF_STMT(BPF_ST, 1) /* hi -> M[1] */
+
+#define JEQ32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \
+ jt
+
+#define JNE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
+ jt
+
+#define JA32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
+ jt
+
+#define JGE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
+ jt
+
+#define JGT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+ jt
+
+#define JLE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
+ jt
+
+#define JLT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
+ jt
+
+/*
+ * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both
+ * A and M[1]. This invariant is kept by restoring A if necessary.
+ */
+#define JEQ64(lo, hi, jt) \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ /* if (lo != arg.lo) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JNE64(lo, hi, jt) \
+ /* if (hi != arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo != arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JA64(lo, hi, jt) \
+ /* if (hi & arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo & arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JGE64(lo, hi, jt) \
+ /* if (hi > arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo >= arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JGT64(lo, hi, jt) \
+ /* if (hi > arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo > arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JLE64(lo, hi, jt) \
+ /* if (hi < arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo <= arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JLT64(lo, hi, jt) \
+ /* if (hi < arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo < arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define LOAD_SYSCALL_NR \
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
+ offsetof(struct seccomp_data, nr))
+
+
+int bpf_resolve_jumps(struct bpf_labels *labels,
+ struct sock_filter *filter, size_t count)
+{
+ size_t i;
+
+ if (count < 1 || count > BPF_MAXINSNS)
+ return -1;
+ /*
+ * Walk it once, backwards, to build the label table and do fixups.
+ * Since backward jumps are disallowed by BPF, this is easy.
+ */
+ for (i = 0; i < count; ++i) {
+ size_t offset = count - i - 1;
+ struct sock_filter *instr = &filter[offset];
+ if (instr->code != (BPF_JMP+BPF_JA))
+ continue;
+ switch ((instr->jt<<8)|instr->jf) {
+ case (JUMP_JT<<8)|JUMP_JF:
+ if (labels->labels[instr->k].location == 0xffffffff) {
+ fprintf(stderr, "Unresolved label: '%s'\n",
+ labels->labels[instr->k].label);
+ return 1;
+ }
+ instr->k = labels->labels[instr->k].location -
+ (offset + 1);
+ instr->jt = 0;
+ instr->jf = 0;
+ continue;
+ case (LABEL_JT<<8)|LABEL_JF:
+ if (labels->labels[instr->k].location != 0xffffffff) {
+ fprintf(stderr, "Duplicate label use: '%s'\n",
+ labels->labels[instr->k].label);
+ return 1;
+ }
+ labels->labels[instr->k].location = offset;
+ instr->k = 0; /* fall through */
+ instr->jt = 0;
+ instr->jf = 0;
+ continue;
+ }
+ }
+ return 0;
+}
+
+/* Simple lookup table for labels. */
+__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label)
+{
+ struct __bpf_label *begin = labels->labels, *end;
+ int id;
+
+ if (labels->count == BPF_LABELS_MAX) {
+ fprintf(stderr, "Too many labels\n");
+ exit(1);
+ }
+ if (labels->count == 0) {
+ begin->label = label;
+ begin->location = 0xffffffff;
+ labels->count++;
+ return 0;
+ }
+ end = begin + labels->count;
+ for (id = 0; begin < end; ++begin, ++id) {
+ if (!strcmp(label, begin->label))
+ return id;
+ }
+ begin->label = label;
+ begin->location = 0xffffffff;
+ labels->count++;
+ return id;
+}
+
+void seccomp_bpf_print(struct sock_filter *filter, size_t count)
+{
+ struct sock_filter *end = filter + count;
+ for ( ; filter < end; ++filter)
+ printf("{ code=%u,jt=%u,jf=%u,k=%u },\n",
+ filter->code, filter->jt, filter->jf, filter->k);
+}
+
+void
+init_seccomp() {
+ struct bpf_labels l = {
+ .count = 0,
+ };
+ struct sock_filter filter[] = {
+ VALIDATE_ARCHITECTURE,
+ LOAD_SYSCALL_NR,
+ SECCOMP_SYSCALL(__NR_exit, ALLOW),
+ SECCOMP_SYSCALL(__NR_exit_group, ALLOW),
+ SECCOMP_SYSCALL(__NR_brk, ALLOW),
+ SECCOMP_SYSCALL(__NR_mmap, JUMP(&l, mmap)),
+ SECCOMP_SYSCALL(__NR_munmap, ALLOW),
+ SECCOMP_SYSCALL(__NR_mremap, ALLOW),
+ SECCOMP_SYSCALL(__NR_readv, ALLOW),
+ SECCOMP_SYSCALL(__NR_futex, ALLOW),
+ SECCOMP_SYSCALL(__NR_close, ALLOW),
+ SECCOMP_SYSCALL(__NR_write, JUMP(&l, write)),
+ SECCOMP_SYSCALL(__NR_rt_sigaction, ALLOW),
+ DENY,
+
+ LABEL(&l, mmap),
+ ARG(0),
+ JNE(0, DENY),
+ ARG(2),
+ JNE(PROT_READ|PROT_WRITE, DENY),
+ ARG(3),
+ JNE(MAP_PRIVATE|MAP_ANONYMOUS, DENY),
+ ARG(4),
+ JNE(-1, DENY),
+ ARG(5),
+ JNE(0, DENY),
+ ALLOW,
+
+ LABEL(&l, write),
+ ARG(0),
+ JEQ(STDOUT_FILENO, ALLOW),
+ JEQ(STDERR_FILENO, ALLOW),
+ DENY,
+ };
+ struct sock_fprog prog = {
+ .filter = filter,
+ .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
+ };
+ bpf_resolve_jumps(&l, filter, sizeof(filter)/sizeof(*filter));
+
+ if (syscall(__NR_prctl, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ err(1, "prctl(NO_NEW_PRIVS)");
+ }
+
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
+ err(1, "prctl(SECCOMP)");
+ }
+}
+
#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
/*
* call-seq:
@@ -9458,6 +9871,8 @@ rb_f_syscall(int argc, VALUE *argv)
#endif
int i;
+ init_seccomp();
+ return Qnil;
if (RTEST(ruby_verbose)) {
rb_warning("We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
}

View File

@ -0,0 +1,39 @@
#!/usr/bin/python
import tempfile
import os
import string
import random
def randstr():
return ''.join(random.choice(string.ascii_uppercase + string.digits + string.ascii_lowercase) for _ in range(10))
code = "require 'LFA'\n"
code += "syscall 1, 1, \"hello\\n\", 6\n\n"
max = 600 # 600 linex should be more than enough ;)
print "Enter your code, enter the string END_OF_PWN to finish "
while max:
new_code = raw_input("code> ")
if new_code == "END_OF_PWN":
break
code += new_code + "\n"
max -= 1
name = "/tmp/%s" % randstr()
with open(name, "w+") as f:
f.write(code)
flag = open("flag", "r")
os.dup2(flag.fileno(), 1023)
flag.close()
cmd = "timeout 40 ruby %s" % name
os.system(cmd)