Не так давно на небезызвестном www.xakep.ru была устроена очередная развлекуха под названием Головоломка для хакера №7: КОНКУРС. Цель оного действа - побуждение ксакепов к решению некоторых задач, требующих некоторой работы мозгов и получение за это некоторой денежной суммы, а также всяческих почестей и уважения в глазах соксакеповцев. Однако, такая безусловно нужная и полезная идея не нашла поддержки в народных массах. Далее будут изложены некоторые мои соображения по поводу задач (точнее их решения), прочитав которые даже самый ксакеповский ксакеп будет способен хоть что-то решить. Сразу хочу сказать что все нижеизложенное всего лишь мое humble opinion, и вся неконструктивная критика идет на /dev/null, все остальное можно вываливать на ксакеповский "форум". Крики типа "а чего ты такой умный, а 10 9 8 7 ... пункты не решил?" идут вместе с критикой.
В условии заявлено, что задачи идут по убыванию их сложности и я почему-то склонен поверить автору. В связи с этим печальным фактом решать задачи мы начнем с 10 и плааавно закончим на 1.
Quote: В основе smurf-атаки - отправка пакетов на широковешательные адреса. Как отличить широковещательный адрес от "нешироковещательного"?
Тут я начал понимать задумку автора. Если такой вопрос будет первым, и его увидит какой-нибудь нормальный человек, то читать задания дальше просто не будет. Respect автору.
Netmask address = 255.255.255.0
Some address = 1.1.0.255
host | mask = 00000001 00000001 00000000 11111111 | 11111111 11111111 11111111 00000000 = 11111111 11111111 11111111 11111111 = broadcast.
Quote: Известно, что функция crypt(variabla,"salt") из *никсовой библиотеки crypt возвращает значение "saeNMv4rNf6.E". Найдите variabla
It's DES, baby. Функция возвращает хеш-образ последовательности символов, salt это двухсимвольная константа, которая позволяет получить (теоретически) 4096 различных хеш образов на каждую символьную последовательность. Да, чуть не забыл... макс. длина последовательности - 8 байт. Прямой реверс этой функции невозможен, однако в связи с ее популярностью существует довольно много брутфорсеров, например crack или John the Ripper. Воспользуемся вторым... Для работы понадобится файл похожий на /etc/passwd с одним абстрактным пользователем и нашей строкой "saeNMv4rNf6.E" в качестве хеша от пароля. После всех мучений должно получиться что variabla = "magazine".
Quote: Реверс для начинающих. Определите "серийник" для sample1.exe
Reverse? Who said reverse? Назвать это творение "crackme" язык просто не поворачивается. Для нахождения процедуры обработки нажатия на "Ok" можно обойтись вообще без отладчика (любители могут заняться bpx GetDlgItemTextA & bpx GetWindowTextA). Предположим, что найти обработчик сможет каждый и глянем что же там интересного. Могу заранее расстроить - ничего.
Неинтересное начало поскипано... CODE:00450275 call @TControl@GetText ; TControl::GetText CODE:0045027A mov eax, [ebp+Serial_txt] CODE:0045027D call @StrToInt CODE:00450282 mov [ebp+Serial_num], eax CODE:00450285 xor eax, eax CODE:00450287 pop edx CODE:00450288 pop ecx CODE:00450289 pop ecx CODE:0045028A mov fs:[eax], edx CODE:0045028D jmp short Code_start CODE:0045028F ; --------------------------------------------------------------------------- CODE:0045028F CODE:0045028F loc_45028F: ; DATA XREF: sub_450238+29 CODE:0045028F jmp loc_403980 CODE:00450294 ; --------------------------------------------------------------------------- CODE:00450294 call sub_403CE8 CODE:00450299 CODE:00450299 Code_start: ; CODE XREF: sub_450238+55 CODE:00450299 ; DATA XREF: sub_450238+61 ... CODE:00450299 mov [ebp+Code_start_ofs], offset Code_start CODE:004502A0 mov eax, offset Code_end CODE:004502A5 sub eax, offset Code_start CODE:004502AA mov [ebp+Code_lengh], eax CODE:004502AD xor ebx, ebx CODE:004502AF mov eax, [ebp+Code_lengh] CODE:004502B2 test eax, eax CODE:004502B4 jl short Code_zero_lengh CODE:004502B6 inc eax CODE:004502B7 xor edx, edx CODE:004502B9 CODE:004502B9 Calculate: ; CODE XREF: sub_450238+8C CODE:004502B9 mov ecx, [ebp+Code_start_ofs] CODE:004502BC movzx ecx, byte ptr [ecx+edx] CODE:004502C0 add ebx, ecx CODE:004502C2 inc edx CODE:004502C3 dec eax CODE:004502C4 jnz short Calculate CODE:004502C6 CODE:004502C6 Code_zero_lengh: ; CODE XREF: sub_450238+7C CODE:004502C6 mov eax, [ebp+Serial_num] CODE:004502C9 xor eax, 0Ah CODE:004502CC cmp ebx, eax CODE:004502CE jnz short Code_end CODE:004502D0 lea edx, [ebp+var_14] CODE:004502D3 mov eax, ebx CODE:004502D5 call @Sysutils@IntToStr$qqri ; Sysutils::IntToStr(int) CODE:004502DA mov edx, [ebp+var_14] CODE:004502DD mov eax, ds:dword_452C1C CODE:004502E2 call @Controls@TControl@SetText$qqrx17System@AnsiString ; Controls::TControl::SetText(System::AnsiString) CODE:004502E7 mov eax, ds:dword_452C1C CODE:004502EC call sub_44B824 CODE:004502F1 mov eax, ds:off_451EF4 CODE:004502F6 mov eax, [eax] CODE:004502F8 call @TCustomForm@Show ; TCustomForm::Show CODE:004502FD CODE:004502FD Code_end: ; CODE XREF: sub_450238+96 CODE:004502FD ; DATA XREF: sub_450238+68 CODE:004502FD xor eax, eax CODE:004502FF pop edx CODE:00450300 pop ecx CODE:00450301 pop ecx CODE:00450302 mov fs:[eax], edx CODE:00450305 push offset loc_450322 Не менее неинтересный конец тоже...Serial из строкового представления преобразуется в число. По умолчанию считается, что система счисления - десятичная. Далее начинаем считать "правильный" serial number. Делается это в цикле Calculate (004502B9 - 004502C4) путем накапливания суммы всех байт начиная с адреса 00450299 и заканчивая 004502FD (Code_start и Code_end соответственно). Полученная сумма сравнивается с Serial xor 0xA. При совпадении - решается что Serial правильный.
serial xor 0xA = magic => serial xor 0xA xor 0xA = magic xor 0xA => serial = magic xor 0xAДетский сад. Счастливые обладатели softice могут запустить sample1.exe, написать "addr sample1" и "bpx 4502CC". После чего ввести что угодно в поле серийника и давануть "Ok". В вылетевшем айсе делается "? ebx ^ 0A" и серийник готов - 12868.
Quote: 7. Для прохождения пятого уровня NG Security Game не обязательно знать логины и пароли, находящиеся в таблице. Однако, существует способ узнать их. Определите, сколько именно логинов и паролей в таблице и перечислите их.
К величайшему сожалению автор забыл оставить ссылку на творение человечества под названием NG Security Game. Возможно оное творение упоминалось в каком-либо выпуске "хацкера", но не все же его читают... Ужасно огорчившись переходим к следующему пункту.Quote: Немного теории. Автор одной из статей про DNS-spoofing пишет: "мне достаточно нескольких минут, чтобы определить все DNS-сервера, используемые любым IRCd, и я - не единственный человек, кто может сделать это". Опишите, кто эти "избранные" и как выглядит способ, о котором говорит автор?
Quote: Немного дикой практики. Опишите атаку, позволяющую заблокировать получение почты через POP3 из любого ящика на mail.ru (при этом остальные ящики должны работать нормально). Hint: создатели системы уверены, что это не бага, а фича.
Не интересно. Копание на форуме в поисках ответа на 5-й вопрос или игра в гадалку для ответа на 6-й (способов этих туева хуча).
Quote: Почувствуйте себя Касперским :) Напишите ядро программы (все, кроме базы сигнатур), проверяющей содержимое почтового ящика через POP3, находящей (по сигнатуре) в ящике зараженные вирусами письма и удаляющей их.
"Пойди туда, не знаю куда... напиши то, не знаю что...". Задача задана весьма абстрактно (или это называется свобода выражения?). Не определены ни язык, на котором это предстоит написать, ни платформа... В таком случае пойдем самым легким путем:
#!/usr/bin/perl -w use Mail::POP3Client; $user = "someone"; $password = "who cares?"; $host = "pop3.host.domain.com"; printf("POP3 mail checker\n"); $pop = new Mail::POP3Client( USER => $user, PASSWORD => $password, HOST => $host ); open(SIGN, "sign") || die "could not open signature file\n"; @sign =Прямолинейно, примитивно и очень просто. Тем не менее это чудо техники работает и исправно ищет и удалят из ящика те самые зараженные файлы. Комментировать тут собственно нечего... все желающие идут и читают умные книжки про perl.; print "Found " . $pop->Count() . " messages in the mailbox...\n"; for( $i = 1; $i <= $pop->Count(); $i++ ) { foreach( $pop->HeadAndBody( $i ) ) { /^(From|Subject):\s+/i && print $_, "\n"; for ($j = 0; $j < @sign; $j++) { chomp $sign[ $j ]; if (/$sign[ $j ]/) { print "signature matched: \"$sign[ $j ]\", deleting message\n"; $pop->Delete( $i ); } } } } $pop->Close();
Quote: Создание remote shell exploit. На хосте 195.209.178.41, порт 4050, находится самописный дырявый "сервис". Исходник и бинарник - не дадим :) OS - Linux, kernel 2.2.
Требует слишком долгого сидения в онлайне (пока это невозможно). В условии ясно сказано, что опять намечается игра в гадалку (это также означает, уязвимость скорее всего - элементарное переполнение при вводе чего-то-там-слишком-длинного). "Rest for now" (c). Возможно поковыряюсь (если будет возможность и желающие что-то послушать по этому поводу).
Quote: Опять RE, но под win32. Из бинарника sample1.exe восстановите исходный код программы (Delphi 6).
I asked, WHO THE HELL SAID "REVERSING"? Возвращаемся к нашим баранам... точнее барану (это не автору). Немного непонятно чего хочет автор. Абсолютно точно восстановить код невозможно, это знают даже вышеупомянутые бараны. Имена переменных (как и некоторые другие вкусности) для нас безвозвратно потеряны. Возможно это своего рода проверка "а можешь ли ты, уважаемый ксакеп реализовать такой подсчет правильного серийника?". Напомню, что серийник считается как сумма байт куска кода программы. Еще можно понять задачу "получить программу, которая ведет себя так же как и sample1.exe, и показать ее исходник". После пояснения (желательно автором) я к этому пункту обязательно вернусь.
Quote: Reverse Engeneering. Дана игра "Тетрис" под Linux, ELF-файл. Для тех, кто хочет в нее поиграть - кнопки управления - a,s,d,f, пробел ;) Остальным - задача пропатчить ее так, чтобы в игре была менюшка с пунктами "сохранить игру" и "загрузить игру".
ELF is magic (c). Единственное более-менее интересное задание (или все-таки менее?). К сожалению формулировка тоже не лишена некоторых неточностей. Например:
$ readelf -l tetris Elf file type is EXEC (Executable file) Entry point 0x80489c0 There are 6 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4 INTERP 0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x01ac2 0x01ac2 R E 0x1000 LOAD 0x001ac4 0x0804aac4 0x0804aac4 0x00144 0x00544 RW 0x1000 DYNAMIC 0x001b60 0x0804ab60 0x0804ab60 0x000a8 0x000a8 RW 0x4 NOTE 0x000108 0x08048108 0x08048108 0x00020 0x00020 R 0x4 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.got .rel.bss .rel.plt .init .plt .text .fini .rodata 03 .data .eh_frame .ctors .dtors .got .dynamic .bss 04 .dynamic 05 .note.ABI-tagЗабавно. Шестой сегмент типа NOTE содержит пачку магических чисел и 3 буквы "G", "N" и "U" идущие подряд. Похоже на что-то, правда? Никакой информации необходимой для работы программы там не содержится. План действий: дописать нужный нам код в конец файла, поправить шестой сегмент. В сегменте необходимо исправить: offset должен быть равен смещению нашего кода в файле (т.е. original file length), тип LOAD (мы же хотим чтобы нас загрузили), VirtAddr&PhysAddr - куда-нибудь ниже адреса с которого начнет грузиться программа. Лирическое Отступление: все ELF файлы cлинкованные ld c установками по умолчанию начинают грузиться с адреса 0x8048000, FileSiz&MemSiz должны быть равны размеру нашего кода, флаги R W E (что означает Read, Write, Execute). So? Let's rock.. Для совершения вышеописанных манипуляций с файлом можно воспользоваться чем угодно. Я решил написать простенькую программу.
#include#include #include #include #include int main() { Elf32_Ehdr *pELF; Elf32_Phdr *note, *code; char file[100000], our_code[100000]; int fd = open("tetris", O_RDONLY); int size = read(fd, file, sizeof(file)); int fd1 = open("_code_", O_RDONLY); int our_size = read(fd1, our_code, sizeof(our_code)); pELF = (Elf32_Ehdr *)file; printf("entry point is at 0x%x\n", pELF->e_entry); note = (Elf32_Phdr *)((int)file + sizeof(Elf32_Phdr) * 5 + pELF->e_phoff); code = (Elf32_Phdr *)((int)file + sizeof(Elf32_Phdr) * 2 + pELF->e_phoff); if (code->p_type != PT_LOAD) { return 1; } if (note->p_type == PT_NOTE) { printf("found note...\n"); note->p_type = PT_LOAD; code->p_flags |=