bin初解禁
解题
看到session的名字确定是go的web框架写的,整个题目的输入点就只有兑换辣条之王,number = -1提示非法,number = 18446744073709551615提示数量不够,number = 18446744073709551616提示非法,可以确定number是uint64类型。
5个辣条 = 1个辣条之王,猜测后端代码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| package main
import "fmt"
func main() {
var number uint64
var havelt uint64
var haveltzw uint64
havelt = 4
number = 3689348814741910324
if number * 5 <= havelt {
fmt.Println(number * 5)
fmt.Println(haveltzw + number)
}
}
|
这样就造成了溢出,导致用4个辣条就能换3689348814741910324个辣条之王
思考
go不是内存安全吗,怎么会存在溢出呢?
用下面的代码,在编译阶段就检测到溢出,编译不通过
1
2
3
4
5
6
7
8
9
10
11
| package main
import "fmt"
func main() {
var number uint64
number = 3689348814741910324 * 5
fmt.Println(number)
}
|
猜测是go只在编译的时候做了检查,运行的时候没有检查是否溢出
gdb调一发
测试程序
1
2
3
4
5
6
7
8
9
10
11
12
13
| package main
import (
"fmt"
)
func main() {
var num uint64
var over uint64
num = 3689348814741910324
over = num * 5
fmt.Println(over)
}
|
go build -gcflags "-N -l" main.go
关闭优化
进gdb打断点,再打印汇编
num * 5 直接优化成了0x4后就传入num了(我不是关了优化吗…
再来看看隔壁的Rust
1
2
3
4
5
6
7
| fn main() {
let mut num: u64 = 0;
let mut over: u64 = 0;
num = 3689348814741910324;
over = num * 5;
println!("{}", over);
}
|
编译通过,但是运行的时候就panic了
gdb一发
rustc -g main.rs
关闭优化
将3689348814741910324送入rdx,再将rdx送入0x28(num),然后0x28的值送入rax,做mul乘法运算(rcx = 5),seto溢出置位,如果无溢出sil = 0x0,反之为0x1,test运算相当于按位与,如果不为0就跳到0x55555555cf24进入panic流程
这个过程rax已经是溢出了,只不过下面做了溢出检查
可以看出rust在运行的时候也有检查是否溢出
最后
第一次接触bin的领域,上述若有错误,大佬们随意指出,一定学习改正
参考
https://www.cnblogs.com/lsgxeva/p/8948153.html
https://xz.aliyun.com/t/2893#toc-15