HITCTF
入职前一天,增强来找我说是中心里组了只队要参加下HITCTF。正好无聊就跟着大家水了一把。
这里简单说下我做的几道题。
ROT
题目就给了一个 ip 和端口。nc 连上去以后返回一个老 jb 长的字符串(长相略像 base64 编码),最后一行有几个字符,“Answer:”,过了两秒以后连接自动断开了。 又连了几次,发现每次得到的 base64 字串都不一样,而且都是两秒后断开。 对该长字符串 Base64 解码,得到了一个 png 图,如下:
仔细观察一发。应该只要把相应的部位拼凑在一起就行。。。题目中不是也说rot90。。。
。。。。好了。。开始编码吧。。。。
import Image import socket import base64 import pytesser sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('41.231.53.40', 9090)) c = '' while True: t = sock.recv(100) c = c + t if len(t) < 100: break data = base64.decodestring(c[:-8]) open('t.png','wb').write(data) img = Image.new('RGB',(160,20)) out = img.load() pix = Image.open('t.png').load() for i in xrange(160): for j in xrange(20): if reduce(lambda x, y : x + y, pix[105 + j, 190 - i] + pix[94 - j, 9 + i]) < 1000: out[i, j] = (255, 255, 255) ans = pytesser.image_to_string(img) print ans sock.send(ans) print sock.recv(1024)
。。。运行后的结果如下。
pytesser的判断偶尔也会失误。。。提交个三四次。。。成功得到flag
RE10
把题目中给的文件下载下来。。。发现是个ELF文件
。运行了一下。。无限输出“baby crackme”。。。
扔ida里。
Main函数如下
.text:08048454 public main .text:08048454 main proc near ; DATA XREF: _start+17o .text:08048454 .text:08048454 arg_0 = dword ptr 8 .text:08048454 .text:08048454 push ebp .text:08048455 mov ebp, esp .text:08048457 and esp, 0FFFFFFF0h .text:0804845A sub esp, 10h .text:0804845D cmp [ebp+arg_0], 1 .text:08048461 jg short loc_8048471 .text:08048463 .text:08048463 loc_8048463: ; CODE XREF: main+1Bj .text:08048463 mov dword ptr [esp], offset s ; "Baby Crackme" .text:0804846A call _puts .text:0804846F jmp short loc_8048463 .text:08048471 ; --------------------------------------------------------------------------- .text:08048471 .text:08048471 loc_8048471: ; CODE XREF: main+Dj .text:08048471 mov dword ptr [esp], 47h ; c .text:08048478 call _putchar .text:0804847D mov dword ptr [esp], 30h ; c .text:08048484 call _putchar .text:08048489 mov dword ptr [esp], 30h ; c .text:08048490 call _putchar .text:08048495 mov dword ptr [esp], 64h ; c .text:0804849C call _putchar .text:080484A1 mov dword ptr [esp], 5Fh ; c .text:080484A8 call _putchar .text:080484AD mov dword ptr [esp], 42h ; c .text:080484B4 call _putchar .text:080484B9 mov dword ptr [esp], 30h ; c .text:080484C0 call _putchar .text:080484C5 mov eax, offset format ; "%c\n" .text:080484CA mov dword ptr [esp+4], 79h .text:080484D2 mov [esp], eax ; format .text:080484D5 call _printf .text:080484DA mov eax, 0 .text:080484DF leave .text:080484E0 retn .text:080484E0 main endp
逆一下。。。
int __cdecl main(signed int argc) { if ( argc <= 1 ) { while ( 1 ) puts("Baby Crackme"); } putchar('G'); putchar('0'); putchar('0'); putchar('d'); putchar('_'); putchar('B'); putchar('0'); printf("%c\n", 'y'); return 0; }
。。这里判断命令行参数个数。。。无参数的话就无循环。。随便加个参数就输出 G00d_B0y。。。。这是个啥东西。。莫非是flag?不要吓我。。。这么简单。后来又看了下题目。只有10分,弱弱的一试。还真是flag
Linux Kernel
下载题目中给出的文件。。。先跑下。。。segment fault、。。。ida调试刚连上去就自己断开。咋回事?到最后都没搞明白。。。
直接扔ida里开始逆吧。。。
从启动函数开始看,一路设置GDT,IDT,IRQ。。。然后开个定时器,主线程就结束了。。。。没发现啥和flag有关的。。。。把定时器翻出来看看,代码如下:
.text:00100958 public timer_tick .text:00100958 timer_tick proc near ; DATA XREF: timer_init+3o .text:00100958 sub esp, 14h .text:0010095B mov eax, ds:1060C0h .text:00100960 lea edx, [eax+1] .text:00100963 mov ds:1060C0h, edx .text:00100969 push eax .text:0010096A push offset aDTick__ ; "%d Tick..\n" .text:0010096F call printf .text:00100974 movzx ecx, byte ptr ds:1060C0h .text:0010097B add esp, 10h .text:0010097E mov eax, 0 .text:00100983 .text:00100983 loc_100983: ; CODE XREF: timer_tick+42j .text:00100983 mov edx, ecx .text:00100985 xor dl, byte ptr ds:flag[eax] .text:0010098B add edx, 1 .text:0010098E mov byte ptr ds:flag[eax], dl .text:00100994 add eax, 1 .text:00100997 cmp eax, 28h .text:0010099A jnz short loc_100983 .text:0010099C add esp, 0Ch .text:0010099F retn .text:0010099F timer_tick endp
。。。。。。。用IDA来F5一下。。。。
int __cdecl timer_tick() { char tick; // cl@1 int i; // eax@1 ++*(_DWORD *)&idt[128]; // int x = idt[128] + 1 printf("%d Tick..\n"); tick = idt[128]; i = 0; do { flag[i] = (flag[i] ^ tick) + 1; ++i; } while ( i != 40 ); return i; }
出现这样的代码。。。。不知道这里是IDA脑抽了还是我的智商太低理解不了。。ida的地址是106140h居然把1060C0h翻译成了&idt[128]。。不应该是&idt[-128]么。。
害我还跟踪了半天的idt[128]。。。结果一无所获。。。。
。。。郁闷。这个值到底咋计算出来了。。。。把程序看了好几遍依然没看出来。。。
之后灵光一闪。。。发现了一个比较蛋疼的办法。。
这里的flag只和tick进行运算。。。而tick是个char。。。也就是说现在flag可能的取值一共有256种。。。。
那就爆破吧。。。。程序如下
#include <stdio.h> #include <string.h> int f(char b[]) { for (int i = 0;i < strlen(b);i++) { if ((int)b[i] < 0x10 || (int)b[i] > 0x80) { return 0; } } return 1; } int main(int argc, char* argv[]) { int i, j; char s[] = { 0x49, 0x74, 0x6F, 0x66, 0x72, 0x6A, 0x78, 0x62, 0x32, 0x60, 0x2E, 0x2E, 0x63, 0x2E, 0x32, 0x2E, 0x36, 0x30, 0x33, 0x31, 0x5D, 0x67, 0x36, 0x62, 0x31, 0x67, 0x67, 0x30, 0x5E, 0x29, 0x62, 0x31, 0x31, 0x63, 0x62, 0x5E, 0x5E, 0x2D, 0x5D, 0x7A, 0x00}; char d[100]; for (i = 0;i < 255;i++) { for (j = 0;j < strlen(s);j++) { d[j] = ((int)s[j] ^ i) + 1; } for (j = 0;j < strlen(s);j++) { d[j] = ((int)d[j] ^ (i + 1)) + 1; } for (j = 0;j < strlen(s);j++) { d[j] = ((int)d[j] ^ (i + 2)) + 1; } d[j] = 0; if (f(d)) { printf("%s\n", d); } } return 0; }
编译。。。运行。。。
结果如下
crackme
。。。题目忘了叫啥了。。。三百分的一个题。。感觉这个题分给高了。200分差不多。。。
题目中给了个地址。http://41.231.53.44:9393/。。。访问下。。下载到一个文件。。。
打开看看。。
文件头是个lpck。。。不知道啥格式。。。不过在之后看到了MZ头。。。把MZ头之前的部分统统删掉。。。成功得到一个exe
。。。。password是啥。。我哪知道。。。直接扔进ida….找到关键部分如下:
.text:00401363 mov [esp+5Ch+var_5C], offset aPassword ; "Password :" .text:0040136A call puts .text:0040136F lea eax, [esp+5Ch+var_3E] .text:00401373 mov [esp+5Ch+var_58], eax .text:00401377 mov [esp+5Ch+var_5C], offset aS ; "%s" .text:0040137E call scanf .text:00401383 mov [esp+5Ch+var_14], 0 .text:0040138B jmp short loc_4013B1 .text:0040138D ; --------------------------------------------------------------------------- .text:0040138D .text:0040138D loc_40138D: ; CODE XREF: main+8Fj .text:0040138D mov eax, [esp+5Ch+var_14] .text:00401391 mov eax, [esp+eax*4+5Ch+var_34] .text:00401395 mov ecx, eax .text:00401397 xor ecx, 1 .text:0040139A lea edx, [esp+5Ch+var_3E] .text:0040139E mov eax, [esp+5Ch+var_14] .text:004013A2 add eax, edx .text:004013A4 mov al, [eax] .text:004013A6 movsx eax, al .text:004013A9 cmp ecx, eax .text:004013AB jnz short loc_4013C7 .text:004013AD inc [esp+5Ch+var_14] .text:004013B1 .text:004013B1 loc_4013B1: ; CODE XREF: main+57j .text:004013B1 mov ebx, [esp+5Ch+var_14] .text:004013B5 lea eax, [esp+5Ch+var_3E] .text:004013B9 mov [esp+5Ch+var_5C], eax .text:004013BC call strlen .text:004013C1 cmp ebx, eax .text:004013C3 jb short loc_40138D .text:004013C5 jmp short loc_4013C8 .text:004013C7 ; --------------------------------------------------------------------------- .text:004013C7 .text:004013C7 loc_4013C7: ; CODE XREF: main+77j .text:004013C7 nop .text:004013C8 .text:004013C8 loc_4013C8: ; CODE XREF: main+91j .text:004013C8 lea eax, [esp+5Ch+var_3E] .text:004013CC mov [esp+5Ch+var_5C], eax .text:004013CF call strlen .text:004013D4 cmp eax, 8 .text:004013D7 jnz short loc_4013E8 .text:004013D9 cmp [esp+5Ch+var_14], 8 .text:004013DE jnz short loc_4013E8 .text:004013E0 mov [esp+5Ch+var_10], 1 .text:004013E8 .text:004013E8 loc_4013E8: ; CODE XREF: main+A3j .text:004013E8 ; main+AAj .text:004013E8 cmp [esp+5Ch+var_10], 1 .text:004013ED jnz short loc_4013FD .text:004013EF mov [esp+5Ch+var_5C], offset aGoodBoySendTha ; "Good Boy ! Send That pass to server to "... .text:004013F6 call printf .text:004013FB jmp short loc_401409 .text:004013FD ; --------------------------------------------------------------------------- .text:004013FD .text:004013FD loc_4013FD: ; CODE XREF: main+B9j .text:004013FD mov [esp+5Ch+var_5C], offset aSorryIncorrect ; "Sorry ! Incorrect pass" .text:00401404 call printf
大概理解一下。。这里输入的字符串为8个字符…然后以esp+5Ch+var_34为地址之后的8个DWORD,取低8位字符,然后都xor 1。。。结果与输入的串比较。。相等刚正确。。
来看看esp+5Ch+var_34的数据怎么得到的
.text:00401345 lea edx, [esp+5Ch+var_34] .text:00401349 mov ebx, 402000h .text:0040134E mov eax, 8 .text:00401353 mov edi, edx .text:00401355 mov esi, ebx .text:00401357 mov ecx, eax .text:00401359 rep movsd
..看样子是从402000h复制过来的啊。。。跟过去看看…
…看样子把这些东西xor 1一下就可以得到password了。。。拿到key以后提交上去。。。结果。。”Too late”…好吧。人家要求两秒种之内。。。
那就把VA转换成文件便宜。。。得到0x1310。。。。写个脚本自动破解吧。。
import requests cookie = {'symfony':'1gc3ucf1kdqqgjeoektjd04703','PHPSESSID':'hql5vuag24tq3vllehoe9r5kg0'} r = requests.get('http://41.231.53.44:9393/', cookies=cookie) print r s = str(r.content[0x1310:0x1330]) k = '' for i in range(0x20): if i % 4 == 0: k = k + chr(ord(s[i]) ^ 1) print k r1 = requests.get('http://41.231.53.44:9393/check.php?p=' + k, cookies=cookie) print r1 print r1.content
2014年12月12日 01:16
好厉害,脚本都是python写的么,汇编好牛
2019年11月02日 01:01
Your dirty house is actually a sanctuary for an array of uncontrollable terrible bacteria plus viruses. The extra dirt plus dust this passes through the home from the doors and windows, the extra expected you're letting around unwanted germs and terrible bacteria. While an easy surface get rid of might keep several of the lesser bugs away, it is simply through your deep cleaning that you may really get rid of and get rid of the bigger terrible germs this skulk underneath the surface. At SpringCLeaning Expert services Dubai most people aid all of our customers to achieve the core of their total deep cleaning up issues resolved by presenting professional, quality profound cleaning expert services in Dubai as well as surrounding spots.