Kompilací zdrojového kódu vznikne binární soubor. Během kompilace můžete kompilátoru poskytnout příznaky pro povolení nebo zakázání určitých vlastností binárního souboru. Některé z těchto vlastností jsou relevantní pro zabezpečení.
Checksec je šikovný malý nástroj (a skript shellu), který kromě jiných funkcí identifikuje vlastnosti zabezpečení, které byly zabudovány do binárního souboru při jeho kompilaci. Kompilátor může ve výchozím nastavení povolit některé z těchto vlastností a možná budete muset poskytnout specifické příznaky, abyste povolili ostatní.
Tento článek vysvětluje, jak použít checksec k identifikaci vlastností zabezpečení binárního souboru, včetně:
- Základní příkazy, které checksec používá k vyhledání informací o vlastnostech zabezpečení
- Jak povolit vlastnosti zabezpečení pomocí GNU Compiler Collection (GCC) při kompilaci ukázkového binárního souboru
Instalovat checksec
Chcete-li nainstalovat checksec na Fedoru a další systémy založené na RPM, použijte:
$ sudo dnf install checksec
Pro distribuce založené na Debianu použijte ekvivalentní apt
příkaz.
Skript prostředí
Checksec je jednosouborový shell skript, i když poměrně velký. Výhodou je, že si můžete skript rychle přečíst a porozumět všem spuštěným systémovým příkazům, abyste našli informace o binárních nebo spustitelných souborech:
$ soubor /usr/bin/checksec
/usr/bin/checksec:Shell skript Bourne-Again, spustitelný text ASCII, s velmi dlouhými řádky
$ wc -l /usr /bin/checksec
2111 /usr/bin/checksec
Proveďte checksec pro jednotku s binárním souborem, který pravděpodobně používáte denně:všudypřítomný ls
příkaz. Formát příkazu je checksec --file=
následuje absolutní cesta k ls
binární:
$ CheckSec --file =/ usr / bin / ls
Relro zásobník symboly nx pie rath rathath symboly opevněné opevněné opevněné opevněné canary counters counters opevněný canary nalezeno nx enabled pie? 5 17 /usr/bin/ls
Když to spustíte v terminálu, uvidíte barevné kódování, které ukazuje, co je dobré a co pravděpodobně ne. Říkám „pravděpodobně“, protože i když je něco červeně, nemusí to nutně znamenat, že jsou věci hrozné – může to znamenat, že prodejci distribucí udělali určité kompromisy při kompilaci binárních souborů.
První řádek poskytuje různé vlastnosti zabezpečení, které jsou obvykle dostupné pro binární soubory, jako je RELRO
, STACK CANARY
, NX
, a tak dále (podrobně vysvětluji níže). Druhý řádek zobrazuje stav těchto vlastností pro daný binární soubor (ls
, v tomto případě). Například NX enabled
znamená, že pro tento binární soubor je povolena nějaká vlastnost.
Ukázkový binární soubor
Pro tento tutoriál použiji následující program „hello world“ jako ukázkový binární soubor.
#include
int main()
{
printf("Hello World\n");
return 0;
}
Všimněte si, že jsem neuvedl gcc
se všemi dalšími příznaky během kompilace:
$ gcc hello.c -o hello
$ file hello
ahoj:ELF 64bitový LSB spustitelný soubor, x86-64, verze 1 (SYSV), dynamicky propojený, interpret / lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pro GNU/Linux 3.2.0, neodstraněno
$ ./Ahoj světe /před>Spusťte binární soubor přes checksec. Některé vlastnosti jsou jiné než u
ls
příkaz výše (na vaší obrazovce se mohou zobrazit červeně):$ CheckSec --file =. / hello
Relro stack Symboly NX Pie rath rathpath symboly opevněné opevněné opevněné opevněné řízený soubor
částečné relro žádné kanárky nalezeno nx enabled no pie no rath no rutpath 85) symboly č. 0 0./ahoj
$Změna výstupního formátu
Checksec umožňuje různé výstupní formáty, které můžete určit pomocí
--output
. Vyberu si formát JSON a výstup nasměruji dojq
nástroj pro pěkný tisk.Chcete-li pokračovat, ujistěte se, že máte
jq
nainstalován, protože tento tutoriál používá tento výstupní formát k rychlému vyhledání konkrétních vlastností z výstupu a hlášeníyes
nebono
na každém:$ checksec --file=./hello --output=json | jq
{
"./hello":{
"relro":"částečné",
"kanár":"ne",
"nx":" ano",
"koláč":"ne",
"rpath":"ne",
"runpath":"no",
"symboly":"ano" ,
"fortify_source":"no",
"fortified":"0",
"fortify-able":"0"
}
}Procházení vlastnostmi zabezpečení
Více o zabezpečení
- Průvodce obranným kódováním
- Webinář:Automatizace zabezpečení systému a soulad se standardním operačním systémem
- 10 vrstev zabezpečení kontejneru Linux
- Omalovánky SELinux
- Další články o zabezpečení
Výše uvedený binární soubor obsahuje několik bezpečnostních vlastností. Porovnám to binární s ls
binární výše, abyste prozkoumali, co je povoleno, a vysvětlili, jak checksec tyto informace našel.
1. Symboly
Začnu nejprve tím jednodušším. Během kompilace jsou do binárního souboru zahrnuty určité symboly, většinou pro ladění. Tyto symboly jsou vyžadovány při vývoji softwaru a vyžadují několik cyklů pro ladění a opravy věcí.
Tyto symboly jsou obvykle odstraněny (odstraněny) z konečného binárního souboru předtím, než je uvolněn pro obecné použití. To nijak neovlivňuje provádění binárního souboru; poběží stejně jako se symboly. Odstraňování se často provádí za účelem úspory místa, protože binární kód je po odstranění symbolů poněkud světlejší. V uzavřeném zdrojovém nebo proprietárním softwaru jsou symboly často odstraněny, protože pokud jsou tyto symboly v binární podobě, je poněkud snadné odvodit vnitřní fungování softwaru.
Podle checksec jsou v tomto binárním souboru přítomny symboly, ale nebyly v ls
binární. Tyto informace můžete také najít spuštěním file
příkaz v programu – vidíte not stripped
ve výstupu ke konci:
$ checksec --file=/bin/ls --output=json | jq | grep symbols
"symbols":"no",
$ checksec --file=./hello --output=json | jq | grep symbols
"symbols":"yes",
$ file ahoj
ahoj:ELF 64bitový LSB spustitelný soubor, x86-64, verze 1 (SYSV), dynamicky propojený , interpret /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pro GNU/Linux 3.2.0, neodstraněno
Jak checksec našel tyto informace? Poskytuje praktický --debug
možnost zobrazit, které funkce byly spuštěny. Spuštění následujícího příkazu by vám proto mělo ukázat, které funkce byly spuštěny v rámci skriptu shellu:
$ checksec --debug --file=./hello
V tomto tutoriálu hledám základní příkazy používané k nalezení těchto informací. Vzhledem k tomu, že se jedná o skript Shell, můžete vždy využít funkce Bash. Tento příkaz vypíše každý příkaz, který byl spuštěn ze skriptu shellu:
$ bash -x /usr/bin/checksec --file=./hello
Pokud procházíte výstupem, měli byste vidět echo_message
následuje kategorie bezpečnostní vlastnosti. Zde je to, co checksec hlásí o tom, zda binární soubor obsahuje symboly:
+ readelf -W --symbols ./hello
+ grep -q '\.symtab'
+ echo_message '\033[31m96) Symbols\t\033[m ' Symboly, ' symboly ="yes"' '"symbols":"yes",'
Pro zjednodušení používá checksec readelf
nástroj pro čtení binárního kódu a poskytuje speciální --symbols
příznak, který uvádí všechny symboly v binárním systému. Poté hledá speciální hodnotu, .symtab
, který poskytuje počet záznamů (symbolov), které najde. Můžete vyzkoušet následující příkazy na testovacím binárním souboru, který jste zkompilovali výše:
$ readelf -W --symbols ./ahoj
$ readelf -W --symbols ./hello | grep -i symtab
Jak odstranit symboly
Symboly můžete odstranit po kompilaci nebo během kompilace.
- Kompilace příspěvku: Po kompilaci můžete použít
strip
nástroj na binární k odstranění symbolů. Pomocífile
potvrďte, že to fungovalo příkaz, který nyní zobrazuje výstup jakostripped
:$ gcc hello.c -o hello
$
$ file hello
ahoj:ELF 64bitový LSB spustitelný soubor, x86-64, verze 1 (SYSV) , dynamicky propojený, interpret /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, pro GNU/Linux>$ 3.2.0, nezbaveno
$ br />$
$ soubor ahoj
ahoj:ELF 64bitový LSB spustitelný soubor, x86-64, verze 1 (SYSV), dynamicky propojený, interpret /lib64/ld-linux-x86-64.so .2, BuildID[sha1]=322037496cf6a2029dcdcf68649a4ebc63780138, pro GNU/Linux 3.2.0, zbaveno
$
Jak odstranit symboly během kompilace
Místo ručního odstraňování symbolů po kompilaci můžete požádat kompilátor, aby to udělal za vás zadáním -s
argument:
$ gcc -s ahoj.c -o ahoj
$
$ soubor ahoj
ahoj:ELF 64bitový spustitelný soubor LSB, x86-64, verze 1 (SYSV), dynamicky propojený , interpret /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=247de82a8ad84e7d8f20751ce79ea9e0cf4bd263, pro GNU/Linux 3.2.0, zbavený
$
Po opětovném spuštění checksec uvidíte, že symbols
jsou zobrazeny jako no
:
$ checksec --file=./hello --output=json | jq | grep symbols
"symbols":"no",
$
2. Kanár
Canaries jsou známé hodnoty, které jsou umístěny mezi vyrovnávací pamětí a kontrolními daty v zásobníku ke sledování přetečení vyrovnávací paměti. Když se aplikace spustí, jsou jí přiřazeny dva druhy paměti. Jedním z nich je zásobník , což je jednoduše datová struktura se dvěma operacemi:push
, který ukládá data do zásobníku, a pop
, který odebírá data ze zásobníku v opačném pořadí. Škodlivý vstup by mohl přetéct nebo poškodit zásobník speciálně vytvořeným vstupem a způsobit selhání programu:
$ checksec --file=/bin/ls --output=json | jq | grep canary
"canary":"ano",
$
$ checksec --file=./hello --output=json | jq | grep canary
"canary":"ne",
$
Jak checksec zjistí, zda je binární soubor povolen s kanárkem? Pomocí výše uvedené metody jej můžete zúžit spuštěním následujícího příkazu v rámci skriptu shellu:
$ readelf -W -s ./hello | grep -E '__stack_chk_fail|__intel_security_cookie'
Povolit canary
K ochraně před těmito případy kompilátor poskytuje -stack-protector-all
příznak, který přidá do binárního souboru další kód pro kontrolu takového přetečení vyrovnávací paměti:
$ gcc -fstack-protector-all hello.c -o hello
$ checksec --file=./hello --output=json | jq | grep canary
"canary":"ano",
Checksec ukazuje, že vlastnost je nyní povolena. Můžete to také ověřit pomocí:
$ readelf -W -s ./ahoj | grep -e '__stack_chk_fail | __intel_security_ChOokie'
2:0000000000000000 0 func globální default und __stack_chk_fail@glubc_2.4 (3)
83:000000000000000000 0
83:000000000000000000 0
83:000000000000000000 0
Func Global Default und __stack_chk_fail @@ glibc_2.4
$
3. KORÁČ
PIE znamená spustitelný soubor nezávislý na pozici. Jak název napovídá, je to kód, který je umístěn někde v paměti pro provedení bez ohledu na jeho absolutní adresu:
$ checksec --file=/bin/ls --output=json | jq | grep pie
"koláč":"ano",
$ checksec --file=./hello --output=json | jq | grep pie
"koláč":"ne",
PIE je často povolen pouze pro knihovny a nikoli pro samostatné programy příkazového řádku. Ve výstupu níže hello
je zobrazen jako LSB executable
, zatímco libc
standardní knihovna (.so
) je soubor označen jako LSB shared object
:
$ file ahoj
ahoj:ELF 64-bit LSB spustitelný, x86-64, verze 1 (SYSV), dynamicky propojený, interpret /lib64/ld-linux-x86-64.so.2, BuildID[ sha1]=014b8966ba43e3ae47fab5acae051e208ec9074c, pro GNU/Linux 3.2.0, neodstraněno
$ soubor /lib64/libc-2.32.so
/lib64/libc-6bit-2.3 LSB sdílený objekt, x86-64, verze 1 (GNU/Linux), dynamicky propojený, interpret /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=4a7fb374097fb927fb93d35ef98ba89262,x0c4 nesvlečené
Checksec se pokusí najít tyto informace pomocí:
$ readelf -W -h ./ahoj | grep EXEC
Typ: EXEC (spustitelný soubor)
Pokud místo EXEC
zkusíte stejný příkaz na sdílené knihovně , uvidíte DYN
:
$ readelf -W -h /lib64/libc-2.32.so | grep DYN
Typ: DYN (soubor sdíleného objektu)
Povolit PIE
Chcete-li povolit PIE v testovacím programu, pošlete kompilátoru následující argumenty:
$ gcc -pie -fpie hello.c -o hello
Aktivaci PIE můžete ověřit pomocí checksec:
$ checksec --file=./hello --output=json | jq | grep pie
"koláč":"ano",
$
Měl by se zobrazit jako spustitelný soubor PIE s typem změněným z EXEC
na DYN
:
$ file ahoj
ahoj:spustitelný ELF 64bitový LSB koláč, x86-64, verze 1 (SYSV), dynamicky propojený, interpret /lib64/ld-linux-x86-64.so.2, BuildID [sha1]=bb039adf2530d97e02f534a94f0f668cd540f940, pro GNU/Linux 3.2.0, neodstraněno
$ readelf -W -h ./ahoj | grep DYN
Typ: DYN (soubor sdíleného objektu)
4. NX
NX je zkratka pro "non-executable." Často je povoleno na úrovni CPU, takže operační systém s povoleným NX může označit určité oblasti paměti jako nespustitelné. Využití přetečení vyrovnávací paměti často umístí kód do zásobníku a poté se jej pokusí spustit. Pokud však tuto zapisovatelnou oblast změníte na nespustitelnou, můžete takovým útokům zabránit. Tato vlastnost je standardně povolena během běžné kompilace pomocí gcc
:
$ checksec --file=/bin/ls --output=json | jq | grep nx
"nx":"ano",
$ checksec --file=./hello --output=json | jq | grep nx
"nx":"ano",
Checksec určuje tyto informace pomocí příkazu níže. RW
směrem ke konci znamená, že zásobník je čitelný a zapisovatelný; protože tam není E
, není spustitelný:
$ readelf -W -l ./ahoj | grep GNU_STACK
GNU_STACK 0x000000 0x0000000000000000 0x000000000000000 0x000000 0x000000 RW 0x10Zakázat NX pro účely ukázky
Nedoporučuje se to, ale můžete zakázat
NX
při kompilaci programu pomocí-z execstack
argument:$ gcc -z execstack hello.c -o hello
$ checksec --file=./hello --output=json | jq | grep nx
"nx":"ne",Po kompilaci se zásobník stane spustitelným (
RWE
), který umožňuje spuštění škodlivého kódu:$ readelf -W -l ./ahoj | grep GNU_STACK
GNU_STACK 0x000000 0x0000000000000000 0x000000000000000 0x000000 0x000000 RWE 0x105. RELRO
RELRO znamená Relocation Read-Only. Binární soubor ELF (Executable Linkable Format) používá k dynamickému řešení funkcí globální tabulku posunu (GOT). Je-li tato vlastnost povolena, způsobí, že GOT je v binárním systému pouze pro čtení, což zabraňuje některým formám útoků na přemístění:
$ checksec --file=/bin/ls --output=json | jq | grep relro
"relro":"plné",
$ checksec --file=./hello --output=json | jq | grep relro
"relro":"částečné",Checksec najde tyto informace pomocí příkazu níže. Zde je povolena jedna z vlastností RELRO; proto binární soubor ukazuje "částečný" při ověřování pomocí checksec:
$ readelf -W -l ./ahoj | grep GNU_RELRO
GNU_RELRO 0x002e10 0x0000000000403e10 0x0000000000403e10 0x0001f0 0x0001f0 Wlo - d. /e$ 0x1f0 R 0 /e$ 0x1lf grep BIND_NOWPovolit úplné RELRO
Chcete-li povolit plné RELRO, použijte při kompilaci pomocí
gcc
následující argumenty příkazového řádku :$ gcc -Wl,-z,relro,-z,nyní ahoj.c -o ahoj
$ checksec --file=./hello --output=json | jq | grep relro
"relro":"plné",Nyní je také povolena druhá vlastnost, takže program je plný RELRO:
$ readelf -W -l ./ahoj | grep GNU_RELRO
GNU_RELRO 0x002dd0 0x0000000000403dd0 0x0000000000403dd0 0x000230 0x000230 0x000230 0x000230 Wlo - d$ čteno - 0 /hel - hel grep BIND_NOW
0x0000000000000018 (BIND_NOW)6. Opevnit
Fortify je další bezpečnostní vlastnost, ale je mimo rozsah tohoto článku. Nechám se učit, jak checksec ověřuje fortify v binárních souborech a jak je povoleno pomocí
gcc
jako cvičení, které musíte řešit.$ checksec --file=/bin/ls --output=json | jq | grep -i forti
"fortify_source":"yes",
"fortified":"5",
"fortify-able":"17"
$ checksec --file=./hello --output=json | jq | grep -i forti
"fortify_source":"no",
"fortified":"0",
"fortify-able":"0"Další funkce checksec
Téma bezpečnosti je nekonečné, a i když zde není možné pokrýt vše, chci se zmínit o několika dalších funkcích
checksec
příkaz, se kterým je radost pracovat.Spustit proti více binárním souborům
Nemusíte poskytovat každý binární soubor pro checksec jednotlivě. Místo toho můžete zadat cestu k adresáři, kde je uloženo několik binárních souborů, a checksec je všechny najednou ověří:
$ checksec --dir=/usr/bin
Procesy
Kromě binárních souborů funguje checksec také na programy během provádění. Následující příkaz najde vlastnosti zabezpečení všech spuštěných programů ve vašem systému. Můžete použít
--proc-all
pokud chcete, aby kontroloval všechny běžící procesy, nebo můžete vybrat konkrétní proces pomocí jeho názvu:$ checksec --proc-all
$ checksec --proc=bashVlastnosti jádra
Kromě uživatelských aplikací checksec popsaných v tomto článku jej můžete použít také ke kontrole vlastností jádra zabudovaného do vašeho systému:
$ checksec --kernel
Vyzkoušejte to
Checksec je dobrý způsob, jak pochopit, jaké vlastnosti uživatelské země a jádra jsou povoleny. Projděte si podrobně každou vlastnost zabezpečení a snažte se porozumět důvodům povolení jednotlivých funkcí a druhům útoků, kterým brání.
Linux