Share
## https://sploitus.com/exploit?id=9D903AC3-081F-5485-A855-58D63FAF01A2
# CVE-2022-1015
## Route Cause

`nft_parse_register` ํ•จ์ˆ˜์—์„œ arg๊ฐ€ default๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ์— ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ํ•˜์ง€ ์•Š์•„ `nft_do_chain` ํ•จ์ˆ˜์˜ stack์—์„œ oob๊ฐ€ ํ„ฐ์ง. 

์ด๋•Œ payload expression์„ ์ด์šฉํ•˜๋ฉด read, write๋ฅผ ๋‘˜ ๋‹ค ํ•  ์ˆ˜ ์žˆ๋‹ค.

payload๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋™์ž‘์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

![image](https://github.com/more-kohii/CVE-2022-1015/assets/87258637/8e739fe5-f667-4e23-bd4a-4066e149f9e6)

์ฆ‰, ์ธ๋ฑ์Šค๋ฅผ ์ ์ ˆํžˆ ์กฐ์ ˆํ•˜๋ฉด stack์—์„œ oob read, write๋ฅผ ํ•  ์ˆ˜ ์žˆ์Œ.

ํ•˜์ง€๋งŒ, regs๋Š” validation์„ ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•œ๋‹ค.

```c
default:
		if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
			return -EINVAL;
		if (len == 0)
			return -EINVAL;
		if (reg * NFT_REG32_SIZE + len >
		    sizeof_field(struct nft_regs, data))
			return -ERANGE;

		if (data != NULL && type != NFT_DATA_VALUE)
			return -EINVAL;
		return 0;
```

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, reg * NFT_REG32_SIZE + len > sizeof_field(struct nft_regs, data) ๋ฅผ ๋งŒ์กฑํ•ด์•ผํ•œ๋‹ค.

์ƒ์ˆ˜ ๋„ฃ์–ด์ฃผ๋ฉด reg * 4 + len > 80 ์ด๊ฑฐ ๋งŒ์กฑํ•˜๋ฉด ๋œ๋‹ค.

์ฆ‰, reg์— ๋งž๊ฒŒ ์ ๋‹นํžˆ len๋ฅผ ์กฐ์ ˆํ•ด์ค˜์•ผํ•œ๋‹ค.

## ์ฐธ๊ณ ํ•  ์†Œ์Šค ์ฝ”๋“œ

- `nft_regs`
    
    ```c
    struct nft_regs {
    	union {
    		u32			data[20];
    		struct nft_verdict	verdict;
    	};
    };
    ```
    
- `nft_do_chain`
    
    ```c
    unsigned int
    nft_do_chain(struct nft_pktinfo *pkt, void *priv)
    {
    	const struct nft_chain *chain = priv, *basechain = chain;
    	const struct net *net = nft_net(pkt);
    	struct nft_rule *const *rules;
    	const struct nft_rule *rule;
    	const struct nft_expr *expr, *last;
    	struct nft_regs regs;
    	...
    }
    ```
    
- `nft_parse_register`
    
    ```c
    static unsigned int nft_parse_register(const struct nlattr *attr)
    {
    	unsigned int reg;
    
    	reg = ntohl(nla_get_be32(attr));
    	switch (reg) {
    	case NFT_REG_VERDICT...NFT_REG_4:
    		return reg * NFT_REG_SIZE / NFT_REG32_SIZE;
    	default:
    		return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
    	}
    }
    ```