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