Information Security
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Help
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
{%hackmd yf0ZwG0ERVmC3ZRUSC6CBw %} [TOC] # NTU Computer Security Fall 2019 ## Binary Exploitatiion ### Binary exploitation - What is PWN - 透過利用程式(Binary)的漏洞(Vulnerability),在執行期間控制執行流程(Control flow),進而使程式執行特定行為 ### Basic concepts - ELF(Executable and Linkable Format) - 執行檔 - Example - exe - Section - 執行時會mapping到RAM上(Virtual memory) - .text, .bss, .data, .rodata, .got, .plt, .fini, etc. - Workflow(Static) - ![image](https://hackmd.io/_uploads/HkFID_Jja.png) - Workflow(dynamic linking) - ![image](https://hackmd.io/_uploads/Hy-_POJip.png) - Section - .bss - 存放未初始化值的全域變數(global variable) - .data - 存放具初始化值的全域變數 - .rodata - 存放唯讀(read-only)資料 - .text - 存放編譯後的code - ![image](https://hackmd.io/_uploads/BkSgdOyo6.png) - Protections - PIE - Position-Independent Executable - NX - No-eXecute - Canary - Stack protector - RELRO - Relocation Read-Only - x64 - 8 bytes alignment - Stack 0x10 bytes alignment - Assembly - Registers - rax, rbx, rcx, rdx, rdi, rsi - 64 bits - eax, ebx, ecx, edx, edi, esi - 32 bits - ax, bx, cx, dx, di, si - 16 bits - ax -> ah, al - 8 bits - RSP - Stack pointer register - 指向stack頂端(頭) - RBP - Base pointer register - 指向stack底端(尾) - RIP - Program counter register - 指向當前執行指令instruction位置 - jmp - 跳至程式某一地址address執行 - call - 將call完後回來緊接著要執行的下一行指令位置push到stack上儲存起來,再跳過去執行 - leave - 還原至caller的stack frame - mov rsp, rbp - pop rbp - ret(return) - Calling convention - Pass parameters - rdi, rsi, rdx, rcx, r8, r9, (stack) - rdi, rsi, rdx, r10, r8, r9, (stack) - rax: store return value - x64: register傳參數 - x86: stack傳參數 - Stack frame - Function prologue - Function epilogue - Stack frame - local variables - \[rbp\] = old rbp(caller rbp) - \[rbp + 0x8\] = return address ### Overflow - Buffer overflow - Stack overflow - Heap overflow - 覆蓋到理論上不應該被修改到的資料 - Important data, Secret - Return address ### BOF - Buffer Overflow - Local variables - Data on stack - gets(buf) - 不會檢查輸入長度 - 可以覆蓋stack上的資料 - 改變return address、control flow等 ### Canary - Function prologue時在stack上放置程式執行時隨機生成的8 bytes在saved rbp前 - 第一個byte為null byte - Function epilogue時會拿儲存在另一segment的值檢查canary值是否相同來檢測是否發生overflow - 若相同才正常return - 否則直接終止程式(abort) - 每次執行canary不同,同一次的canary固定 ### Shellcode - Write assembly code and use assembler to turn to machine code #### Linux Syscall - System call - 跟kernel做溝通的interface - instruction - syscall - rax - syscall number - Arguments - rdi, rsi, rdx, r10, r8, r9 - Return value - rax Shellcode: execve - execve - int execve(const char \*pathname, char \*const argv\[\], char \*const envp\[\]) - Spawn a shell - execve("/bin/sh", NULL, NULL) - ![image](https://hackmd.io/_uploads/BywBPBZsT.png) ### NX - No-execute - Data segment不應具有執行權限 - stack, heap - rw- - Code segment具執行權限,但不具寫入權限 - r-x - ![image](https://hackmd.io/_uploads/Byam_SWsT.png) - seccomp ### ASLR - Address Space Layout Randomizaion - Kernel的保護機制 - 每次動態載入時,base都是隨機的 - library - stack - heap ### PIE - Position-Independent Executable - 可以看成是ELF code & data section map到virtual address時的ASLR - PIE開啟時,每次執行程式code base都會不同,否則固定0x400000 - 紀錄在ELF file中 ### Lazy Binding - Dynamic linking的程式,有些使用到的library function可能因執行流程到結束都不會被執行到 - Lazy binding機制為當程式第一次呼叫library function時,才會去尋找libc function的位置(function address)進行binding,並填入GOT表中,後續呼叫此function則直接從GOT表中獲取位置 #### GOT - Global Offset Table - Library的位置在載入時才決定,compiler在編譯時期亦無法得知執行時期的library function address - GOT為儲存library function位置的指標陣列,而lazy binding的機制,一開始不會得知真實位置,而是先填入位於plt的code ### GOT Hijacking - 因為Lazy binding的機制,GOT為可寫區域 - 假設程式有漏洞可以造成對GOT做寫入覆蓋其值,下一次呼叫對應的library function時則可以從中劫持,任意控制將要執行的function pointer ### ROP(Return Oriented Programming Attack) #### ROP gadgets - 片段可執行的code - 結尾是ret instruction - call, jmp等任何可以繼續控制流程的方式 - How to find the gadgets - https://github.com/JonathanSalwan/ROPgadget - https://github.com/sashs/Ropper - 手動找 ROP: - NX: 見招拆招 - 在既有的執行區域(code segment)尋找gadgets,運用這些gadgets疊成一長串的return address chain(ROP chain) - 透過許多片段執行行為的gadget,來串出任意代碼執行,藉此繞過NX保護機制的限制 - Function return時,會拿走第一個return address,此時rsp指在第二個return address,並跳至第一個return address執行,接著會執行到ret instruction - 而第二個return address也在開始時放置好,做到繼續control flow,如此反覆來達到Return Oriented Porgramming形式的攻擊 #### Control Register - Gadget - pop (reg); - ret - 因為byte的數量,因此找到的機會比較搭 ROP: - 常常不會那麼剛好有想要的gadget且是ret結尾 - 想辦法組合gadget,達成同樣的目的 - 存在overflow,或任何成功control rip的前提下 - NX關的情況,可以撰寫執行`execve("/bin/sh", 0, 0)`的shellcode並嘗試控制rip跳至shellcode - NX開的情況,可以透過ROP的方式,堆疊出執行`execve("/bin/sh", 0, 0)`行為的ROP chain ### ret2plt(return to .plt) - 如果想要串的行為本身就有function在binary中,可以直接用ROP放好參數使用它 - 不用用ROP去堆全部的行為 - 在PIE關的情況下,即使不知道library function address(因ASLR),也可以透過return到.plt上使用此function ### ret2libc(return to libc) - 若能得知library被map到的隨機起始地址(base address),則可以計算出libc中function的位置,便能調用library中的函式 - 關鍵為bypass ASLR,找出libc的隨機base - 透過information leak漏洞,洩漏memory上的內容,獲取屬於libc segment的address - 此address會是隨機的base address加上一固定位移值offset - 不同版本的libc offset不同 - leaked_address - offset = base_address - 有base後繼可以透過加上offset的方式得知其他function的address來call它,結合ROP等等 #### Information leak - Compiler開空間時,Stack上面的值不會清乾淨 - 可以leak出來 - 透過剛好input到沒乾淨的值的前面,可以將殘留的值leak出來 - libc的memory ### Stack pivoting(Stack migration) - ROP需要很多空間放置長串的ROP chain,有時並不會有那麼多空間,可能很短甚至只能控第一次rip - 若找到其他地方有足夠空間放置ROP payload,此時可以透過運用較少的gadget數,將stack搬移到ROP payload的位置,再進行ROP - 很多做法 - leave; ret - Overflow時將rbp填成ROP Chain的address - 8 - Return address填leave; ret gadget - pop rsp; ret - 手動找針對各種當下情況的gadget ### ret2csu(return to _\_libc\_csu_init) - 位於`__libc_csu_init`函式中,為compiler編進去的function - 尾部有一片段code,很適合拿來控制register放置參數,以及control flow - ![image](https://hackmd.io/_uploads/ByDkcYMi6.png) - 透過控制rbp, rbx, r12, r13, r14, r15 registers的值,跳至Gadget開頭,r13, r14, r15分別放置前三個參數rdi, rsi, rdx - 此部分解決很少找到pop rdx gadget的問題 - ROP很難控制第三個參數 - 控制r12, rbx來指定任意記憶體位置call \[r12+rbx\*8\] - 將rbx設為0,將rbp設為1,在call完後使rbx == rbp == 1,jne不會take,而繼續執行後面的連續pop register,如此可重複使用,達到任意ROP ## Heap Exploitation ### Heap intro - 在打heap時,需要先知道library的版本 - `ldd --version` - ptmalloc2 - glibc - tcmalloc: google - jemalloc - etc. - malloc - 要用多少分配多少 - 提升記憶體分配效率及避免記憶體空間的浪費 - `void *ptr = malloc(size)` - Workflow - ![image](https://hackmd.io/_uploads/H1Op-Thj6.png) - main arena - 一開始malloc < 128 KB,透過brk,kernel會給132KB的heap segment(rw) - main arena - 對kernel來說已經被使用,對binary來說還沒拿到 - 會交給glibc管理 - ![image](https://hackmd.io/_uploads/BJFV7T2jp.png) - ASLR: heap base - Chunk - glibc實作記憶體管理機制的資料結構(data structure) - malloc拿到的一塊記憶體 - Allocated chunk - Free chunk - Top chunk - Size alignment - 0x10的倍數,malloc 0x18會拿到0x20的大小 - 整個chunk占記憶體大小為header(0x10) + data - ![image](https://hackmd.io/_uploads/r1rCmahs6.png) #### Chunk header - Allocated chunk - prev_size - 連續記憶體上一塊若是free chunk,則記錄該size - 若是allocated chunk則同時為它的data - size - Chunk size with 3 flags - PREV_INUSE(P) - 上一個chunk是否使用中 - IS_MMAPED(M) - Chunk是否透過mmap出來的 - NON_MAIN_ARENA(N) - 該chunk是否不屬於main arena - ![image](https://hackmd.io/_uploads/Byg2SzJTi6.png) - Pointer會指在user data - Free chunk - prev_size - 連續記憶體上一塊若是free chunk,則記錄該size - 若是allocated chunk則為它的data - size - 連續記憶體下一塊的P flag為0 - fd - 指向同一bin中的前一塊chunk(linked list) - bk - 指向同一bin中的後一塊chunk(linked list) - ![image](https://hackmd.io/_uploads/r1h-7yasa.png) - Top chunk - 第一次malloc後,剩下的空間為top chunk,分配空間時視情況從top chunk切割分配 - free Top chunk連續記憶體上一塊chunk時,若不是fastbin則會與Top chunk merge,top chunk P恆為1 - ![image](https://hackmd.io/_uploads/S19X7y6op.png) ### bins - 回收free chunk的資料結構 - 主要依據size大小分為 - fast bin - small bin - large bin - unsorted bin - Fast bin - Size < 0x90 bytes - bin中依據size劃分為0x20, 0x30, 0x40, ... - global_max_fast = 0x80 - Singly linked list - fd指向前一個,bk沒用到 - LIFO(Last in, First out) - Free時不會將下一塊chunk P flag設成0 - Small bin - Circular doubly linked list - 依據size劃分為62個bin - 0x20, 0x30, ..., 0x3f0 - 0x20 ~ 0x80的大小與fast bin重疊,會根據機置放到fast bin或small bin - FIFO(First in, First out) - Free掉時會將下一塊chunk P設為0 - Large bin - Circular doubly linked list - 依據大小遞減排序 - size >= 1024 bytes(0x400) - 63 bins - 細節可以參考source code - header - fd_nextsize - bk_nextsize - ![image](https://hackmd.io/_uploads/BJkxSk6s6.png) - Unsorted bin - Circular doubly linked list - free的chunk size大於fast bin時,不會直接放到對應的bin哩,會先丟到unsorted bin中 - malloc fast bin size大小時會先去fast bin list裡找,若沒有則會至unsorted bin找 - 如找到一樣大小則回傳 - 若無但找到大小大於所需大小的chunk則切割回傳 - 剩下的部分會丟回unsorted bin - 若都沒有則從top chunk切出來回傳 ### Vulnerability #### Heap overflow - 在heap segment發生的overflow - 和stack overflow類似 - Stack overflow目標是掌控stack上可利用資訊 - return address等 - Heap overflow是掌握heap中的利用目標 - 某個chunk分配來是一個object struct,透過heap overflow overwrite進行偽造 - 控制chunk header,並結合glibc malloc free的記憶體管理機制,做到進一步利用 #### UAF(Use after free) - free(ptr) - free完pointer後未將ptr清空(ptr=NULL),稱為dangling pointer - 有一個pointer指著一塊已經被釋放的記憶體 - 根據不同的存取方式,有各種利用方法,可以進一步去做後續exploit的利用 - 用來information leak,存取殘留的data - Struct Type Confusion - Double free就是因為存在dangling pointer所以造成free一塊已經釋放的chunk,一樣可以透過一些技巧達到進一步的利用 - Information leak - free兩個同size的fastbin,fd指向heap,如果存在UAF,將此chunk user data印出來或任何方法得知其值,透過印出fd來leak出heap address - malloc一塊非fast bin size的chunk,free掉它使它被放入unsorted bin中,或任何製造出unsorted bin的方法,unsorted bin的fd與bk會是一個libc address - 直接UAF印出fd來leak出libc address,或是malloc拿回這塊chunk,印出殘留的fd等 ### Heap exploitation #### Fastbin attack - fastbin在檢查double free時,只檢查現在linked list第一個chunk是否等於現在即將要free掉的chunk - 若存在double free,則可以透過`free(A) free(B) free(A)`的方式繞過此檢查 - 下次再malloc此fastbin size時,會拿到chunk A,而同時chunk A依舊存在於free chunk linked list中,藉此寫入data時修改掉fd,接下來連續malloc兩次後,第三次則會回傳拿到我們偽造的address - Constraints - malloc時會檢查chunk size正不正確 - 在目標地址+0x8的地方偽造size - 尋找附近存在正確size之目標位置 - 增加可行性的利用技巧 - address alignment weakness - libc address hardcode - 檢查size時是抓取4 bytes int #### Hooks - glibc中存在許多function hooks,在攻擊時如果能達到arbitrary write或任意寫,hooks會是一個很好的寫入目標,來做到control flow - `__malloc_hook` - `__free_hook` - `__realloc_hook` - etc. - 在執行該function時,發現該function hoook有值,則當作function pointer跳上去執行 - 結合fastbin attack拿到位於hooks附近位置的fake chunk,來overwrite hooks的值 #### One gadget - 跳過去即執行`execve("/bin/sh", argv[], envp[])`(開shell) - magic gadget - 有一些前提(constraints)要滿足 - 常搭配hooks使用 - https://github.com/david942j/one_gadget - 補充 - 如果malloc一塊unsorted bin大小的空間,free之後假如那空間的後面連著top chunk,會被merge #### Tcache(per-thread cache) - glibc >= 2.26 - Ubuntu 17.10後 - 新的機制,提升performance - 第一次malloc後,會先分配一塊記憶體,存放`tcache_perthread_struct` - 一個thread一個`tcache_perthread_struct` - ![image](https://hackmd.io/_uploads/HJCIo576T.png) - 根據size分為不同大小的tcache - smallbin大小範圍的chunk都會使用tcache - 以fastbin來說,free時不會直接放到fastbin裡,而是放到對應的size的Tcache中,當滿7個時,再free才會放至fastbin中 - fastbin的fd是指向整個chunk的頭(Header),而tcache fd則是指向user data - malloc時優先從tcache取出,tcache為空才會從原本的bin中開始找 - 若tcache為空,而原本的bin中有剛好大小的chunk時,會從bin中填補至tcache中直到填滿,再從tcache中取出 - tcache中的順序會與bin中相反 - 對於fastbin來說,會先將bin中第一塊取出,才將後面做填補 - 提升效能,而降低了安全性 - 沒有檢查double free - malloc時沒有檢查size是否合法 - 不需要偽造chunk、偽造size,就能拿到任意記憶體的位置 - 有許多進階玩法與技巧 - 透過漏洞掌握整個`tcache_perthread_struct`等 ### Some Heap Technique #### Heap Overlap - 可能一開始漏洞無法直接性做到太多事情 - 透過各式偽造chunk size的方式,以及玩弄malloc free的流程,使得不同的chunk發生重疊(heap overlap)的情形 - 假設chunk A的data與chunk B的不可寫部分重疊 - chunk B可能是一個struct,亦或是function pointer,則可以透過chunk A來偽造,overwrite data pointer達到任意讀寫,overwrite function pointer則可以hijack control flow - 可以更進一步偽造chunk header,偽造heap chunk,玩弄記憶體管理機制 - off-by-one null byte overflow - [The poisoned NULL byte - Google Project Zero](https://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html) - 某種程度上算很容易發生的漏洞 - 如宣告size剛剛好的字元陣列,一些libc function操作會自動append null byte或自行邊界操作不當等 #### Unsafe Unlink - doubly linked list - unlink - unlink(p) - p->fd = bk - p->bk = fd - 古典作法 - 在有漏洞的前提下,偽造p的fd, bk,透過unlink,可以對memory做寫入 - ![image](https://hackmd.io/_uploads/HyhWPsQTa.png) - 後來增加檢查,驗證doubly linked list的完整性 - 指過去要能指回來 - P->bk->fd = P - P->fd->bk = P - 後來的利用條件 - 已知address底下存放著p指標(已知&p) - p為data pointer可以多次寫入,或其他同效果方法 - ![image](https://hackmd.io/_uploads/Bkwuvs7pa.png) - 之後再對data pointer p做寫入,便可以覆蓋掉p,overwrite為任意地址 - 再次寫入即會對目標地址寫入,達到write everywhere的效果 #### Unsorted bin attack - 在有漏洞的前提下 - 將unsorted bin的bk填成address - 0x10,再malloc相同大小的size,address的地方會被填上libc的address,指向main_arena中 - 無法直接性做到太多事情,可以用來間接進一步利用 - 將一個地方填上很大的數字 - information leak - 進階heap exploit技巧搭配 - etc. ### Something good - [how2heap](https://github.com/shellphish/how2heap) - [Angelboy](https://www.slideshare.net/AngelBoy1)

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully