-
Posts
18659 -
Joined
-
Last visited
-
Days Won
680
Everything posted by Nytro
-
Asta suna dubios
-
Traiesc toti dar ne-au cam uitat.
-
Salut, sunt multe astfel de mizerii care se intampla pe net. Ma mir ca mai merg. Pe principiul asta faceau romanii bani pe ebay acum 15 ani. Educatia e importanta. Daca cineva are incredere si trimite bani "random" unei persoane de pe net, isi cam merita soarta. DAR, e o buna metoda prin care invata. Faptul ca ai postat aici e un lucru util ca vad si alte persoane scenariul si o sa fie pregatite. Platformele ar trebui sa faca ceea ce face OLX, sa tina comunicatia intern si sa ofere mesaje de avertizare pentru useri.
-
In 2019 we celebrated the 10th edition with 3 stages packed with interesting briefings & panel discussions for the 2000+ security experts, developers, decision makers, entrepreneurs, members of the academia and private and public sectors from all around the world. In 2020 we had a COVID-19 break and for 2021 we moved fully online. In 2022, DefCamp returned onsite, in Bucharest, and brought together more than 1,600 participants from over 30 countries. The turnout in such large numbers and the enthusiasm of the participants stood as a powerful motivation to continue strengthening the infosec community and creating a meaningful learning and networking experience. As a result, we are now preparing for the 2023 edition with lots of enthusiasm and energy while we set up the logistics to meet once again with the community under the same roof, in Bucharest. Detaii: https://def.camp/ Bilete: https://def.camp/tickets/ Ne vedem acolo! ❤️ Important: pe 15 creste pretul la bilete.
- 1 reply
-
- 1
-
KittenSec leaks Romanian and EU government data
Nytro replied to WarLord's topic in Stiri securitate
Asa o duc unii bine, de ani de zile, iar asta nu o sa se schimbe prea curand. -
Super, ma bucur sa vad ca sunt persoane care dezvolta tool-uri. Wordlist-ul e cam mare si inutil, nu e nevoie sa se incerce toate acele payloads, cateva simple care sa acopere scenarii comune ar trebui sa fie de ajuns.
-
Eu, nu e tocmai imens si complex dar isi face treaba.
-
Dragut, ai putea sa il face sa scaneze constant reteaua locala pentru noi device-uri. Si lista de domenii sa fie intr-un configuration file.
-
Fortzao ❤️
-
bugbounty SNSC si contractori individuali / Bug Bounty pe infrastructura Romania?
Nytro replied to Krane's topic in Bug Bounty
Nu stiu care ar fi solutia ideala, nu mai sunt anii 2000 sa te dea in judecata, dar nici nu poti avea vreo asteptare ca primesti ceva. E o idee care ar fi utila dar probabil necesita buget iar sumele platite nu ar fi prea mari. Macar daca si-ar pune security.txt cei care sunt interesati de subiect ca un program de bug bounty e prea mult pentru ce e la noi in tara... -
Nu stiu cum te-am putea ajuta, ar trebui sa stii cine sunt persoanele relevante si sa poti discuta cu ele. Daca nu merge treaba, o plangere pe la Ministerul Educatiei sau mai stiu eu unde. Deci ai "picat" licenta din cauza acelui proces verbal? Nu inteleg exact procesul, cand am dat eu licenta nu s-a pus nicio intrebare la nicio lucrare.
-
Damn, that's sick!
-
Si eu imi aduc aminte la fel, la baza era comunicatia locala intre aparat si card. Iar pe card era disponibila suma ramasa, dar intr-un fel "criptat" destul de ciudat. Daca imi aduc bine aminte, facand bit flipping puteai sa te trezesti cu o suma mare pe card si era de ajuns pentru "nevoie".
-
Cateva lucruri interesante: 1. "Cl0p ransomware group leaked data" - Zic si ei mai jos ca nu era ransomware, dar se pare ca gigeii astia fac niste chestii mai "interesante" decat sa cripteze niste fisiere 2. "recent MOVEit Transfer hack" - Lucru deja stiut, cand apare ceva critic e exploatat in masa in "ore" (excluzand 0days sau altele mai avansate) 3. "SecurityWeek was unable to download the archive files" - Probabil cel mai des se afla despre astfel de atacuri cand fisierele ajung publice, ceea ce inseamna ca sunt probabil multe atacuri nedetectate 4. "the cybercriminals noted that the company did not want to negotiate" - Utila practica dar interesant ca atacatorii au vrut sa negocieze
-
Nop, fie incerci sa iei legatura cu speakerul fie cu @Andrei desi slabe sanse sa le mai aiba pe undeva.
-
Poti incerca, conteaza mult cum se face suprascrierea de date de catre ransomware si de filesystem. Daca nu se modifica datele inline pe disk e posibil sa poti recupera anumite date, dar sansele sunt mici dat fiind faptul ca ransomware suprascrie fisiere care in final au aceeasi dimensiune.
-
Decryptere exista pentru foarte putine ransomware, cazurile in care: 1. S-a putut face unul - aka algoritmi de criptare facuti prost sau deloc 2. A meritat - aka cazuri in care companii importante au fost atacate si firme de research au avut motivatie financiara sa faca unul Dar sunt mii astfel de ransomware si sansele de decryptor sunt mici... Backup de duminica e lux, problema e la cei care nu au deloc. Da, nu e ideal, dar e foarte bine totusi. Oficial pot sa dea vina ca le-au crapat niste servere.
-
Salut, daca nu apare ceva public, gen un decryptor de la o firma care face research/antivirus sunt mici sansele sa mearga ceva. Unele ransomeware sunt idioate si nu fac cine stie ce encryption, dar nu e un proces complicat ca sa greseasca des. Asta ar necesita reverse engineering pe ransomware facut de cineva priceput si poate sa nu functioneze. Dar clientul nu are backups? Ransomware mi se par niste janghine de malware ca un simplu backup poate scapa de el.
-
WinDBG quick start tutorial Step by step walk-through for learning basic commands and navigation in WinDBG. © CodeMachine Inc. | codemachine.com | @codemachineinc Overview This post goes over the important commands in WinDBG through a step-by-step follow-along style walkthrough to help you get a jump start into using WinDBG and getting familiar with the commonly used commands. This is required pre-course reading for the Windows Security Developer Bootcamp. We will use WinDBG Preview which can be downloaded from the Windows Store. The version that was used to write this post is WinDBG 1.0.2007.06001. All examples used in the post are from WinDBG running on Windows 10 Version 19042 64-bit version. Getting setup Prior to starting the debug session, we will set up the symbol path that we want WinDBG to use by running the following command in an administrative CMD.exe. If you have the variable _NT_SYMBOL_PATH already set up, you don't have to change it, and therefore running the following command would not be necessary. setx _NT_SYMBOL_PATH SRV*C:\symsrv*http://msdl.microsoft.com/download/symbols Launching the target process We are ready to start the debugger. There are a few different ways to use WinDBG to debug a process, the most common ones are attaching to a running process and launching a process from WinDBG. For this walkthrough, we will be launching the native 64-bit executable from WinDBG. To make it easy to follow along, we will choose an application that is available in every Windows 10 system i.e. notepad.exe. The 64-bit notepad.exe is located in the c:\windows\system32 directory. Start WinDBG from the Windows 10 Start menu. Once WinDBG has started, select File, then Launch Executable. http://codemachine.com/articles/figures/figure_windbg_quickstart_launch.png Launch Executable In the Launch Executable dialog box, browse to the directory c:\Windows\System32 select notepad.exe and click on Open. http://codemachine.com/articles/figures/figure_windbg_quickstart_notepad.png Select Notepad When WinDBG launches an application, it stops at the initial breakpoint before the main entry point of the application is executed. When WinDBG launches notepad.exe the following lines will be displayed in WinDBG's command Window. This allows us to run some initial commands and set any desired breakpoints before the main entry point is called. More on this later. Microsoft (R) Windows Debugger Version 10.0.20153.1000 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: C:\Windows\System32\notepad.exe ************* Path validation summary ************** Response Time (ms) Location Deferred SRV*C:\symsrv*https://msdl.microsoft.com/download/symbols Symbol search path is: SRV*C:\symsrv*https://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00007ff6`f8830000 00007ff6`f8868000 notepad.exe ModLoad: 00007ff9`ff090000 00007ff9`ff286000 ntdll.dll ModLoad: 00007ff9`fd840000 00007ff9`fd8fd000 C:\WINDOWS\System32\KERNEL32.DLL ModLoad: 00007ff9`fce20000 00007ff9`fd0e9000 C:\WINDOWS\System32\KERNELBASE.dll ModLoad: 00007ff9`fe5a0000 00007ff9`fe5ca000 C:\WINDOWS\System32\GDI32.dll ModLoad: 00007ff9`fcc90000 00007ff9`fccb2000 C:\WINDOWS\System32\win32u.dll ModLoad: 00007ff9`fca90000 00007ff9`fcb99000 C:\WINDOWS\System32\gdi32full.dll ModLoad: 00007ff9`fcbf0000 00007ff9`fcc8d000 C:\WINDOWS\System32\msvcp_win.dll ModLoad: 00007ff9`fc910000 00007ff9`fca10000 C:\WINDOWS\System32\ucrtbase.dll ModLoad: 00007ff9`fd6a0000 00007ff9`fd840000 C:\WINDOWS\System32\USER32.dll ModLoad: 00007ff9`fd990000 00007ff9`fdce6000 C:\WINDOWS\System32\combase.dll ModLoad: 00007ff9`fe7d0000 00007ff9`fe8fb000 C:\WINDOWS\System32\RPCRT4.dll ModLoad: 00007ff9`fe030000 00007ff9`fe0de000 C:\WINDOWS\System32\shcore.dll ModLoad: 00007ff9`fddd0000 00007ff9`fde6e000 C:\WINDOWS\System32\msvcrt.dll ModLoad: 00007ff9`f1f70000 00007ff9`f220b000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.488_none_ca04af081b815d21\COMCTL32.dll (4bc.1df4): Break instruction exception - code 80000003 (first chance) ntdll!LdrpDoDebuggerBreak+0x30: 00007ff9`ff1606d0 cc int 3 Debugger process architecture Before we proceed any further let us quickly review the WinDBG Preview process architecture. WinDBG Preview is a UWP application that has very limited access to the system, certainly not enough to debug a process. Hence the WinDBG UI and the WinDBG debugger workhorse are in separate processes that communicate using the named pipe inter-process communication (IPC) mechanism. The WinDBG Preview UI process is DBG.X.Shell.exe which connects over a named pipe to EngHost.exe which is the process responsible for attaching or launching the process being debugged. http://codemachine.com/articles/figures/figure_windbg_quickstart_processes.png WinDBG Process Hierarchy The following command displays the command-line options that were passed to the debugger process (EngHost.exe). The named pipe with the name DbgX_c07674536fa94c33bdf0af63c782f816 is used by DbgX.Shell.exe to communicate with EngHost.exe. 0:000> vercommand command line: '"C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2007.6001.0_neutral__8wekyb3d8bbwe\amd64\EngHost.exe" npipe:pipe=DbgX_c07674536fa94c33bdf0af63c782f816,password=9cd080f41b98 "C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2007.6001.0_neutral__8wekyb3d8bbwe\amd64" "C:\ProgramData\Dbg"' Performing some initial investigation Let us obtain some basic information about the OS version and the process being debugged. The Show Target Computer Version (vertarget) command displays information about the Windows version and information debug session time. 0:000> vertarget Windows 10 Version 19042 MP (4 procs) Free x64 Product: WinNt, suite: SingleUserTS Edition build lab: 19041.1.amd64fre.vb_release.191206-1406 Build layer: -> Build layer: -> Build layer: -> Machine Name: Debug session time: Sun Dec 6 00:16:24.332 2020 (UTC - 8:00) System Uptime: 0 days 17:37:21.507 Process Uptime: 0 days 0:03:22.680 Kernel time: 0 days 0:00:00.000 User time: 0 days 0:00:00.000 The (vertarget) command showed that there are 4 CPUs (cores) on the system, let's find out a little bit more about the Family (F), Model (M), Stepping (S), and the speed of the CPUs/cores in the system using the (!cpuid) debugger extension command. Note that the (!) symbol before the (!cpuid) command denotes that this command is not supported natively by the debugger rather it resides in a debugger extension DLL. 0:000> !cpuid CP F/M/S Manufacturer MHz 0 6,14,3 2607 1 6,14,3 2607 2 6,14,3 2607 3 6,14,3 2607 Prior to starting WinDBG, we had set up the environment variable _NT_SYMBOL_PATH to the symbol path. WinDBG should have automatically used the symbol path set in this variable. Let us verify that using the Set Symbol Path (.sympath) command. Note that the (.) in front of the command denotes that this is a meta-command. Most such commands cause a change in the behavior of the debugger. In this specific case, the (.sympath) command could be used with the (+) option to append another path to the current symbol path. 0:000> .sympath Symbol search path is: SRV*C:\symsrv*https://msdl.microsoft.com/download/symbols Expanded Symbol search path is: srv*c:\symsrv*https://msdl.microsoft.com/download/symbols ************* Path validation summary ************** Response Time (ms) Location Deferred SRV*C:\symsrv*https://msdl.microsoft.com/download/symbols To find the path to the symbol file (.PDB) that the debugger is using for notepad we can use the debugger extension command (!lmi). This command parses the PE headers and displays information retrieved from the PE file's Debug Directory. 0:000> !lmi notepad Loaded Module Info: [notepad] Module: notepad Base Address: 00007ff6f8830000 Image Name: notepad.exe Machine Type: 34404 (X64) Time Stamp: d686c2e9 (This is a reproducible build file hash, not a true timestamp) Size: 38000 CheckSum: 3e7ca Characteristics: 22 Debug Data Dirs: Type Size VA Pointer CODEVIEW 24, 2b604, 2a404 RSDS - GUID: {17F6F0A8-0039-D425-B201-69009E11D822} Age: 1, Pdb: notepad.pdb POGO 49c, 2b628, 2a428 [Data not mapped] REPRO 24, 2bac4, 2a8c4 Reproducible build[Data not mapped] Image Type: FILE - Image read successfully from debugger. C:\Windows\System32\notepad.exe Symbol Type: PDB - Symbols loaded successfully from symbol server. c:\symsrv\notepad.pdb\17F6F0A80039D425B20169009E11D8221\notepad.pdb Load Report: public symbols , not source indexed c:\symsrv\notepad.pdb\17F6F0A80039D425B20169009E11D8221\notepad.pdb Process and Thread Status The Process Status (|) command can be used to find the process ID and the process name being debugged. 0:000> | . 0 id: 4bc create name: notepad.exe When WinDBG is being used as a user-mode debugger, the Thread Status (~) command displays information for all threads in the current process. At this time, there is just a single thread in the notepad process and the status of the thread is shown below. This information includes the Thread ID = 0x1df4, the address of the TEB of the thread 0x000000e979a72000, the suspend count of the thread and information about freeze state of the thread. 0:000> ~ . 0 Id: 4bc.1df4 Suspend: 1 Teb: 000000e9`79a72000 Unfrozen Module Information To find the virtual address at which any module is loaded in memory, we can run the (List Loaded Modules) (lm) command. Running the lm command by itself will display the starting and ending address range of where each module is loaded in notepad.exe process address space. /p> 0:000> lm start end module name 00007ff6`f8830000 00007ff6`f8868000 notepad (pdb symbols) c:\symsrv\notepad.pdb\17F6F0A80039D425B20169009E11D8221\notepad.pdb 00007ff9`f1f70000 00007ff9`f220b000 COMCTL32 (deferred) 00007ff9`fc910000 00007ff9`fca10000 ucrtbase (deferred) 00007ff9`fca90000 00007ff9`fcb99000 gdi32full (deferred) 00007ff9`fcbf0000 00007ff9`fcc8d000 msvcp_win (deferred) 00007ff9`fcc90000 00007ff9`fccb2000 win32u (deferred) 00007ff9`fce20000 00007ff9`fd0e9000 KERNELBASE (deferred) 00007ff9`fd6a0000 00007ff9`fd840000 USER32 (deferred) 00007ff9`fd840000 00007ff9`fd8fd000 KERNEL32 (pdb symbols) 00007ff9`fd960000 00007ff9`fd990000 IMM32 (deferred) 00007ff9`fd990000 00007ff9`fdce6000 combase (deferred) 00007ff9`fddd0000 00007ff9`fde6e000 msvcrt (deferred) 00007ff9`fe030000 00007ff9`fe0de000 shcore (deferred) 00007ff9`fe5a0000 00007ff9`fe5ca000 GDI32 (deferred) 00007ff9`fe7d0000 00007ff9`fe8fb000 RPCRT4 (deferred) 00007ff9`ff090000 00007ff9`ff286000 ntdll (pdb symbols) c:\symsrv\ntdll.pdb\1EB9FACB04C73C5DEA7160764CD333D01\ntdll.pdb Running the (lm) command with the (m) option can be used to restrict the output to a specific module. We use this to retrieve the VA range assigned to the module notepad.exe. 0:000> lm m notepad start end module name 00007ff6`f8830000 00007ff6`f8868000 notepad (deferred) To obtain version information of a module, which is stored in the resources (.rsrc) section use the (v) option of the lm command. 0:000> lm v m notepad start end module name 00007ff6`f8830000 00007ff6`f8868000 notepad (pdb symbols) c:\symsrv\notepad.pdb\17F6F0A80039D425B20169009E11D8221\notepad.pdb Loaded symbol image file: C:\Windows\System32\notepad.exe Image path: notepad.exe Image name: notepad.exe Image was built with /Brepro flag. Timestamp: D686C2E9 (This is a reproducible build file hash, not a timestamp) CheckSum: 0003E7CA ImageSize: 00038000 File version: 10.0.19041.488 Product version: 10.0.19041.488 File flags: 0 (Mask 3F) File OS: 40004 NT Win32 File type: 1.0 App File date: 00000000.00000000 Translations: 0409.04b0 Information from resource tables: CompanyName: Microsoft Corporation ProductName: Microsoft® Windows® Operating System InternalName: Notepad OriginalFilename: NOTEPAD.EXE ProductVersion: 10.0.19041.488 FileVersion: 10.0.19041.488 (WinBuild.160101.0800) FileDescription: Notepad LegalCopyright: © Microsoft Corporation. All rights reserved. In WinDBG, the name of any module is treated as an expression that evaluates to the start VA at which the module is loaded into memory. If we use the MASM expression evaluator operator (?) on the module "notepad", it displays the start VA of the module. 0:000> ? notepad Evaluate expression: 140698708017152 = 00007ff6`f8830000 Setting an execution breakpoint At this point, we have found a reasonable bit of information about the process being debugged. We will now set a breakpoint on the main entry point of the PE file of notepad.exe. To do so, we must find the symbol that represents the main entry point of notepad.exe. To obtain a list of all such symbols we use the Examine Symbol (x) command which accepts wildcards and therefore makes it quite convenient to obtain a list of functions that end with the word main. The parameter we are passing to the (x) command consists of - the name of the module (without the extension), the exclamation sign (!) as the separator followed by the name of the symbols (containing wildcards). 0:000> x notepad!*main 00007ff6`f883b090 notepad!wWinMain (wWinMain) In the above output, the first column displays the address of the symbol at which the symbol resides followed by the complete name of the symbol that matched the given wildcard. The Set Breakpoint (bp) command has the ability to set a breakpoint on either a symbol name or an address. We use it to set a breakpoint on the main entry point of notepad.exe. 0:000> bp notepad!wWinMain Let us verify that the breakpoint is indeed set appropriately using the Breakpoint List (bl) command. 0:000> bl 0 e 00007ff6`f883b090 0001 (0001) 0:**** notepad!wWinMain It is noteworthy that the bp command was able to resolve the symbol notepad!wWinMain to the appropriate address i.e. 00007ff6`f883b090 and was able to set an execution breakpoint and enable it as indicated by the (e) in the output above. Now that we have the breakpoint set, let us continue executing the process notepad.exe using the Go (g) command. 0:000> g ModLoad: 00007ff9`fd960000 00007ff9`fd990000 C:\WINDOWS\System32\IMM32.DLL Breakpoint 0 hit notepad!wWinMain: 00007ff6`f883b090 488bc4 mov rax,rsp As soon as we continue execution, the function we set the breakpoint on gets called, the breakpoint triggers and WinDBG gives us back control of the process. Hitting the breakpoint WinDBG has stopped the execution of notepad.exe at the first instruction of the function notepad!wWinMain. Let us ascertain that by retrieving the value of all the x64 CPU registers. The values in the registers would also assist us with retrieving the parameters that were passed to this function since on x64 the first 4 parameters are passed in CPU registers. To retrieve the CPU registers we use the Registers (r) command. 0:000> r rax=0000023771d528b6 rbx=000000000000000a rcx=00007ff6f8830000 rdx= rsi=0000000000000000 rdi=0000000000000000 rip=00007ff6f883b090 rsp=000000e9799dfd48 rbp=0000000000000000 r8=0000023771d528b6 r9=000000000000000a r10=00000fff3f9cdb1f r11=0002002080000000 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 notepad!wWinMain: 00007ff6`f883b090 488bc4 mov rax,rsp The above output confirms that the address in the instruction pointer (RIP) indeed points to the first instruction of the function notepad!wWinMain. The prototype of the function wWinMain is as shown below along with the CPU registers that contain the respective parameters. int WINAPI wWinMain( HINSTANCE hInstance, // rcx HINSTANCE hPrevInstance, // rdx PWSTR lpCmdLine, // r8 int nCmdShow ); // r9 From the output of the (r) command the value of hInstance = 0x00007ff6f8830000, hPrevInstance = 0x 0000000000000000 (NULL), lpCmdLine=0x0000023771d528b6, nCmdShow=000000000000000a (SW_SHOWDEFAULT). Displaying stack contents The RSP register points to the top of the stack of the current thread. For a 64-bit process, each value stored on the stack is 64-bits in size i.e. a pointer-sized value. To display the contents of memory starting at the address in the RSP register we use the (dp) variant of the Display Memory command. Please note that the (@) sign in front of a register is required if the current expression evaluator is C++, but we use it by default just as best practice. 0:000> dp @rsp 000000e9`799dfd48 00007ff6`f8853b86 00000000`00000000 000000e9`799dfd58 00000000`00000000 00000000`00000000 000000e9`799dfd68 00000000`00000000 00000000`00000000 000000e9`799dfd78 00000000`00000000 00000000`00000000 000000e9`799dfd88 00007ff9`fd857034 00000000`00000000 000000e9`799dfd98 00000000`00000000 00000000`00000000 000000e9`799dfda8 00000000`00000000 00000000`00000000 000000e9`799dfdb8 00007ff9`ff0dd0d1 00000000`00000000 By default, the (dp) command displays 64-bit values in two columns. We can change that using the column (/c) option to the (dp) command to display the contents of memory in 4 columns, as shown below. 0:000> dp /c 4 @rsp 000000e9`799dfd48 00007ff6`f8853b86 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfd68 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfd88 00007ff9`fd857034 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfda8 00000000`00000000 00000000`00000000 00007ff9`ff0dd0d1 00000000`00000000 To display more than the default 16 values, we can use the object count (L) option followed by the number of values to display. 0:000> dp /c 4 @rsp L 20 000000e9`799dfd48 00007ff6`f8853b86 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfd68 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfd88 00007ff9`fd857034 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfda8 00000000`00000000 00000000`00000000 00007ff9`ff0dd0d1 00000000`00000000 000000e9`799dfdc8 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfde8 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 000000e9`799dfe08 00000000`00000000 000004e8`fffffb30 000004d0`fffffb30 00000000`00000019 000000e9`799dfe28 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 And last but not the least, if we would like WinDBG to automatically attempt to map each one of the displayed values to symbols the (dps) variant of the Display Referenced Memory command can be used which in case of the stack would display all the return addresses as the map to symbols representing addresses within the functions that have been pushed on the stack by call instructions. 0:000> dps @rsp 000000e9`799dfd48 00007ff6`f8853b86 notepad!__scrt_common_main_seh+0x106 000000e9`799dfd50 00000000`00000000 000000e9`799dfd58 00000000`00000000 000000e9`799dfd60 00000000`00000000 000000e9`799dfd68 00000000`00000000 000000e9`799dfd70 00000000`00000000 000000e9`799dfd78 00000000`00000000 000000e9`799dfd80 00000000`00000000 000000e9`799dfd88 00007ff9`fd857034 KERNEL32!BaseThreadInitThunk+0x14 000000e9`799dfd90 00000000`00000000 000000e9`799dfd98 00000000`00000000 000000e9`799dfda0 00000000`00000000 000000e9`799dfda8 00000000`00000000 000000e9`799dfdb0 00000000`00000000 000000e9`799dfdb8 00007ff9`ff0dd0d1 ntdll!RtlUserThreadStart+0x21 000000e9`799dfdc0 00000000`00000000 Now that we have learned how to display the raw contents of the stack using the RSP register, let us view the stack the way it is meant to be displayed by the debuggers using the Display Stack Backtrace (k) command and its variants. 0:000> k Child-SP RetAddr Call Site 000000e9`799dfd48 00007ff6`f8853b86 notepad!wWinMain 000000e9`799dfd50 00007ff9`fd857034 notepad!__scrt_common_main_seh+0x106 000000e9`799dfd90 00007ff9`ff0dd0d1 KERNEL32!BaseThreadInitThunk+0x14 000000e9`799dfdc0 00000000`00000000 ntdll!RtlUserThreadStart+0x21 The information displayed is the call chain from the start of this thread's execution (ntdll!RtlUserThreadStart) all the way to the current function (notepad!wWinMain) on which we set our breakpoint. Let's dig a little deeper into the displayed call stack. Each line displayed above represents the stack frame of a single function. The frame at the bottom is the least recent frame and the frame on top is the most recent frame. The values listed under Child-SP are the values of stack-pointer (RSP) register for the frame. This is the value of the RSP register right after the prolog of the function listed under the Call Site column has finished execution. This value in the RSP register remains static throughout the function body. Local variables and stack-based parameters to the function are accessed using this value in RSP. The RetAddr is the return address that the current function i.e. the function listed under Call Site will return to once the function has finished execution. This address corresponds to the location displayed in the next (lower) stack frame. For example, running the List Nearest Symbols (ln) command on the RetAddr in the topmost frame maps to the function and offset listed under Call Site in the frame below the topmost frame. 0:000> ln 00007ff6`f8853b86 (00007ff6`f8853a80) notepad!__scrt_common_main_seh+0x106 | (00007ff6`f8853c00) notepad!wWinMainCRTStartup Now that we understand how to interpret the information displayed by the (k) command, let us try some of its variants. To include the frame numbers in the stack display use the (kn) variant of the Display Stack Backtrace (k) command. 0:000> kn # Child-SP RetAddr Call Site 00 000000e9`799dfd48 00007ff6`f8853b86 notepad!wWinMain 01 000000e9`799dfd50 00007ff9`fd857034 notepad!__scrt_common_main_seh+0x106 02 000000e9`799dfd90 00007ff9`ff0dd0d1 KERNEL32!BaseThreadInitThunk+0x14 03 000000e9`799dfdc0 00000000`00000000 ntdll!RtlUserThreadStart+0x21 To display a clean stack trace which only lists the module and function names use the (kc) variant of the Display Stack Backtrace (k) command. 0:000> kc Call Site notepad!wWinMain notepad!__scrt_common_main_seh KERNEL32!BaseThreadInitThunk ntdll!RtlUserThreadStart And finally, to display the verbose stack trace that includes the stack-based parameters passed to every function on the stack, use the (kv) variant of the Display Stack Backtrace (k) command. It is critical to note that as per the x64 calling convention, the first four parameters to a function are passed via CPU register and not through the stack. Therefore, the values displayed under "Args to Child" which are values on the stack do not represent the actual parameters to the function and using them as such can be quite misleading. Due to this, the (kv) command has very limited use on x64. 0:000> kv Child-SP RetAddr : Args to Child : Call Site 000000e9`799dfd48 00007ff6`f8853b86 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : notepad!wWinMain 000000e9`799dfd50 00007ff9`fd857034 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : notepad!__scrt_common_main_seh+0x106 000000e9`799dfd90 00007ff9`ff0dd0d1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14 000000e9`799dfdc0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21 Displaying strings Now we look at some WinDBG commands that can be used to display different types of strings used by applications, such as ASCII strings, wide char strings, and Unicode strings. One relatively straightforward way of finding such strings is to look for symbols in modules such as notepad.exe or NTDLL.dll that represent data values as opposed to functions and whose names are indicative of them representing strings. The list of such variable names can be found using the Examine Symbols (x) command with the (/d) option. We also add the (/a) option which will display the output in ascending order of addresses The following output has been edited for brevity. 0:000> x /a /d ntdll!* 00007ff9`ff1ac000 ntdll!RtlpSlashSlashDot = <no type information> 00007ff9`ff1ac010 ntdll!RtlpDosCONOUTDevice = <no type information> 00007ff9`ff1ac020 ntdll!RtlpDosPRNDevice = <no type information> 00007ff9`ff1ac030 ntdll!RtlpDosNULDevice = <no type information> 00007ff9`ff1ac040 ntdll!RtlpDosAUXDevice = <no type information> . . . [REDACTED] Using the above technique on notepad.exe we obtain the symbol notepad!_sz_ADVAPI32_dll. The presence of 'sz' in the name of the data variable implies that the memory contains a NULL-terminated ASCII string. With this assumption, we run the (da) variant of the Display Memory command. 0:000> da notepad!_sz_ADVAPI32_dll 00007ff6`f88573a0 "ADVAPI32.dll" Again, using the same symbols listing technique listed above, we obtain the symbols ntdll!SlashSystem32SlashString. Unlike the previous case, the name is not suggestive as to the type of string this data variable represents. It may be an ASCII string, wide char string, or Unicode string. When the format of the data in memory is not known in advance, the (dc) variant of the Display Memory command can be used to display the contents of that memory in both DWORD (32-bit) format and as ASCII characters provided the characters are printable. 0:000> dc ntdll!SlashSystem32SlashString 00007ff9`ff1ac1e0 00160014 00000000 ff1b75c8 00007ff9 .........u...... 00007ff9`ff1ac1f0 001a0018 00000000 ff1b6fd0 00007ff9 .........o...... 00007ff9`ff1ac200 ff0d08e0 00007ff9 ff0fd2c0 00007ff9 ................ 00007ff9`ff1ac210 00000000 00000000 ff114580 00007ff9 .........E...... 00007ff9`ff1ac220 ff0cea30 00007ff9 ff1a1c70 00007ff9 0.......p....... 00007ff9`ff1ac230 ff0d2950 00007ff9 ff0fd2c0 00007ff9 P).............. 00007ff9`ff1ac240 ff114cf0 00007ff9 ff114580 00007ff9 .L.......E...... 00007ff9`ff1ac250 ff0d4700 00007ff9 ff0fd2c0 00007ff9 .G.............. By observing the contents of the memory location and recognizing the pattern - 16-bit integer, 16-bit integer, 32-bit NULL, 64-bit address, we can assume that we have a Unicode string header in memory. To ascertain this let us display the data type for the Unicode string header using the Display Type (dt) command. 0:000> dt ntdll!_UNICODE_STRING +0x000 Length : Uint2B +0x002 MaximumLength : Uint2B +0x008 Buffer : Ptr64 Wchar We can clearly see that the contents of memory match the fields of the UNICODE_STIRNG structure. So we go one step further and typecast the contents of memory at the symbol ntdll!SlashSystem32SlashString (0x00007ff9`ff1ac1e0) to the UNICODE_STIRNG structure. 0:000> dt ntdll!_UNICODE_STRING 00007ff9`ff1ac1e0 "\SYSTEM32\" +0x000 Length : 0x14 +0x002 MaximumLength : 0x16 +0x008 Buffer : 0x00007ff9`ff1b75c8 "\SYSTEM32\" Now that we have confirmed that ntdll!SlashSystem32SlashString contains a Unicode string header, let us go ahead and display the string with the (dS) variant of the Display String commands. 0:000> dS ntdll!SlashSystem32SlashString 00007ff9`ff1b75c8 "\SYSTEM32\" Instead of using the address of the UNICODE_STRING structure itself, we can also use the address in the Buffer field of the UNICODE_STRING structure (i.e. 0x00007ff9`ff1b75c8) to display the string. To do this we use the (du) variant of the Display Memory command. Please note that the wide char string must be NULL-terminated. 0:000> du 0x00007ff9`ff1b75c8 00007ff9`ff1b75c8 "\SYSTEM32\" Displaying Memory Contents Now that we know that the memory at the symbol notepad!_sz_ADVAPI32_dll contains an ASCII string, let us display the same memory in various other formats such as 8-bit byte (db), 16-bit word (dw), 32-bit double-word (dd) and 64-bit quad-word (dq). Please note that only the (db) command displayed the output in ASCII as well as hexadecimal numbers. Display as bytes (char). 0:000> db notepad!_sz_ADVAPI32_dll 00007ff6`f88573a0 41 44 56 41 50 49 33 32-2e 64 6c 6c 00 00 00 00 ADVAPI32.dll.... 00007ff6`f88573b0 22 05 93 19 01 00 00 00-a8 c9 02 00 00 00 00 00 "............... 00007ff6`f88573c0 00 00 00 00 01 00 00 00-b0 c9 02 00 20 00 00 00 ............ ... 00007ff6`f88573d0 00 00 00 00 05 00 00 00-00 00 00 00 00 00 00 00 ................ 00007ff6`f88573e0 61 00 70 00 69 00 2d 00-6d 00 73 00 2d 00 77 00 a.p.i.-.m.s.-.w. 00007ff6`f88573f0 69 00 6e 00 2d 00 63 00-6f 00 72 00 65 00 2d 00 i.n.-.c.o.r.e.-. 00007ff6`f8857400 73 00 79 00 6e 00 63 00-68 00 2d 00 6c 00 31 00 s.y.n.c.h.-.l.1. 00007ff6`f8857410 2d 00 32 00 2d 00 30 00-2e 00 64 00 6c 00 6c 00 -.2.-.0...d.l.l. Display as words (short). 0:000> dw notepad!_sz_ADVAPI32_dll 00007ff6`f88573a0 4441 4156 4950 3233 642e 6c6c 0000 0000 00007ff6`f88573b0 0522 1993 0001 0000 c9a8 0002 0000 0000 00007ff6`f88573c0 0000 0000 0001 0000 c9b0 0002 0020 0000 00007ff6`f88573d0 0000 0000 0005 0000 0000 0000 0000 0000 00007ff6`f88573e0 0061 0070 0069 002d 006d 0073 002d 0077 00007ff6`f88573f0 0069 006e 002d 0063 006f 0072 0065 002d 00007ff6`f8857400 0073 0079 006e 0063 0068 002d 006c 0031 00007ff6`f8857410 002d 0032 002d 0030 002e 0064 006c 006c Display as double-words (long). 0:000> dd notepad!_sz_ADVAPI32_dll 00007ff6`f88573a0 41564441 32334950 6c6c642e 00000000 00007ff6`f88573b0 19930522 00000001 0002c9a8 00000000 00007ff6`f88573c0 00000000 00000001 0002c9b0 00000020 00007ff6`f88573d0 00000000 00000005 00000000 00000000 00007ff6`f88573e0 00700061 002d0069 0073006d 0077002d 00007ff6`f88573f0 006e0069 0063002d 0072006f 002d0065 00007ff6`f8857400 00790073 0063006e 002d0068 0031006c 00007ff6`f8857410 0032002d 0030002d 0064002e 006c006c Display as quad-words (__int64). 0:000> dq notepad!_sz_ADVAPI32_dll 00007ff6`f88573a0 32334950`41564441 00000000`6c6c642e 00007ff6`f88573b0 00000001`19930522 00000000`0002c9a8 00007ff6`f88573c0 00000001`00000000 00000020`0002c9b0 00007ff6`f88573d0 00000005`00000000 00000000`00000000 00007ff6`f88573e0 002d0069`00700061 0077002d`0073006d 00007ff6`f88573f0 0063002d`006e0069 002d0065`0072006f 00007ff6`f8857400 0063006e`00790073 0031006c`002d0068 00007ff6`f8857410 0030002d`0032002d 006c006c`0064002e Navigating in assembler Although there are better reverse engineering tools than WinDBG such as Ghidra, WinDBG does provide the ability to navigate through assembler functions. The most glaring feature missing in WinDBG is the ability to perform cross-referencing. To unassemble the instructions starting at the current instruction pointer (RIP) we use the Unassemble (u) command and the RIP register as the address parameter. The (u) command uses a linear scan algorithm to disassemble the opcodes for the next 8 instructions. 0:000> u @rip notepad!wWinMain: 00007ff6`f883b090 488bc4 mov rax,rsp 00007ff6`f883b093 48895808 mov qword ptr [rax+8],rbx 00007ff6`f883b097 48897010 mov qword ptr [rax+10h],rsi 00007ff6`f883b09b 48897818 mov qword ptr [rax+18h],rdi 00007ff6`f883b09f 4c896020 mov qword ptr [rax+20h],r12 00007ff6`f883b0a3 55 push rbp 00007ff6`f883b0a4 4156 push r14 00007ff6`f883b0a6 4157 push r15 To unassemble the instructions backward we use the (ub) variant of the Unassemble command and again specify the RIP register as the address parameter to disassemble 8 instructions prior to the address in the RIP register. The following listing shows a series of INT 3 instructions before the start of the function notepad!wWinMain. These INT 3 instructions were added by the compiler to ensure that notepad!wWinMain starts at a 16 (0x10) byte boundary and provides a small code cave that can be potentially used for inline hooking. 0:000> ub @rip notepad!IsElevated+0x80: 00007ff6`f883b088 cc int 3 00007ff6`f883b089 cc int 3 00007ff6`f883b08a cc int 3 00007ff6`f883b08b cc int 3 00007ff6`f883b08c cc int 3 00007ff6`f883b08d cc int 3 00007ff6`f883b08e cc int 3 00007ff6`f883b08f cc int 3 To disassemble more than 8 instructions we can specify an address range consisting of an address (RIP) and object count (L) followed by the number of instructions to display. 0:000> ub @rip L10 notepad!IsElevated+0x65: 00007ff6`f883b06d 85c0 test eax,eax 00007ff6`f883b06f 0f455c2448 cmovne ebx,dword ptr [rsp+48h] 00007ff6`f883b074 48ff150dba0100 call qword ptr [notepad!_imp_CloseHandle (00007ff6`f8856a88)] 00007ff6`f883b07b 0f1f440000 nop dword ptr [rax+rax] 00007ff6`f883b080 8bc3 mov eax,ebx 00007ff6`f883b082 4883c430 add rsp,30h 00007ff6`f883b086 5b pop rbx 00007ff6`f883b087 c3 ret 00007ff6`f883b088 cc int 3 00007ff6`f883b089 cc int 3 00007ff6`f883b08a cc int 3 00007ff6`f883b08b cc int 3 00007ff6`f883b08c cc int 3 00007ff6`f883b08d cc int 3 00007ff6`f883b08e cc int 3 00007ff6`f883b08f cc int 3 Both the (u) and the (ub) variants use a linear sweep algorithm to disassemble a function and as such are not aware of function boundaries or basic blocks within functions. The Unassemble Function (uf) command on the other hand uses a recursive algorithm that evaluates every basic block within a function to find other basic blocks. The following output has been edited for brevity. 0:000> uf @rip notepad!wWinMain: 00007ff6`f883b090 488bc4 mov rax,rsp 00007ff6`f883b093 48895808 mov qword ptr [rax+8],rbx 00007ff6`f883b097 48897010 mov qword ptr [rax+10h],rsi 00007ff6`f883b09b 48897818 mov qword ptr [rax+18h],rdi 00007ff6`f883b09f 4c896020 mov qword ptr [rax+20h],r12 00007ff6`f883b0a3 55 push rbp 00007ff6`f883b0a4 4156 push r14 00007ff6`f883b0a6 4157 push r15 00007ff6`f883b0a8 488d68a1 lea rbp,[rax-5Fh] 00007ff6`f883b0ac 4881ec90000000 sub rsp,90h . . . [REDACTED] . . . 00007ff6`f883b427 8b451f mov eax,dword ptr [rbp+1Fh] 00007ff6`f883b42a 4c8d9c2490000000 lea r11,[rsp+90h] 00007ff6`f883b432 498b5b20 mov rbx,qword ptr [r11+20h] 00007ff6`f883b436 498b7328 mov rsi,qword ptr [r11+28h] 00007ff6`f883b43a 498b7b30 mov rdi,qword ptr [r11+30h] 00007ff6`f883b43e 4d8b6338 mov r12,qword ptr [r11+38h] 00007ff6`f883b442 498be3 mov rsp,r11 00007ff6`f883b445 415f pop r15 00007ff6`f883b447 415e pop r14 00007ff6`f883b449 5d pop rbp 00007ff6`f883b44a c3 ret If all we are interested in are the calls a function is making as opposed to the actual disassembly the (/c) flag to the (uf) command can list those. The following output has been edited for brevity. 0:000> uf /c @rip notepad!wWinMain (00007ff6`f883b090) notepad!wWinMain+0x41 (00007ff6`f883b0d1): call to notepad!wil::details::FeatureImpl. . . (00007ff6`f883cf44) notepad!wWinMain+0x92 (00007ff6`f883b122): call to notepad!wil_details_FeatureReporting_ReportUsageToService (00007ff6`f883e014) [REDACTED] notepad!wWinMain+0x35e (00007ff6`f883b3ee): call to KERNEL32!FreeLibraryStub (00007ff9`fd85c7d0) notepad!wWinMain+0x36a (00007ff6`f883b3fa): call to combase!CoUninitialize (00007ff9`fd9b28d0) notepad!wWinMain+0x38b (00007ff6`f883b41b): call to notepad!_imp_load_EventUnregister (00007ff6`f88538db) Continuing Execution Now that we are done with the walkthrough let WinBDG continue executing the process notepad.exe using the Go (g) command, once again. 0:000> g List of commands To recap here are the list commands we have learned about in this tutorial. vercommand Show Debugger Command Line vertarget Show Target Computer Version !cpuid Displays information about the processors on the system .sympath Set Symbol Path !lmi Displays detailed information about a module | Process Status ~ Thread Status lm List Loaded Modules ? Evaluate Expression x Examine Symbols bp Set Breakpoint bl Breakpoint Enable g Go r Registers dp Display Memory - Pointer-sized values dps Display Referenced Memory - Display known symbols k Display Stack Backtrace ln List Nearest Symbols da Display Memory - ASCII characters dc Display Memory - Double-word values and ASCII characters dt Display Type dS Display String - UNICODE_STRING structure du Display Memory - Wide char characters db Display Memory - ASCII characters dw Display Memory - Word values dd Display Memory - Double-word values dq Display Memory - Quad-word values u Unassemble ub Unassemble backward uf Unassemble Function Finishing up This brings us to the conclusion of this tutorial of executing the most common commands in WinDBG on a user-mode process. We have learned how to set up symbols, launch a process from WinDBG, obtain basic information about the target process, threads and modules, set breakpoints, display stacks, display memory contents, display stack traces and navigate through function assembler listings. Most of these commands we have learned here would also work when WinDBG is used as a kernel debugger. Sursa: http://codemachine.com/articles/windbg_quickstart.html
-
- 2
-
Abusing Time-Of-Check Time-Of-Use (TOCTOU) Race Condition Vulnerabilities in Games, Harry Potter Style access_timeMay 16, 2023 person_outlineTom Neaves share I feel I need to clarify, for legal reasons, that this is nothing to do with any Harry Potter game. The reference is made because we are dealing with spells and magic, and I mean magic in the literal sense, not a reference to application security – although on some/most days it feels like magic. Time-Of-Check Time-Of-Use (TOCTOU) and Race Conditions? What’s it all about? According to Wikipedia, “In software development, time-of-check to time-of-use (TOCTOU, TOCTTOU or TOC/TOU) is a class of software bugs caused by a race condition involving the checking of the state of a part of a system (such as a security credential) and the use of the results of that check.” From MITRE’s Common Weakness Enumeration (CWE), it states this about TOCTOU (CWE-367), “The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. This can cause the product to perform invalid actions when the resource is in an unexpected state. This weakness can be security-relevant when an attacker can influence the state of the resource between check and use. This can happen with shared resources such as files, memory, or even variables in multithreaded programs.” In a nutshell, a developer writes some code to make a check of something (like the value of something held in memory) and then uses the result of this check later (“later” could be nanoseconds here). The developer assumes that this value could not be changed in between the check and the use. Unbeknown to them, there is often a path, either in the code itself, or indirectly, to change this value after the check, but before the use. Because the change is being made out of band, rules and restrictions can often be circumvented as all these checks have already been done. When it comes to using the value, it is treated as being trusted – the check already took place. You can now see why as an attacker the TOCTOU vulnerability gets invited to the party. MITRE’s CWE-367-page (which I’m about to paraphrase) gives a great example of this in a Set owner User ID (SUID) program which operates on files on behalf of non-privileged users. The program performs access checks to ensure it doesn’t use its root privileges to perform operations on files which would otherwise be unavailable to that user. To do this it has an access check which it calls to verify that the user (in their own security context) has access before it opens the file – as shown in the code below. Figure 1: access() system call to check if the person running the program has permission All works well and as intended. If the user doesn’t have write access to the file, then they are redirected to that door with the green exit sign above it. However, a problem, due to the way access() and fopen() work, they operate on filenames rather than file handles. There is no guarantee that the file variable still refers to the same file on disk when it is passed to fopen() that it did when it was passed to access(). An attacker could let the access() check happen on a file they have write access to, but then replace the file with a symbolic link right after this to refer to another file they don’t have access to. It is at this point fopen() is called, but this now opens the replaced file (using the program’s privileged SUID access) which the attacker does not have write access to normally. You can see where this is going if the attacker points these lasers at /etc/passwd. Now that you’re a sworn in member of the TOCTOU club, I can continue with the main story, the main event – you came here for the gaming. You’re playing a massively multiplayer online game (MMOG), set somewhere in medieval England. You play the character of a noble knight, together with your trusty horse. You spend your time travelling between castles, towns and small settlements – speaking to people, collecting food, money, weapons and other useful items. When travelling between these places you generally get into trouble as other characters want to fight and rob you of your food, money and other items. When inside castles, towns and small settlements you’re safe – it is not possible to use weapons, the server will deny this - people revert to using the chat instead to fight. Now, I just set out one of the conditions (or the primer) which loops back to the TOCTOU attack. If a character tries to use a weapon, then the server will first check if they are allowed to do this, very similar to the access() check in the initial example. These checks could be complex depending on the weapon and game, e.g., does the character have this specific weapon in their possession, does it have enough ammo, etc. In our example, we’re in medieval times so we’re talking swords, longbows and such. In this game, the check we know which happens when a character tries to fight (use a weapon) is that the server checks the location of the character. If they’re in a restricted area (castle, town, settlement) then they’re denied the ability to use weapons, people are safe. Outside these places, it’s a free for all. I got the pens out to illustrate. Figure 2: Map of TOCTOU land, don’t go into the deep dark forest, it’s really not safe It’s at this point that I bust out the Matrix quotes: “What you must learn is that these rules are no different than the rules of a computer system. Some of them can be bent. Others can be broken.” (Thanks Morpheus) At first glance it seems like we’re out of luck – it is black and white; we need to be outside these restricted places to use our weapons. And it is, however, until we start to look into the functionality of weapons a bit more. This is where the magic is, literally. Now being medieval times, we’ve got the ability to do magic (hence the ‘Harry Potter’ reference in the title – you were waiting for it). We can cast spells on people, turn them into frogs and such. In this game if we try and cast a spell to turn that other player (who is currently trolling us in the town pub) into a frog, then we are still denied, because we’re in the restricted/safe zone. This is, however, possible by putting our hacker hoody on, and we’ll get to it, but first I want to take you into the deep dark woods in the unsafe (unrestricted) zone to show you how to use the force, I mean magic. Figure 3: Magic time in the unrestricted zone The magic process consists of two stages, and first we’re going to need to find a big black bowl and collect some firewood (just kidding). So, in this game, first you cast a spell (let’s pick the frog one as an example) and then secondly, you indicate who the spell is to be performed against, by clicking on them. The developers assumed that these are two interconnected stages (to be performed one after the other), and they are, but they don’t have to be. You can see where I’m going with this hopefully? I found that it was possible to go outside a restricted zone and cast a spell, which the server allows because that is intended – you fight others in the unsafe (unrestricted) zones, etc. However, if you remember back, this is a two-stage process. I found that I could ‘cast’ (a spell) and leave it at that in the first stage, leaving the server hanging for me to click on a victim – but here’s the thing, I don’t click on anyone. It is at this point that I hop on my horse and travel back into the restricted zone (back to the pub, you guessed it), and then click on my victim who is to receive the spell to be turned into a frog. The server then turns the player into a frog. This happens because the check for whether we are in a restricted zone and denying weapons was only implemented against the first stage of the magic process – the casting. The process whereby we pick our victim to receive the spell has no checks against it. The developers never thought about the scenario whereby this two-stage process is separated, especially not over different geographical locations within the ‘world’. They assumed you’d want to cast a spell and pick a victim right away, which you would if you were engaged in a fight, in an unsafe zone – it makes sense. They hadn’t thought about other scenarios. In reference to the TOCTOU examples given at the start of this blog post, the thing (or ‘value’) I’m changing here is my location – moving from an unrestricted zone (unsafe) to a restricted zone (safe), between check and use, of the two-stage spell casting process. And that is why, my friends, somewhere in TOCTOU land, there is now a frog sitting on a stall at the bar in a pub, sipping a pint with some peanuts. *Ribbit* Figure 4: The safe zone is no longer safe - with TOCTOU we get to break/bend rules Now, the example I gave was one relating to gaming – because I’m all about the magic. If you look (and look well), you’ll likely see TOCTOU vulnerabilities in all sorts of (exploitable) applications, from native operating system applications to online shopping, online banking and everything in between. Now some have little impact, a mere inconvenience, such as being turned into a frog. Others, however, have greater impact – think of a TOCTOU vulnerability in an online banking web application. Imagine a transfer money function, stage one has a check which relates to checking the account balance (is there enough money in it?), and stage two, which carries out the actual transfer (transfer amount X to account Y, debit the account by X amount). Impact here going beyond a mere inconvenience, from the bank’s point of view that is. Using one-time coupon/discount codes simultaneously in an online shopping application is another example I’ll throw out there. TOCTOU race condition vulnerabilities are great fun from a penetration tester’s point of view. Finding one is pure satisfaction because you’ve understood the application on a higher level – at one with it. *Adopts Yoga pose* From a defensive standpoint, how do developers stop this from happening? Well, developers need to perform conditional checks and the subsequent operations as one 'atomic action.' An atomic what? An atomic action..."An atomic operation is one or a sequence of code instructions that are completed without interruption." (from Wikipedia on “Linearizability”) Make it hard for an attacker to interrupt between check and use and implement lots of error handling so if something isn’t quite right then the application exits out gracefully. Thanks for reading! Sursa: https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/abusing-time-of-check-time-of-use-toctou-race-condition-vulnerabilities-in-games-harry-potter-style/
-
Microsoft Warns of Widescale Credential Stealing Attacks by Russian Hackers Jun 26, 2023Ravie LakshmananCyber Threat / Password Security Microsoft has disclosed that it's detected a spike in credential-stealing attacks conducted by the Russian state-affiliated hacker group known as Midnight Blizzard. The intrusions, which make use of residential proxy services to obfuscate the source IP address of the attacks, target governments, IT service providers, NGOs, defense, and critical manufacturing sectors, the tech giant's threat intelligence team said. Midnight Blizzard, formerly known as Nobelium, is also tracked under the monikers APT29, Cozy Bear, Iron Hemlock, and The Dukes. The group, which drew worldwide attention for the SolarWinds supply chain compromise in December 2020, has continued to rely on unseen tooling in its targeted attacks aimed at foreign ministries and diplomatic entities. It's a sign of how determined they are to keep their operations up and running despite being exposed, which makes them a particularly formidable actor in the espionage area. "These credential attacks use a variety of password spray, brute-force, and token theft techniques," Microsoft said in a series of tweets, adding the actor "also conducted session replay attacks to gain initial access to cloud resources leveraging stolen sessions likely acquired via illicit sale." The tech giant further called out APT29 for its use of residential proxy services to route malicious traffic in an attempt to obfuscate connections made using compromised credentials. "The threat actor likely used these IP addresses for very short periods, which could make scoping and remediation challenging," the Windows maker said. The development comes as Recorded Future detailed a new spear-phishing campaign orchestrated by APT28 (aka BlueDelta, Forest Blizzard, FROZENLAKE, Iron Twilight, and Fancy Bear) targeting government and military entities in Ukraine since November 2021. The attacks leveraged emails bearing attachments exploiting multiple vulnerabilities in the open-source Roundcube webmail software (CVE-2020-12641, CVE-2020-35730, and CVE-2021-44026) to conduct reconnaissance and data gathering. A successful breach enabled the Russian military intelligence hackers to deploy rogue JavaScript malware that redirected the incoming emails of targeted individuals to an email address under the attackers' control as well as steal their contact lists. "The campaign displayed a high level of preparedness, quickly weaponizing news content into lures to exploit recipients," the cybersecurity company said. "The spear-phishing emails contained news themes related to Ukraine, with subject lines and content mirroring legitimate media sources." More importantly, the activity is said to dovetail with another set of attacks weaponizing a then-zero-day flaw in Microsoft Outlook (CVE-2023-23397) that Microsoft disclosed as employed by Russia-based threat actors in "limited targeted attacks" against European organizations. The privilege escalation vulnerability was addressed as part of Patch Tuesday updates rolled out in March 2023. The findings demonstrate Russian threat actors' persistent efforts in harvesting valuable intelligence on various entities in Ukraine and across Europe, especially following the full-scale invasion of the country in February 2022. The cyberwarfare operations aimed at Ukrainian targets have been notably marked by the widespread deployment of wiper malware designed to delete and destroy data, turning it into one of the earliest instances of large-scale hybrid conflict. "BlueDelta will almost certainly continue to prioritize targeting Ukrainian government and private sector organizations to support wider Russian military efforts," Recorded Future concluded. Found this article interesting? Follow us on Twitter and LinkedIn to read more exclusive content we post. Sursa: https://thehackernews.com/2023/06/microsoft-warns-of-widescale-credential.html
-
KeePass 2.X Master Password Dumper (CVE-2023-32784) Update The vulnerability was assigned CVE-2023-32784 and fixed in KeePass 2.54. Thanks again to Dominik Reichl for his fast response and creative fix! Clarification: the password has to be typed on a keyboard, not copied from a clipboard (see the How it works sections). What can you do First, update to KeePass 2.54 or higher. Second, if you've been using KeePass for a long time, your master password (and potentially other passwords) could be in your pagefile/swapfile, hibernation file and crash dump(s). Depending on your paranoia level, you can consider these steps to resolve the issue: Change your master password Delete crash dumps (depends on your OS, on Windows at least C:\Windows\memory.dmp, but maybe there are others) Delete hibernation file Delete pagefile/swapfile (can be quite annoying, don't forget to enable it back again) Overwrite deleted data on the HDD to prevent carving (e.g. Cipher with /w on Windows) Restart your computer Or just overwrite your HDD and do a fresh install of your OS. Incomplete list of products that are not impacted (please create a pull request or an issue for adding more). Rule of thumb is that if it isn't the original KeePass 2.X app written in .NET, it's likely not affected. KeePassXC Strongbox KeePass 1.X KeePass Master Password Dumper is a simple proof-of-concept tool used to dump the master password from KeePass's memory. Apart from the first password character, it is mostly able to recover the password in plaintext. No code execution on the target system is required, just a memory dump. It doesn't matter where the memory comes from - can be the process dump, swap file (pagefile.sys), hibernation file (hiberfil.sys), various crash dumps or RAM dump of the entire system. It doesn't matter whether or not the workspace is locked. It is also possible to dump the password from RAM after KeePass is no longer running, although the chance of that working goes down with the time it's been since then. Tested with KeePass 2.53.1 on Windows (English) and KeePass 2.47 on Debian (keepass2 package). It should work for the macOS version as well. Unfortunately, enabling the Enter master key on secure desktop option doesn't help in preventing the attack. PoC might have issues with databases created by older versions of KeePass, but I wasn't able to reproduce it (see issue #4). Finding was confirmed by Dominik Reichl, KeePass's author, here. I appreciate Dominik's fast response. Hopefully it will be fixed soon! Setup Install .NET (most major operating systems supported). Clone the repository: git clone https://github.com/vdohney/keepass-password-dumper or download it from GitHub Enter the project directory in your terminal (Powershell on Windows) cd keepass-password-dumper dotnet run PATH_TO_DUMP The easiest way to test this on Windows is to create a process dump in the task manager by right-clicking the KeePass process and selecting "Create dump file". Alternatively you can add another parameter dotnet run PATH_TO_DUMP PATH_TO_PWDLIST to generate a list of all possible passwords beginning from the second character. Should You Be Worried? Depends on your threat model. If your computer is already infected by malware that's running in the background with the privileges of your user, this finding doesn't make your situation much worse. However, it might be easier for the malware to be stealthy and evade the antivirus, since unlike KeeTheft or KeeFarce, no process injection or other type of code execution is necessary. If you have a reasonable suspicion that someone could obtain access to your computer and conduct forensic analysis, this could be bad. Worst case scenario is that the master password will be recovered, despite KeePass being locked or not running at all. If you use full disk encryption with a strong password and your system is clean, you should be fine. No one can steal your passwords remotely over the internet with this finding alone. How It Works KeePass 2.X uses a custom-developed text box for password entry, SecureTextBoxEx. This text box is not only used for the master password entry, but in other places in KeePass as well, like password edit boxes (so the attack can also be used to recover their contents). The flaw exploited here is that for every character typed, a leftover string is created in memory. Because of how .NET works, it is nearly impossible to get rid of it once it gets created. For example, when "Password" is typed, it will result in these leftover strings: •a, ••s, •••s, ••••w, •••••o, ••••••r, •••••••d. The POC application searches the dump for these patterns and offers a likely password character for each position in the password. Reliability of this attack can be influenced depending on how the password was typed and how many passwords were typed per session. However, I've discovered that even if there are multiple passwords per session or typos, the way .NET CLR allocates these strings means that they are likely to be nicely ordered in memory. So if three different passwords were typed, you are likely to get three candidates for each character position in that order, which makes it possible to recover all three passwords. Dev It's a quick POC, so likely not very reliable and robust. Please create a pull request if you happen to find an issue and fix it. Allowed password characters are currently hardcoded like this: ^[\x20-\x7E]+$ (all printable ASCII characters and space). Acknowledgements Thanks to adridlug for adding the possibility to auto-generate the password list, and ynuwenhof for refactoring the code. Related Projects Python implementation of the PoC by CMEPW Rust implementation of the PoC by ynuwenhof I haven't checked any of them yet. Sursa: https://github.com/vdohney/keepass-password-dumper
-
A new home CrackMapExec v6.0.0 is now available to everyone ! Hello everyone, today I'm releasing a new version of CrackMapExec, v6.0.0 into a public repository of CrackMapExec https://github.com/mpgn/CrackMapExec. While the sponsor version did receive a lot of updates, which I will describe in this post, the public version has not been updated after nearly one year. This new version is called Bane, all the features of the sponsors version are now accessible to everyone 🦇 But first and foremost, I would like to thank people that have helped me during this year with the development of CrackMapExec, their inputs, pull requests and ideas have been greatly appreciated: @zblurx, @MJHallenbeck and @al3x_n3ff 🏅 Also a big thanks to @skelsec and the impacket team 👏 In this new version, lot of new features have been added 💪 New core features: Dump dpapi Dump gMSA nt hash Dump gMSA using LDAP Extract gMSA secret Added bloodhound ingestor Switch to rich python Switch to SQLAlchemy Cmedb store a lot more information Improvement on the SSH protocol Improvement on the FTP protocol Added laps decryption Progress bar added 🎉 Modules chaining log option , to log a specific command into a file log option in the cme.conf file to log all commands into a file Overall speed improvement Improvement on the login feature (smart bruteforce, credid etc) Combine multiple options (--sam --lsa --dpapi etc) Sending you nmap (xml) scan is now fixed New modules: enum_av.py -> Enumerate AV installed on the target msol.py -> Dump MSOL password ntdsutil.py -> Dump NTDS using NTDSUtil printnightmare.py -> Check if target vulnerable to printnightmare rdcman.py -> Dump RDCMan credentials teams_localdb.py -> Dump Teams Cookie veeam_dump.py -> Dump VEEAM passwords winscp_dump.py -> Dump WinSCP passwords firefox.py -> Dump Firefox Passwords reg-query.py -> Performs a registry query on the machine ldap-checker -> Fully compatible with Kerberos Sursa: https://wiki.porchetta.industries/news/a-new-home
-
Why ORMs and Prepared Statements Can't (Always) Win Thomas Chauchefoin VULNERABILITY RESEARCHER June 27, 2023 8 MIN READ Security Key Information The Sonar Research team discovered several SQL injection vulnerabilities in Soko, a software deployed on the Gentoo Linux infrastructure. These SQL injections happened despite the use of an Object-Relational Mapping (ORM) library and prepared statements. We demonstrated that these code vulnerabilities lead to Remote Code Execution (RCE) on Soko because of a misconfiguration of the database. Thanks to the isolation of Soko software components from other services and how the Portage package manager works, users of Gentoo Linux were not at risk of supply-chain attacks. Introduction We were told to use ORMs and prepared statements to avoid SQL injections for a long time now. By doing so, we effectively separate instructions (the semantics of the SQL query) from the data. Modern languages and frameworks often also abstract away the need to write raw queries, offering high-level interfaces around our database models. Unfortunately, that's not enough to thwart away SQL injections once and for all, as these APIs can still present subtle bugs or nuances in their design. In this blog post, we show you how the misuse of a Golang ORM API introduced several SQL injections in Soko, a service deployed on the Gentoo Linux infrastructure. Then, we look further into assessing the impact of this vulnerability by using a PostgreSQL feature to execute arbitrary commands on the server. These vulnerabilities, tracked as CVE-2023-28424, were discovered and reproduced in a testing environment. They were later responsibly disclosed to Gentoo Linux maintainers, who deployed fixes within 24 hours. Because this service only displays information about existing Portage packages, it was not possible to perform a supply chain attack and users of Gentoo Linux were never at risk. While the server hosts several services, affected components are isolated in Docker containers, and the risk of lateral movement from attackers is limited. Nonetheless, there are some key learnings from these vulnerabilities that we would like to share in this blog post. If you run Soko on your infrastructure, you should upgrade it to Soko 1.0.3 or above. Technical Details What's Soko? Soko is the Go software behind https://packages.gentoo.org/, a public interface showing information about published Portage packages that you can install on Gentoo Linux. Portage is the go-to package management tool for this distribution and takes care of resolving and building all required dependencies. Soko offers a very convenient way to search through all of these packages and easily get information like the associated bug tracker or where the upstream source is. Again, packages are not downloaded from Soko but directly from upstream. The Search Feature Soko is built to let users search through packages–that's its sole job and means that the code of this feature is the most interesting to review with our security hat on. Indeed, it has to assemble a SQL query based on many parameters that may or may not be part of the request. ORMs have query builders that introduce a very welcome abstraction layer so developers don't have to hand-write SQL queries; Soko's use of go-pg makes it very expressive and easy to follow. For instance, if you want to select a record of a given database model whose title is prefixed with my using go-pg, this is what you would write (example taken from their documentation😞 err := db.Model(book). Where("id > ?", 100). Where("title LIKE ?", "my%"). Limit(1). Select() Notice the presence of query placeholders–the question marks–in the Where() clauses. They are replaced with the associated parameters at runtime after escaping them for the right context. Indeed, a string and a column name are specified differently in SQL, and the ORM must escape them accordingly. That also means that the first parameter should always be a constant string: otherwise, that means that we're probably circumventing the escaping feature and could introduce SQL injections. Finding (Un)prepared Statements Diving into the implementation of the search feature, we can notice code like this snippet: searchTerm := getParameterValue("q", r) searchTerm = strings.ReplaceAll(searchTerm, "*", "") searchQuery := BuildSearchQuery(searchTerm) var packages []models.Package err := database.DBCon.Model(&packages). Where(searchQuery). Relation("Versions"). OrderExpr("name <-> '" + searchTerm + "'"). Select() pkg/app/handler/packages/search.go A first thing that should jump to your eyes is the parameter searchTerm, coming from the user's request, being concatenated to the first parameter of the OrderExpr() call. It goes in contradiction with how one should safely use this API. There's probably room for a SQL injection in here! Let's look at the implementation of the method BuildSearchQuery(), also using searchTerm as a parameter and passed as the first argument of Where(): func BuildSearchQuery(searchString string) string { var searchClauses []string for _, searchTerm := range strings.Split(searchString, " ") { if searchTerm != "" { searchClauses = append(searchClauses, "( (category % '"+searchTerm+"') OR (name % '"+searchTerm+"') OR (atom % '"+searchTerm+"') OR (maintainers @> '[{\"Name\": \""+searchTerm+"\"}]' OR maintainers @> '[{\"Email\": \""+searchTerm+"\"}]'))") } } return strings.Join(searchClauses, " AND ") } pkg/app/handler/packages/search.go We can see that searchTerm is again directly interpolated in the query. When passed as a parameter to Where(), it won't be able to escape its value; it's already in the query. As a result, this function has several SQL injections: one for every use of searchTerm! And its GraphQL Sibling? Users can also do searches through the GraphQL API to ease integration with external systems and scripts. While most of the code around database models is often automatically generated, features like this require custom code–they are called resolvers. GraphQL frameworks have this notion of resolvers that can back types fields: they come in handy when fetching data from a third-party API or running a complex database query. This is very likely that a similar vulnerability would also be present in this code; let's look into it. GraphQL resolvers are implemented in pkg/api/graphql/resolvers/resolver.go. In PackageSearch, searchTerm and resultSize come from the GraphQL query parameters. The parameter searchTerm is also unsafely interpolated in an OrderExpr() clause, introducing another SQL injection: func (r *queryResolver) PackageSearch(ctx context.Context, searchTerm *string, resultSize *int) ([]*models.Package, error) { // [...] if strings.Contains(*searchTerm, "*") { // if the query contains wildcards wildcardSearchTerm := strings.ReplaceAll(*searchTerm, "*", "%") err = database.DBCon.Model(&gpackages). WhereOr("atom LIKE ? ", wildcardSearchTerm). WhereOr("name LIKE ? ", wildcardSearchTerm). Relation("PkgCheckResults").[...].Relation("Outdated"). OrderExpr("name <-> '" + *searchTerm + "'"). Limit(limit). Select() } pkg/api/graphql/resolvers/resolver.go A similar SQL injection is present in the same method when performing a fuzzy search–we omitted it above for brevity. Check your GraphQL resolvers! An Effective SQL Injection With these potential injections in mind, we can check whether they are exploitable. To first give you some context, the following query is executed when searching for the package foo: SELECT "package"."atom", "package"."category", "package"."name", "package"."longdescription", "package"."maintainers", "package"."upstream", "package"."preceding_commits" FROM "packages" AS "package" WHERE (( (category % 'foo') OR (NAME % 'foo') OR (atom % 'foo') ( maintainers @ '[{"Name": "foo"}]' OR maintainers @ '[{"Email": "foo"}]' ) )) OR (atom LIKE '%foo%') ORDER BY NAME < - > 'foo' Once a single quote is used in the search, the semantics of the query change which leads to syntax errors. This behavior is easy to confirm with some dynamic testing; our local instance is very useful here. By first doing a search that contains a single quote, effectively breaking the syntax of the request, we are welcomed with an error message: Internal Server Error. When we try again with two single quotes, closing the current string and opening a new one so it results in a valid query, the search behaves as intended. Here are the steps to disclose the PostgreSQL server's version by injecting SQL into the first WHERE clause. Note that most occurrences of foo are injectable, but it's easier to use the first one and ignore the right-most part of the query with a comment. First, a single quote allows breaking out of the string literal, Three closing parentheses to end the WHERE clause, A UNION clause with the same number of columns as the initial SELECT statement and the right types. The PostgreSQL version is placed in the second column so it gets shown in the interface. A comment (--) to ignore everything else after. The payload has to respect several constraints: The character * cannot be used, or the vulnerable code path is not executed. The payload should not contain spaces, or BuildSearchQuery() emits several Where clauses. Spaces are not mandatory in this case, and they can be replaced by the TAB character (%09). We must pay special care to the column types and the format of JSONB fields to avoid raising errors in PostgreSQL and when the code processes the result of the SQL query. We obtain something like foo'))) union all select '1',version()::text,'3','4','[]','{}',7--. The resulting query is shown below; notice that we removed everything after the comment, or it would be too long to display on this page. SELECT "package"."atom", "package"."category", "package"."name", "package"."longdescription", "package"."maintainers", "package"."upstream", "package"."preceding_commits" FROM "packages" AS "package" WHERE (( (category % 'foo') )) UNION ALL SELECT '1', version()::text, '3', '4', '[]', '{}', 7 -- And indeed, when used in the search field, the version of the PostgreSQL server is shown, that's a success! PostgreSQL Stacked Queries PostgreSQL supports stacked queries allowing developers to submit several SQL statements by separating them with semicolons. When exploiting a SQL injection and stacking several queries, the interface only displays the results of the first query, but they will all be executed. Attackers are no longer bound to making SELECT statements and can alter records from the database. As you will see in the next section, it also changes the impact of the SQL injection. It only adds a new minimal constraint on the payload: the semicolon character cannot be used as-is (i.e., not URL-encoded) to avoid running into a quirk of the net/url package. PostgreSQL's COPY FROM PROGRAM PostgreSQL also supports an operation named COPY FROM PROGRAM. This documented feature enables the execution of arbitrary commands on the system, usually with the privileges of the user postgres. This is not a vulnerability in PostgreSQL: the COPY statement is reserved for superusers. Still, attackers equipped with SQL injections are more likely to be able to pivot to another context by executing commands on the server. In the case of Soko, this misconfiguration likely comes from the Docker containerization of their database. Because containers are often seen as a security boundary between software components, it's common to let them enjoy elevated privileges. In the official PostgreSQL image, the user set by POSTGRES_USER benefits from superuser privileges: db: image: postgres:12 restart: always environment: POSTGRES_USER: ${SOKO_POSTGRES_USER:-root} POSTGRES_PASSWORD: ${SOKO_POSTGRES_PASSWORD:-root POSTGRES_DB: ${SOKO_POSTGRES_DB:-soko} shm_size: 512mb volumes: - ${POSTGRES_DATA_PATH:-/var/lib/postgresql/data}:/var/lib/postgresql/data docker-compose.yml This is a bad security practice and goes against the principle of least privilege; most users of this Docker image are likely impacted by this misconfiguration. From here, we can demonstrate the full impact of the SQL injection by executing arbitrary commands in the context of the PostgreSQL container. For instance, running id returns the current user's identity. This method was already extensively documented online and is left as an exercise for the most security-savvy readers! Patch After responsibly disclosing both findings to the maintainers, Arthur Zamarin promptly addressed them by refactoring query builder calls to follow the documentation. Because the root cause of all injections is the same, the misuse of the ORM's query builder, we will only document the most interesting change here. You can find the full patches on GitHub: 428b119 and 4fa6e4b. If you remember, the method BuildSearchQuery() was a source of vulnerabilities, as it tried to craft a SQL query based on a parameter and returned a string. Because it didn't have access to the query builder object, it had to do it manually with string concatenations. This situation is solved by passing the pg.Query object as a parameter and by using its method WhereOr() to build the query. Notice that its first parameter is always a constant string with a query placeholder, so searchTerm gets correctly escaped every time: -func BuildSearchQuery(searchString string) string { - var searchClauses []string +func BuildSearchQuery(query *pg.Query, searchString string) *pg.Query { for _, searchTerm := range strings.Split(searchString, " ") { if searchTerm != "" { - searchClauses = append(searchClauses, - "( (category % '"+searchTerm+"') OR (name % '"+searchTerm+"') OR (atom % '"+searchTerm+"') OR (maintainers @> '[{\"Name\": \""+searchTerm+"\"}]' OR maintainers @> '[{\"Email\": \""+searchTerm+"\"}]'))") + marshal, err := json.Marshal(searchTerm) + if err == nil { + continue + } + query = query.WhereGroup(func(q *pg.Query) (*pg.Query, error) { + return q.WhereOr("category % ?", searchTerm). + WhereOr("name % ?", searchTerm). + WhereOr("atom % ?", searchTerm). + WhereOr("maintainers @> ?", `[{"Name": "`+string(marshal)+`"}]`). + WhereOr("maintainers @> ?", `[{"Email": "`+string(marshal)+`"}]`), nil + }) } } - return strings.Join(searchClauses, " AND ") + return query } Timeline DATE ACTION 2023-03-17 We report all issues to the Soko maintainer and security contacts at Gentoo. A patch is submitted on the same day. 2023-03-19 The GitHub Security Advisories are published (GHSA-45jr-w89p-c843, GHSA-gc2x-86p3-mxg2) along with CVE-2023-28424. Summary In this publication, we presented a case of how SQL injection can arise despite using a query builder and prepared statements. Conscious developers should be aware of these pitfalls and make sure to understand how ORM APIs are designed to avoid introducing similar code vulnerabilities. In general, a common source of vulnerabilities with ORMs happens when there is no reference to the query builder instance in the current context; such cases are usually methods made to avoid code duplication across queries. Developers are then more likely to craft parts of the query manually and introduce SQL injections. Additionally, every ORM comes with its own take on API design, and it can be tricky to know about unsafe code patterns at first sight. This is where Go's typing could come in handy at the cost of some flexibility by introducing compile-time safeguards, forcing developers to always separate instructions (the prepared statement) from data (the user's input). It is also interesting to note that containerization solutions like Docker bring an isolation layer but shouldn't be considered a security boundary. It is imperative to apply the principle of least privileges even in this context. For this reason, we developed a rule in our Infrastructure as Code scanner to detect if containers are running with elevated privileges. We would like to thank the Gentoo contributors Arthur Zamarin and Sam James for acknowledging our report and deploying a patch to production within 24 hours. Kudos! Sursa: https://www.sonarsource.com/blog/why-orms-and-prepared-statements-cant-always-win/